import { ADAPTERS, type Scope, type TargetId } from "@designpaca/core";
import { getVersion } from "./skill.ts";
import { checkForUpdate } from "./update-check.ts";
import { printNextSteps, printOutcomes, runInstall } from "./commands/install.ts";
import { runDoctor } from "./commands/doctor.ts";
import { runTools } from "./commands/tools.ts";
import { runUpdate } from "./commands/update.ts";
import { runUninstall } from "./commands/uninstall.ts";
import { runList } from "./commands/list.ts";
import { onboard } from "./tui/onboard.ts";
import { accent, bad, bold, dim, warn } from "./ui.ts";

const VALID_TARGETS = ADAPTERS.map((a) => a.id) as string[];

interface Args {
  command: string;
  targets: TargetId[];
  scope: Scope;
  yes: boolean;
  force: boolean;
  dryRun: boolean;
  help: boolean;
  version: boolean;
}

function parse(argv: string[]): Args {
  const out: Args = {
    command: "",
    targets: [],
    scope: "user",
    yes: false,
    force: false,
    dryRun: false,
    help: false,
    version: false,
  };

  for (let i = 0; i < argv.length; i++) {
    const a = argv[i] as string;
    if (a === "--help" || a === "-h") out.help = true;
    else if (a === "--version" || a === "-v") out.version = true;
    else if (a === "--yes" || a === "-y") out.yes = true;
    else if (a === "--force" || a === "-f") out.force = true;
    else if (a === "--dry-run") out.dryRun = true;
    else if (a === "--no-update-check") process.env["DESIGNPACA_NO_UPDATE_CHECK"] = "1";
    else if (a === "--target" || a === "-t") {
      const v = argv[++i];
      if (v) out.targets.push(...(v.split(",") as TargetId[]));
    } else if (a.startsWith("--target=")) {
      out.targets.push(...(a.slice(9).split(",") as TargetId[]));
    } else if (a === "--scope" || a === "-s") {
      const v = argv[++i];
      if (v) out.scope = v as Scope;
    } else if (a.startsWith("--scope=")) {
      out.scope = a.slice(8) as Scope;
    } else if (!a.startsWith("-") && !out.command) {
      out.command = a;
    }
  }
  return out;
}

function usage(version: string): string {
  return `
${accent("designpaca")} ${dim(`v${version}`)} — 웹 디자인 파이프라인 스킬 설치기

${bold("사용법")}
  npx designpaca                     대화형 온보딩 (권장)
  npx designpaca install             설치
  npx designpaca update              최신 스킬로 갱신
  npx designpaca uninstall           제거
  npx designpaca doctor              설치 상태 진단
  npx designpaca list                설치 가능 대상과 현재 설치 목록
  npx designpaca tools               브라우저 도구 상태 확인 ${dim("(--yes 로 설치)")}

${bold("옵션")}
  -t, --target <id[,id]>   설치 대상: ${VALID_TARGETS.join(", ")}
  -s, --scope <범위>       user | project            ${dim("(기본: user)")}
  -y, --yes                확인 없이 진행합니다
  -f, --force              직접 수정한 파일도 덮어씁니다 ${dim("(.orig 로 백업)")}
      --dry-run            쓰지 않고 계획만 보여줍니다
      --no-update-check    새 버전 확인을 건너뜁니다
  -h, --help               이 도움말
  -v, --version            버전

${bold("예시")}
  ${dim("npx designpaca install -t claude-code,codex -s user -y")}
  ${dim("npx designpaca install -t cursor -s project")}
  ${dim("npx designpaca update --force")}
  ${dim("npx designpaca tools --yes")}
`.trimStart();
}

async function main(): Promise<number> {
  const args = parse(process.argv.slice(2));
  const version = await getVersion();

  if (args.version) {
    console.log(version);
    return 0;
  }
  if (args.help) {
    console.log(usage(version));
    return 0;
  }

  const bad_ = args.targets.filter((t) => !VALID_TARGETS.includes(t));
  if (bad_.length > 0) {
    console.error(bad(`알 수 없는 대상: ${bad_.join(", ")}`));
    console.error(dim(`  가능한 값: ${VALID_TARGETS.join(", ")}`));
    return 2;
  }
  if (args.scope !== "user" && args.scope !== "project") {
    console.error(bad(`알 수 없는 범위: ${args.scope} (user | project)`));
    return 2;
  }

  // 대화형으로 쓸 수 있는 환경이면 인자 없이 실행했을 때 온보딩으로 보낸다
  const interactive = process.stdout.isTTY && !args.yes;
  if (!args.command || args.command === "onboard") {
    if (interactive) return onboard();
    console.log(usage(version));
    return 0;
  }

  let code = 0;
  switch (args.command) {
    case "install": {
      const targets = args.targets.length > 0 ? args.targets : (["claude-code"] as TargetId[]);
      if (interactive && args.targets.length === 0) return onboard();
      const outcomes = await runInstall({
        targets,
        scope: args.scope,
        force: args.force,
        dryRun: args.dryRun,
      });
      printOutcomes(outcomes, args.dryRun);
      if (!args.dryRun) printNextSteps(targets);
      code = outcomes.some((o) => o.blocked) ? 1 : 0;
      break;
    }
    case "update":
      code = await runUpdate({ force: args.force });
      break;
    case "uninstall":
    case "remove":
      code = await runUninstall({ targets: args.targets, force: args.force });
      break;
    case "doctor":
      code = await runDoctor();
      break;
    case "tools":
      // 수백 MB 를 받는 일이라 --yes 없이는 상태만 보여준다
      code = await runTools({ install: args.yes });
      break;
    case "list":
    case "ls":
      code = await runList();
      break;
    default:
      console.error(bad(`알 수 없는 명령입니다: ${args.command}`));
      console.log(usage(version));
      return 2;
  }

  // 명령을 마친 뒤에만 알린다 — 시작을 지연시키지 않는다
  const latest = await checkForUpdate(version);
  if (latest) {
    console.log(
      "\n" + warn(`새 버전 v${latest} 이 나왔습니다 — ${dim("npx designpaca@latest update")}`),
    );
  }
  return code;
}

main()
  .then((code) => {
    process.exitCode = code;
  })
  .catch((err: unknown) => {
    console.error(bad(err instanceof Error ? err.message : String(err)));
    if (process.env["DESIGNPACA_DEBUG"] === "1" && err instanceof Error) console.error(err.stack);
    process.exitCode = 1;
  });
