/**
 * acr init — 互動式初始化設定
 * 詢問 CF Account ID、KV namespace、API Token、email，
 * 呼叫 arcrun.dev 取得 API Key，寫入 ~/.arcrun/config.yaml
 */
import { createInterface } from 'node:readline/promises';
import { writeFileSync, existsSync, readFileSync, appendFileSync } from 'node:fs';
import { join } from 'node:path';
import chalk from 'chalk';
import { saveConfig, type ArcrunConfig } from '../lib/config.js';
import { CfAccountClient } from '../lib/cf-api.js';
import {
  downloadAndDeploy,
  type DeployContext,
} from '../lib/deploy.js';
import { cmdInstallHarness } from './install-harness.js';
import { cmdMcpSetup } from './mcp-setup.js';
import { detectEnvironment, printPreflight, verifyInstall } from '../lib/preflight.js';

const ARCRUN_LOGIN_URL = 'https://arcrun.dev/login';

async function prompt(rl: ReturnType<typeof createInterface>, question: string): Promise<string> {
  const answer = await rl.question(chalk.cyan(`? ${question}: `));
  return answer.trim();
}

export interface InitOptions {
  local?: boolean;
  selfHosted?: boolean;
  accountId?: string;
  apiToken?: string;
}

export async function cmdInit(options: InitOptions): Promise<void> {
  const rl = createInterface({ input: process.stdin, output: process.stdout });

  console.log(chalk.bold('\n  arcrun 初始化設定\n'));

  try {
    if (options.local) {
      await initLocal();
    } else if (options.selfHosted) {
      await initSelfHosted(rl, options);
    } else {
      await initStandard(rl);
    }
  } finally {
    rl.close();
  }

  // init 末尾順便裝 CC harness 進當前專案（SDD user-cc-harness §2：init 裝 + 可單獨裝）。
  // 失敗不影響 init 本身（harness 是加分，可事後 acr install-harness 補）。
  try {
    await cmdInstallHarness();
  } catch (e) {
    console.log(chalk.gray(`  （harness 安裝略過：${e instanceof Error ? e.message : e}；可稍後跑 acr install-harness）`));
  }

  // 順便寫專案 .mcp.json，讓 Claude Code 連對的 MCP（依 config 的 mcp_url，SDD mcp-account-source.md）。
  // 失敗不影響 init（可事後 acr mcp-setup 補）。
  try {
    cmdMcpSetup();
  } catch (e) {
    console.log(chalk.gray(`  （.mcp.json 略過：${e instanceof Error ? e.message : e}；可稍後跑 acr mcp-setup）`));
  }

  // 冷啟動環境檢查（harness：機制強制，不靠提醒）。
  // 失敗會 exit 2，用戶必須修復後重跑 acr init。
  console.log('');
  try {
    const { execSync } = await import('child_process');
    const hookPath = new URL('../../../.claude/hooks/pre-cold-startup-check.sh', import.meta.url);
    execSync(`bash "${hookPath.pathname}"`, { stdio: 'inherit' });
  } catch (e) {
    if ((e as any)?.status === 2) {
      // exit 2 = 環境檢查失敗，停下，不繼續
      process.exit(2);
    }
    // 其他錯誤（hook 不存在等）只警告，不擋 init
    console.log(chalk.gray(`  （環境檢查略過，可手動跑 bash .claude/hooks/pre-cold-startup-check.sh）`));
  }
}

async function initLocal(): Promise<void> {
  console.log(chalk.gray('  Local 模式：不需要 Cloudflare 帳號，workflow 由 arcrun.dev 雲端引擎執行\n'));

  const config: ArcrunConfig = {
    mode: 'local',
  };

  saveConfig(config);
  createHelloYamlIfMissing();

  console.log(chalk.green('\n  ✓ 設定完成 → ~/.arcrun/config.yaml（local 模式）'));
  console.log(chalk.green('  ✓ 建立 hello.yaml 範例 workflow\n'));
  console.log('  你可以立刻開始：');
  console.log(chalk.cyan('    acr validate hello.yaml --offline') + '        # 驗證 workflow 格式');
  console.log(chalk.cyan('    acr run hello --input input="Hello, arcrun!"') + '  # 執行，輸出大寫字串\n');
  console.log(chalk.gray('  Local 模式：YAML 留在本機，workflow 由 arcrun.dev 引擎執行。'));
  console.log(chalk.gray('  需要用自己的 CF 帳號存放 credentials？執行 acr init（Standard 模式）。\n'));
}

