import * as p from "@clack/prompts";
import path from "node:path";
import {
  ADAPTERS,
  detectTargets,
  getAdapter,
  planInstall,
  tildify,
  type Scope,
  type TargetId,
} from "@designpaca/core";
import { getSkill } from "../skill.ts";
import { runInstall, printNextSteps, printOutcomes } from "../commands/install.ts";
import { accent, bold, dim } from "../ui.ts";

/** 선택한 범위를 어댑터가 지원하지 않으면 지원 가능한 범위로 낮춘다 */
function effectiveScope(target: TargetId, wanted: Scope): Scope {
  const a = getAdapter(target);
  return a.scopes.includes(wanted) ? wanted : (a.scopes[0] as Scope);
}

export async function onboard(): Promise<number> {
  const skill = await getSkill();

  console.clear();
  p.intro(`${accent("◆ designpaca")} ${dim(`v${skill.version}`)}`);

  p.note(
    [
      "브리프에서 시작해 레퍼런스 조사 · 방향 결정 · 디자인 토큰 ·",
      "구현 · 셀프 감사까지 끌고 가는 웹 디자인 파이프라인 스킬.",
      "",
      `${dim("SVG 필터 · three.js · 인터랙티브 모션을 기본 재료로 쓴다.")}`,
    ].join("\n"),
    "무엇을 설치하나",
  );

  // 시스템에 흔적이 있는 도구를 기본 체크해 둔다 — 사용자가 매번 고르게 하지 않는다
  const detected = await detectTargets(skill);

  const targets = await p.multiselect<TargetId>({
    message: "어디에 설치할까?",
    options: ADAPTERS.map((a) => ({
      value: a.id,
      label: a.label + (detected.includes(a.id) ? dim("  (감지됨)") : ""),
      hint: a.hint,
    })),
    initialValues: detected.length > 0 ? detected : ["claude-code"],
    required: true,
  });
  if (p.isCancel(targets)) return cancel();

  const wanted = await p.select<Scope>({
    message: "설치 범위",
    options: [
      { value: "user", label: "전역", hint: "홈 디렉터리 — 모든 프로젝트에서 쓴다" },
      { value: "project", label: "이 프로젝트만", hint: tildify(process.cwd()) },
    ],
    initialValue: "user",
  });
  if (p.isCancel(wanted)) return cancel();

  // 범위가 낮춰진 타깃이 있으면 미리 알린다 — 설치 후에 "왜 여기 깔렸지"가 되지 않게
  const downgraded = targets.filter((t) => effectiveScope(t, wanted) !== wanted);
  if (downgraded.length > 0) {
    p.log.warn(
      downgraded
        .map((t) => {
          const a = getAdapter(t);
          return `${a.label} 은(는) ${a.scopes.join("/")} 범위만 지원한다 → ${effectiveScope(t, wanted)} 로 설치한다`;
        })
        .join("\n"),
    );
  }

  // 무엇이 어디에 쓰이는지 먼저 보여준다
  const previews: string[] = [];
  for (const t of targets) {
    const scope = effectiveScope(t, wanted);
    const plan = await planInstall(t, scope, skill);
    if (plan.blocked) {
      previews.push(`${bold(getAdapter(t).label)}\n  ${dim(plan.blocked)}`);
      continue;
    }
    const dirs = new Set(plan.actions.map((a) => path.dirname(a.path)));
    previews.push(
      [
        `${bold(getAdapter(t).label)} ${plan.alreadyInstalled ? dim("(재설치)") : ""}`,
        `  ${dim(tildify(plan.root))}`,
        `  ${dim(`파일 ${plan.actions.length}개 · 디렉터리 ${dirs.size}개`)}`,
      ].join("\n"),
    );
  }
  p.note(previews.join("\n\n"), "설치 계획");

  const go = await p.confirm({ message: "이대로 설치할까?", initialValue: true });
  if (p.isCancel(go) || !go) return cancel();

  const s = p.spinner();
  s.start("설치 중");
  const outcomes = [];
  try {
    for (const t of targets) {
      const scope = effectiveScope(t, wanted);
      s.message(`설치 중 — ${getAdapter(t).label}`);
      outcomes.push(...(await runInstall({ targets: [t], scope })));
    }
    s.stop("설치 완료");
  } catch (err) {
    s.stop("설치 실패", 1);
    p.log.error(err instanceof Error ? err.message : String(err));
    return 1;
  }

  printOutcomes(outcomes);
  printNextSteps(targets);

  p.outro(`${accent("designpaca")} 준비됨 — 이제 브리프를 던져라`);
  return 0;
}

function cancel(): number {
  p.cancel("설치를 취소했다. 아무것도 바꾸지 않았다.");
  return 130;
}
