/**
 * GET /api/setup/status — what does the wizard need to ask about?
 * GET /api/setup/list-dirs — directory browser used by the folder picker
 *
 * Detects whether Claude Code is installed, whether the user is
 * actually logged in (real macOS keychain check), whether
 * ANTHROPIC_API_KEY is available, and surfaces a candidate workspace
 * root (iCloud claude-output if it exists).
 *
 * The wizard pre-fills its answers when detection succeeds, so most
 * users click through in seconds.
 */
import type { Hono } from "hono";
import { existsSync, readdirSync, statSync } from "node:fs";
import { isAbsolute, join, resolve } from "node:path";
import { homedir } from "node:os";
import { spawnSync } from "node:child_process";
import { ICLOUD_ROOT } from "./paths";
import { loadSettings } from "./settings";

function isClaudeInstalled(): boolean {
  // Check common static paths first for speed (important for AppleScript app wrappers
  // where the PATH is minimal and misses brew/npm global directories).
  const commonPaths = [
    join(homedir(), ".npm-global", "bin", "claude"),
    join(homedir(), ".local", "bin", "claude"),
    "/usr/local/bin/claude",
    "/opt/homebrew/bin/claude",
  ];
  for (const p of commonPaths) {
    if (existsSync(p)) return true;
  }

  // Fallback: spawn a login shell to inherit the user's real PATH (reads .zshrc etc)
  try {
    const shell = process.env.SHELL || "/bin/zsh";
    const r = spawnSync(shell, ["-l", "-c", "command -v claude"], { encoding: "utf8" });
    if (r.status === 0 && r.stdout.trim()) return true;
  } catch { /* ignore */ }

  return false;
}

function isClaudeLoggedIn(): boolean {
  if (!isClaudeInstalled()) return false;
  // Authoritative check: query the macOS login keychain for the OAuth
  // credential the Claude CLI writes when `claude login` succeeds. This
  // catches the "used CLI before but logged out / token expired" case
  // that the older file-existence heuristic missed.
  try {
    const r = spawnSync(
      "security",
      ["find-generic-password", "-s", "Claude Code-credentials"],
      { encoding: "utf8" }
    );
    return r.status === 0;
  } catch {
    // `security` not on PATH (extremely unlikely on macOS) — fall back
    // to the heuristic so we don't false-negative every user.
    const dir = join(homedir(), ".claude");
    return existsSync(dir) && (existsSync(join(dir, "projects")) || existsSync(join(dir, "history.jsonl")));
  }
}

function iCloudWorkspaceCandidate(): string | null {
  try {
    if (existsSync(ICLOUD_ROOT) && statSync(ICLOUD_ROOT).isDirectory()) {
      return ICLOUD_ROOT;
    }
  } catch { /* fall through */ }
  return null;
}

export function registerSetupRoutes(app: Hono) {
  app.get("/api/setup/status", (c) => {
    const s = loadSettings();
    return c.json({
      setupComplete: s.setupComplete,
      claudeInstalled: isClaudeInstalled(),
      claudeLoggedIn: isClaudeLoggedIn(),
      hasApiKey: !!process.env.ANTHROPIC_API_KEY || !!s.apiKey,
      currentAuthMode: s.authMode,
      workspaceRoot: s.workspaceRoot,
      workspaceRootCandidate: iCloudWorkspaceCandidate(),
      workspaceExists: existsSync(s.workspaceRoot),
      defaultWorkspaceRoot: iCloudWorkspaceCandidate() || join(homedir(), "Documents", "head-of-product"),
    });
  });

  // GET /api/setup/list-dirs?path=<absolute>&showHidden=true
  //
  // Lists immediate subdirectories of `path` for the in-app folder
  // picker. Defaults to $HOME. Returns the resolved absolute path so
  // the client can show breadcrumbs without re-computing.
  //
  // Containment: only paths inside the user's home, the root chain,
  // or /Volumes are allowed. Anything else falls back to $HOME so a
  // typo can't ls /etc or /private.
  app.get("/api/setup/list-dirs", (c) => {
    const showHidden = c.req.query("showHidden") === "true";
    const requested = c.req.query("path") || homedir();
    let abs = isAbsolute(requested) ? resolve(requested) : resolve(homedir(), requested);

    const home = homedir();
    const allowed = abs === "/" || abs.startsWith(home) || abs.startsWith("/Volumes") || abs === "/Users";
    if (!allowed) abs = home;

    const entries: { name: string; path: string }[] = [];
    let err: string | null = null;
    try {
      for (const name of readdirSync(abs)) {
        if (!showHidden && name.startsWith(".")) continue;
        try {
          const full = join(abs, name);
          if (statSync(full).isDirectory()) entries.push({ name, path: full });
        } catch { /* skip unreadable entries */ }
      }
      entries.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
    } catch (e: any) {
      err = e?.message || String(e);
    }

    // Quick-pick suggestions for common workspace candidates.
    const suggestions: { label: string; path: string }[] = [];
    if (existsSync(ICLOUD_ROOT)) suggestions.push({ label: "iCloud claude-output", path: ICLOUD_ROOT });
    const docs = join(home, "Documents");
    if (existsSync(docs)) suggestions.push({ label: "Documents", path: docs });
    const desktop = join(home, "Desktop");
    if (existsSync(desktop)) suggestions.push({ label: "Desktop", path: desktop });
    const code = join(home, "personal", "codebase");
    if (existsSync(code)) suggestions.push({ label: "personal/codebase", path: code });

    return c.json({
      path: abs,
      parent: abs === "/" ? null : resolve(abs, ".."),
      home,
      entries,
      suggestions,
      error: err,
    });
  });

  app.get("/api/user", (c) => {
    try {
      const shell = process.env.SHELL || "/bin/zsh";
      const r = spawnSync(shell, ["-l", "-c", "claude auth status --json"], { encoding: "utf8" });
      if (r.status === 0 && r.stdout) {
        // CLI might output escape codes; extract JSON cleanly
        const match = r.stdout.match(/\{[\s\S]*\}/);
        if (match) {
          return c.json(JSON.parse(match[0]));
        }
      }
    } catch { /* ignore */ }
    return c.json(null);
  });
}