async function initStandard(rl: ReturnType<typeof createInterface>): Promise<void> {
  console.log(chalk.gray('  Standard 模式：用 arcrun.dev 帳號登入取得 API Key\n'));

  // API Key 發放走網站 OAuth 登入（/auth/google/start、/auth/github/start）。
  // CLI 是薄殼，不自己發 key（rule 07），只引導用戶去拿再貼回來。
  console.log('  1. 開啟 ' + chalk.cyan(ARCRUN_LOGIN_URL) + ' 用 Google / GitHub 登入');
  console.log('  2. 在 Dashboard 複製你的 API Key（ak_ 開頭）\n');

  const apiKey = (await prompt(rl, 'API Key（ak_...）')).trim();

  if (!apiKey.startsWith('ak_')) {
    console.log(chalk.yellow('\n  ✗ API Key 應以 ak_ 開頭，請重新執行 acr init\n'));
    process.exit(1);
  }

  const config: ArcrunConfig = {
    mode: 'standard',
    api_key: apiKey,
  };

  saveConfig(config);
  createCredentialsYamlIfMissing();

  console.log(chalk.green('\n  ✓ 設定完成 → ~/.arcrun/config.yaml'));
  console.log(chalk.green(`  ✓ API Key：${apiKey.slice(0, 8)}...`));
  console.log(chalk.green('  ✓ 建立 credentials.yaml（已加入 .gitignore）\n'));
  console.log('  下一步：');
  console.log(chalk.cyan('    acr parts scaffold <component>') + '   # 查看零件 config 範本');
  console.log(chalk.cyan('    acr creds push credentials.yaml') + '  # 上傳加密 credentials');
  console.log(chalk.cyan('    acr push workflow.yaml') + '            # 部署 workflow 並取得 Webhook URL\n');
}

/**
 * Self-hosted installer：用戶只提供 CF Account ID + API Token，其餘自動。
 *   驗 token → 查 subdomain → 下載部署物 → 解析資源（沿用既有／必要才新建）→ 部署 Worker
 *   → seed auth+api recipe → 寫 config → 印手動 secret 提示。
 * SDD：.agents/specs/arcrun/sdk-and-website/self-hosted-init.md
 */
async function initSelfHosted(
  rl: ReturnType<typeof createInterface>,
  options: InitOptions,
): Promise<void> {
  console.log(chalk.gray('  Self-hosted 模式：自動部署整套 arcrun 到你的 Cloudflare 帳號\n'));
  console.log(chalk.gray('  你只需提供 CF Account ID + API Token，其餘 CLI 自動完成。\n'));

  // §7.8 P0：偵測先於動作（pip 式）——先看環境有什麼，缺前置就停下給補救指令，
  // 不假設齊備直接動手（test_arcrun/4：D1 缺了 AI 跑去讀原始碼自己想辦法的災難）。
  const pre = detectEnvironment();
  printPreflight('環境偵測（安裝前）', pre.items);
  if (pre.fatal) {
    console.log(chalk.yellow('\n  ✗ 缺少必要前置（見上方 →）。補齊後重新執行 acr init --self-hosted。'));
    console.log(chalk.gray('    init 冪等：補好重跑，已就緒的會自動跳過。\n'));
    process.exit(1);
  }

  // account-id / api-token 取得順序：flag > env（CLOUDFLARE_*）> 互動問答。
  // 解壓測 #7：AI/CI 可非互動完成。帳號設定值非風險確認（mindset §7），flag/env 合法。
  // SDD: sdk-and-website/config-layering.md §2.3
  const accountId =
    options.accountId ?? process.env.CLOUDFLARE_ACCOUNT_ID ?? (await prompt(rl, '你的 Cloudflare Account ID'));
  const cfApiToken =
    options.apiToken ?? process.env.CLOUDFLARE_API_TOKEN
    ?? (await prompt(rl, 'CF API Token（需 Workers Scripts Edit + Workers KV Storage Edit）'));

  if (!accountId || !cfApiToken) {
    console.log(chalk.yellow('\n  ✗ 缺少 Account ID 或 API Token。'));
    console.log(chalk.yellow('    非互動用法：acr init --self-hosted --account-id <id> --api-token <token>'));
    console.log(chalk.yellow('    或設環境變數 CLOUDFLARE_ACCOUNT_ID / CLOUDFLARE_API_TOKEN\n'));
    process.exit(1);
  }

  const cf = new CfAccountClient(accountId, cfApiToken);

  // 1. 驗 token / account 可達
  process.stdout.write(chalk.gray('\n  → 驗證 Cloudflare 憑證...'));
  try {
    await cf.verifyAccess();
    console.log(chalk.green(' ✓'));
  } catch (e) {
    console.log(chalk.yellow(` ✗ ${e instanceof Error ? e.message : e}`));
    console.log(chalk.yellow('    請確認 Account ID 與 API Token（含權限）正確後重試\n'));
    process.exit(1);
  }

  // 2. KV / D1 / Vectorize 不在這裡預先建（Arcrun#97）。
  //    舊版在這一步「照名字 ensure」一輪再往下傳，acr update 沿用同一段程式碼
  //    ⇒ 對一台安裝器裝出來的實例（資源名字不同）等於每次更新都重建一整套空的綁上去。
  //    現在資源解析統一在 downloadAndDeploy 內：**先看已部署的 worker 綁著什麼**，
  //    對得上就沿用、確定沒人綁過才建、說不準就停手。init 走 mode:'init'（允許從零建起）。
  //    不建 R2：R2 是 dead storage（registry-canon Phase 1.5），且 CF R2 首次啟用強制綁信用卡，
  //    違背 arcrun「開源免費自架，Workers + KV 免費額度即可運行」核心理念（壓測 2026-06-04 #3）。

  // 3. 查 workers.dev subdomain（cypher-executor WORKER_SUBDOMAIN 用）
  let workerSubdomain = '';
  try {
    workerSubdomain = await cf.getWorkersSubdomain();
    console.log(chalk.gray(`  → workers.dev subdomain: ${workerSubdomain}`));
  } catch (e) {
    console.log(chalk.yellow(`  ⚠ 查 subdomain 失敗（${e instanceof Error ? e.message : e}），稍後可手動補`));
  }

  // 3.5 語義查詢（issue #7 / T2.4）：**預設開**（2026-08-09 翻轉，leo：「語義搜尋已經
  //     確定是一安裝就提供的功能」——預設關會產出一批「看起來裝好了、其實少一條腿」的
  //     實例，之後畫面上還被誤說成「沒開通」）。顯式回答 n 才關（極端省額度者自選）。
  //     開 → deploy 建 CF Vectorize index + 注入 binding。關 → base 維持 LIKE keyword。
  const embedAns = (await prompt(
    rl,
    '要開語義查詢嗎？(內建功能，建議保持開啟；用 CF Vectorize，有免費額度) [Y/n]',
  )).trim().toLowerCase();
  const kbdbEmbed = !(embedAns === 'n' || embedAns === 'no');
  if (!kbdbEmbed) console.log(chalk.yellow('  → 已選關語義查詢：這台實例將只有關鍵字搜尋（之後可設 kbdb_embed:true + acr update 補開）。'));

  // 4. 下載 repo 部署物（含預編譯 wasm）+ 注入 KV id + wrangler deploy 全部 Worker
  console.log(chalk.gray('\n  → 下載部署物 + 部署 Worker（從 GitHub 拉預編譯 wasm，用你的 CF token 部署）...'));
  // selfHosted: true → deploy 注入 MULTI_TENANT="false"（mcp-account-source §5.5，修 MCP 401）。
  // init.ts 這條本就是 --self-hosted 分支（config.mode 稍後寫 'self-hosted'）。
  const deployCtx: DeployContext = { accountId, apiToken: cfApiToken, workerSubdomain, selfHosted: true, kbdbEmbed };
  const deploy = await downloadAndDeploy(deployCtx, 'main', { mode: 'init', api: cf });

  // 資源解析喊停（例：這台其實已經裝過、但某顆綁著的資源不見了）→ 什麼都沒建、什麼都沒部。
  if (deploy.blocked) {
    console.log(chalk.yellow('\n  ⚠ 安裝沒有進行，你的 Cloudflare 帳號維持原樣。\n'));
    console.log('  ' + deploy.message.split('\n').join('\n  '));
    console.log('');
    process.exit(1);
  }

  // 實際用上的資源（沿用既有的，或這次新建的）——寫 config / 驗收都以這份為準，不再自己查名字。
  const kvNamespaceIds = deployCtx.kvNamespaceIds ?? {};
  const d1DatabaseId = deployCtx.d1DatabaseId ?? '';
  const cypherUrl = deploy.cypherExecutorUrl
    ?? (workerSubdomain ? `https://arcrun-cypher-executor.${workerSubdomain}.workers.dev` : '');
  // self-hosted 自己的 MCP worker URL（mcp-account-source §3：.mcp.json 指自己，不 fallback 官方）。
  const mcpUrl = deploy.mcpUrl
    ?? (workerSubdomain ? `https://arcrun-mcp.${workerSubdomain}.workers.dev/mcp` : '');
  // 誠實回報部署結果；但**不**用「全部成功」字串 gate 後續 seed（壓測 §4.1：
  // registry 一個無關 worker 失敗就連坐讓 seed 永遠被跳過）。seed 只看 cypher-executor 是否可達。
  const deployFullyOk = /全部成功/.test(deploy.message);
  console.log(deployFullyOk ? chalk.green(`  ✓ ${deploy.message}`) : chalk.yellow(`  ⚠ ${deploy.message}`));

  // 5. 寫 config（資源資訊存好，供後續 acr push / update / seed）
  const config: ArcrunConfig = {
    mode: 'self-hosted',
    cloudflare_account_id: accountId,
    cf_api_token: cfApiToken,
    cypher_executor_url: cypherUrl,
    mcp_url: mcpUrl || undefined,   // 指自己的 MCP（mcp-account-source §3），無 subdomain 才留空 fallback 官方
    webhooks_kv_namespace_id: kvNamespaceIds['WEBHOOKS'],
    credentials_kv_namespace_id: kvNamespaceIds['CREDENTIALS_KV'],
    multi_tenant: false,
    kbdb_embed: kbdbEmbed,   // 語義查詢開關（issue #7）；存進 config 讓後續 acr update 維持一致
  };
  saveConfig(config);
  createCredentialsYamlIfMissing();

  // 6.5 config 寫好後重寫 .mcp.json，讓它指向「自己的」MCP（init 開頭的 cmdMcpSetup 在 config 前跑，
  //     那時 mcp_url 還沒設 → 會 fallback 官方；這裡 config 已含自己的 mcp_url，重跑一次蓋成自己的）。
  try {
    cmdMcpSetup();
  } catch (e) {
    console.log(chalk.gray(`  （.mcp.json 重寫略過：${e instanceof Error ? e.message : e}）`));
  }

  // 6. seed recipe（薄殼：呼叫 API 的 /init/seed 一次，由 API 灌 API recipe + auth recipe）。
  //    只要 cypher-executor 可達就 seed——不被無關 worker（registry）的失敗連坐（壓測 §4.1）。
  if (cypherUrl) {
    await callSeedEndpoint(cypherUrl);
  }

  // §7.8 P0 裝完驗收：實查 CF（KV/D1）+ 打 cypher /health 確認真就緒，缺哪項明確報哪項
  // + 給一鍵補裝指令（不靜默印灰字）。假綠零容忍（mindset §7）：看實際狀態，非看 config 寫了沒。
  const verify = await verifyInstall({
    cf,
    kvNamespaceIds,
    d1DatabaseId: d1DatabaseId || undefined,
    cypherUrl,
  });
  printPreflight('安裝驗收（裝完檢查）', verify.items);
  if (!verify.allOk) {
    console.log(chalk.yellow('\n  ⚠ 部分項目未就緒（見上方 →）。多數可跑 acr update 冪等補裝。'));
    console.log(chalk.gray('    （worker 剛部署可能需數十秒生效，可稍候再跑 acr update 重驗。）'));
  }

  // 結果回報（誠實：部分失敗時明說，不假綠 — mindset §7）
  console.log(chalk.green(`\n  ✓ Cloudflare 資源就緒（${Object.keys(kvNamespaceIds).length} KV，免費額度即可，無需綁卡）`));
  console.log(chalk.green('  ✓ 設定寫入 ~/.arcrun/config.yaml'));
  console.log(chalk.green('  ✓ 建立 credentials.yaml'));

  // 下一步：身份設定（self-hosted 單租戶——namespace 明碼用戶自填）。
  // 工具不生成、不 hash、不外傳任何 key（守 rule 05 精神：secret 不進自動化，由用戶持有）。
  console.log(chalk.bold('\n  下一步 ①：在這個專案建 .env（你自己填，工具不碰）：'));
  console.log(chalk.cyan('    NAMESPACE=leo                 # 你的資料分區標籤（明碼即可，不是密碼）'));
  console.log(chalk.gray('    （NAMESPACE 是分區標籤非密碼；要防外部呼叫請對 webhook 加保護。'));
  console.log(chalk.gray('     .env 已被 gitignore。）'));
  console.log(chalk.gray('    credential 不需要自管加密金鑰：明文由 CF Workers Secrets 託管。\n'));

  // credential-store-migration T3（§2.3）：cypher worker 要有一把「能打 CF Workers Scripts
  // secrets 管理 API 的 token」才能讓 POST/PUT /credentials 把密文寫進 Workers Secrets。
  // 印手動指令而非工具自動 put——CF_ACCOUNT_ID 非機密，已由 downloadAndDeploy/
  // injectWranglerConfig 自動注入（同 WORKER_SUBDOMAIN 模式），
  // 只有 CF_SECRETS_API_TOKEN（機密）需要用戶手動 put。
  console.log(chalk.bold('  下一步 ②：把能打 Workers Scripts secrets API 的 CF token 設進 cypher worker：'));
  console.log(chalk.cyan(`    wrangler secret put CF_SECRETS_API_TOKEN --name arcrun-cypher-executor`));
  console.log(chalk.gray('  貼你剛才用來部署的同一個 CF API Token（需含 Workers Scripts:Edit 權限）。'));
  console.log(chalk.gray('  用途：POST/PUT /credentials 把密文寫進 Workers per-script Secrets（credential-store-migration T5）。'));
  console.log(chalk.gray('  CF_ACCOUNT_ID 已自動注入（非機密），不需手動設定。\n'));
}

/**
 * 薄殼：呼叫 API 的 /init/seed 一次（rule 07）。
 * seed 的編排 + 種子資料全在 cypher-executor（routes/init-seed.ts），CLI 不自己迴圈 POST。
 * 之前 seedApiRecipes 在 CLI 迴圈 POST + deployFullyOk gate 是壓測 §4.1 的反例，已移除。
 */
async function callSeedEndpoint(cypherUrl: string): Promise<void> {
  process.stdout.write(chalk.gray('  → seed recipe（API recipe + auth recipe，由 API 灌入）...'));
  try {
    const res = await fetch(`${cypherUrl}/init/seed`, { method: 'POST' });
    const body = await res.json().catch(() => null) as
      | { success?: boolean; message?: string }
      | null;
    if (res.ok && body?.success) {
      console.log(chalk.green(` ✓ ${body.message ?? ''}`));
    } else {
      // 誠實：不假綠。seed 沒全成就明說，提示 acr update 可重跑（冪等）。
      console.log(chalk.yellow(` ⚠ ${body?.message ?? `HTTP ${res.status}`}（可 acr update 重跑，seed 冪等）`));
    }
  } catch (e) {
    console.log(chalk.yellow(` ⚠ seed 端點呼叫失敗（${e instanceof Error ? e.message : e}）；cypher 穩定後 acr update 重跑`));
  }
}

function createHelloYamlIfMissing(): void {
  const helloPath = join(process.cwd(), 'hello.yaml');
  if (!existsSync(helloPath)) {
    writeFileSync(helloPath,
      '# arcrun hello world workflow\n' +
      '# 執行：acr run hello --input input="Hello, arcrun!"\n\n' +
      'name: hello\n' +
      'description: "Hello world — 示範字串轉大寫"\n\n' +
      'flow:\n' +
      '  - "input >> ON_SUCCESS >> transform"\n\n' +
      'config:\n' +
      '  transform:\n' +
      '    component: string_ops\n' +
      '    operation: upper\n',
      'utf8'
    );
  }
}

function createCredentialsYamlIfMissing(): void {
  const credPath = join(process.cwd(), 'credentials.yaml');
  if (!existsSync(credPath)) {
    writeFileSync(credPath,
      '# arcrun credentials — 不要提交至 git！\n' +
      '# 執行 acr creds push 上傳加密後的 credential 到你的 CF KV\n\n' +
      '# gmail_token: "your-google-oauth-token"\n' +
      '# telegram_bot_token: "your-telegram-bot-token"\n' +
      '# google_oauth: "your-google-oauth-token"\n' +
      '# line_token: "your-line-notify-token"\n',
      'utf8'
    );
  }

  // 確保 .gitignore 排除 credentials.yaml + 專案層 .arcrun.yaml（可能含 cf_api_token）
  // 壓測 §1.2 安全附帶發現：憑證進版控 = 帳號控制權外洩。
  const gitignorePath = join(process.cwd(), '.gitignore');
  if (existsSync(gitignorePath)) {
    const content = readFileSync(gitignorePath, 'utf8');
    const toAdd: string[] = [];
    if (!content.includes('credentials.yaml')) toAdd.push('credentials.yaml');
    if (!content.includes('.arcrun.yaml')) toAdd.push('.arcrun.yaml');
    if (toAdd.length > 0) appendFileSync(gitignorePath, '\n' + toAdd.join('\n') + '\n');
  }
}
