#!/usr/bin/env node
/**
 * arcrun CLI — acr
 * AI Workflow CLI for Cloudflare Workers + WASM
 *
 * 安裝：npm i -g arcrun
 * 使用：acr <指令>
 */
import { Command } from 'commander';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { cmdInit } from './commands/init.js';
import { cmdConfig } from './commands/config.js';
import { cmdWhoami } from './commands/whoami.js';
import { cmdCredsPush, cmdCredsList, cmdCredsReplace, cmdCredsDelete } from './commands/creds.js';
import { cmdPush } from './commands/push.js';
import { cmdRun } from './commands/run.js';
import { cmdValidate } from './commands/validate.js';
import { cmdParts, cmdPartsScaffold, cmdPartsPublish } from './commands/parts.js';
import { cmdRecipePush, cmdRecipeList, cmdRecipeDelete, cmdRecipeSearch, cmdRecipePull, cmdRecipeSubmitP } from './commands/recipe.js';
import { cmdList } from './commands/list.js';
import { cmdSearch } from './commands/search.js';
import { cmdLogs } from './commands/logs.js';
import { cmdUpdate } from './commands/update.js';
import { cmdInstallHarness } from './commands/install-harness.js';
import { cmdMcpSetup } from './commands/mcp-setup.js';
import {
  cmdKbdbTemplateCreate,
  cmdKbdbTemplateList,
  cmdKbdbRecordCreate,
  cmdKbdbRecordGet,
  cmdKbdbQuery,
  cmdKbdbSearch,
} from './commands/kbdb.js';
import { cmdAuthRecipeList, cmdAuthRecipeInfo, cmdAuthRecipeScaffold } from './commands/auth-recipe.js';

const program = new Command();

// 版本從 package.json 動態讀（dist/index.js 旁的 ../package.json），不 hardcode → 永不漂移。
// 之前 hardcode '1.1.0' 與 package.json '1.2.0' 不一致，正是「忘了改」的反例。
function readVersion(): string {
  try {
    const here = dirname(fileURLToPath(import.meta.url));
    return (JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf8')) as { version?: string }).version ?? '0.0.0';
  } catch {
    return '0.0.0';
  }
}

program
  .name('acr')
  .description('arcrun — AI Workflow CLI for Cloudflare Workers + WASM')
  .version(readVersion());

// acr init [--self-hosted] [--account-id <id>] [--api-token <token>]
program
  .command('init')
  .description('互動式初始化設定（建立 ~/.arcrun/config.yaml）')
  .option('--local', '本機模式：不需要 Cloudflare 帳號，直接在本機測試 workflow')
  .option('--self-hosted', '完全 Self-hosted 模式：自行部署所有 Cloudflare Worker')
  .option('--account-id <id>', 'self-hosted：CF Account ID（非互動；亦可用 CLOUDFLARE_ACCOUNT_ID env）')
  .option('--api-token <token>', 'self-hosted：CF API Token（非互動；亦可用 CLOUDFLARE_API_TOKEN env）')
  .action((options: { local?: boolean; selfHosted?: boolean; accountId?: string; apiToken?: string }) =>
    cmdInit(options),
  );

// acr config [--where]：印出目前生效的設定與每個值的來源層（env / 專案層 / 全域）
program
  .command('config')
  .description('顯示目前生效的設定與來源層（避免在錯的資料夾用錯帳號）')
  .option('--where', '顯示每個設定值來自哪一層（env > 專案層 .arcrun.yaml > 全域）')
  .action((options: { where?: boolean }) => cmdConfig(options));

// acr whoami [--json]：一眼看當前身份（mode / 連哪台 cypher / 帳號來源層）。§7.8 P1 D2 修法。
program
  .command('whoami')
  .description('顯示目前生效的身份（帳號、連哪台 cypher、來源層）——AI 別自己 curl 猜帳號')
  .option('--json', '結構化輸出（給 AI / 腳本讀取）')
  .action((options: { json?: boolean }) => cmdWhoami(options));

// acr creds push/list/replace/delete — credential-store-migration T9（治理端點 CLI 薄殼）
const credsCmd = program.command('creds').description('Credential 管理（D19：只能看目錄/replace/delete，讀不回值）');
credsCmd
  .command('push [file]')
  .description('批次上傳 credentials.yaml（明文經 TLS，值存進你的 Workers Secrets，不經過 arcrun.dev）')
  .action((file: string) => cmdCredsPush(file ?? 'credentials.yaml'));
credsCmd
  .command('list')
  .description('列出已存的 credential 目錄（name/service/sensitivity/last_used，不含值）')
  .action(() => cmdCredsList());
credsCmd
  .command('replace <name> <value>')
  .description('整筆覆寫一個 credential 的值（只能整筆換，不能局部編輯）')
  .option('--service <service>', '對應 service 名（如 telegram）')
  .option('--sensitivity <level>', 'standard | high')
  .action((name: string, value: string, options: { service?: string; sensitivity?: string }) =>
    cmdCredsReplace(name, value, options));
credsCmd
  .command('delete <name>')
  .description('刪除一個 credential（目錄 row + Workers Secret 本體）')
  .action((name: string) => cmdCredsDelete(name));

// acr push <workflow.yaml>
program
  .command('push <file>')
  .description('解析 workflow.yaml 並部署至你的 CF KV')
  .action((file: string) => cmdPush(file));

// acr run <workflow_name> [--input key=value...]
program
  .command('run <workflow>')
  .description('執行指定 workflow')
  .option('-i, --input <pairs...>', 'input 參數（格式：key=value）')
  .action((workflow: string, options: { input?: string[] }) => cmdRun(workflow, options));

// acr validate <workflow.yaml>
program
  .command('validate <file>')
  .description('執行前驗證 workflow.yaml（格式、關係詞、零件存在性、credentials）')
  .option('--offline', '離線模式：跳過零件存在性與 credentials 的遠端檢查')
  .action((file: string, options: { offline?: boolean }) => cmdValidate(file, options));

// acr parts
// acr parts scaffold <component>
// acr parts publish <component> [--status <submission_id>]
const partsCmd = program.command('parts').description('零件庫管理');
partsCmd
  .action(() => cmdParts());

partsCmd
  .command('scaffold <component>')
  .description('輸出零件的 config 範本（可直接貼入 workflow.yaml）')
  .action((component: string) => cmdPartsScaffold(component));

partsCmd
  .command('publish <component-dir>')
  .description('提交零件至 arcrun.dev 公眾 registry')
  .option('--status <submission_id>', '查詢提交審核進度')
  .action((dir: string, options: { status?: string }) => cmdPartsPublish(dir, options));

// acr recipe push / list / delete
const recipeCmd = program.command('recipe').description('API Recipe 管理');
recipeCmd
  .command('push <file>')
  .description('上傳 recipe YAML 到 arcrun.dev（不需要 deploy Worker）')
  .action((file: string) => cmdRecipePush(file));
recipeCmd
  .command('list')
  .description('列出已上傳的 recipe')
  .action(() => cmdRecipeList());
recipeCmd
  .command('delete <id>')
  .description('刪除 recipe（canonical_id 或 rec_hash）')
  .action((id: string) => cmdRecipeDelete(id));
// 公庫互動（kbdb-base §7.5）
recipeCmd
  .command('search <query>')
  .description('搜尋公庫 recipe（同名可多作者，附市場數據）')
  .action((query: string) => cmdRecipeSearch(query));
recipeCmd
  .command('pull <canonical_id>')
  .description('從公庫取一份 recipe 寫進自己私庫')
  .option('--author <name>', '指定作者版本（不指定取市場最佳）')
  .action((canonicalId: string, opts: { author?: string }) => cmdRecipePull(canonicalId, opts.author));
recipeCmd
  .command('submit-p <canonical_id>')
  .description('把私庫某 recipe 投稿到公庫（新增作者版本，需暴露同意）')
  .option('--author <name>', '署名作者（預設用 recipe 既有 author）')
  .action((canonicalId: string, opts: { author?: string }) => cmdRecipeSubmitP(canonicalId, opts.author));

// acr auth-recipe list / info / scaffold
const authRecipeCmd = program.command('auth-recipe').description('第三方服務認證 Recipe（新增服務整合）');
authRecipeCmd
  .command('list')
  .description('列出所有平台預建的服務整合（Notion、Slack、GitHub 等）')
  .action(() => cmdAuthRecipeList());
authRecipeCmd
  .command('info <service>')
  .description('顯示服務 recipe 詳情（需要哪些 credential）')
  .action((service: string) => cmdAuthRecipeInfo(service));
authRecipeCmd
  .command('scaffold <service>')
  .description('輸出 credentials.yaml 範本 + workflow.yaml 使用範例')
  .action((service: string) => cmdAuthRecipeScaffold(service));

// acr kbdb — KBDB 資料層薄殼（kbdb-base 9.2，透過 cypher KBDB proxy；與 MCP kbdb_* 同能力）
const kbdbCmd = program.command('kbdb').description('KBDB 資料層（template/record/query/search；不建表、不寫 SQL）');
const kbdbTemplateCmd = kbdbCmd.command('template').description('template = 虛擬表定義（name + slots）');
kbdbTemplateCmd
  .command('create <name>')
  .description('建一個 template（虛擬表定義），如 --slots name,email,phone')
  .requiredOption('--slots <list>', '欄位名清單，逗號分隔，如 name,email,phone')
  .action((name: string, opts: { slots: string }) => cmdKbdbTemplateCreate(name, opts));
kbdbTemplateCmd
  .command('list')
  .description('列出所有 template')
  .action(() => cmdKbdbTemplateList());
const kbdbRecordCmd = kbdbCmd.command('record').description('record = 依 template 填的一筆資料');
kbdbRecordCmd
  .command('create <template>')
  .description('填一筆 record，如 --values name=Leo --values email=x@y.com（可重複）')
  .option('--values <pair...>', 'slot=內容（可重複）')
  .action((template: string, opts: { values?: string[] }) => cmdKbdbRecordCreate(template, opts));
kbdbRecordCmd
  .command('get <record_id>')
  .description('取單筆 record 全文')
  .action((recordId: string) => cmdKbdbRecordGet(recordId));
kbdbCmd
  .command('query <template>')
  .description('列某 template 下本租戶的所有 record')
  .action((template: string) => cmdKbdbQuery(template));
kbdbCmd
  .command('search <q>')
  .description('關鍵字搜尋本租戶內容（LIKE，基本盤）')
  .action((q: string) => cmdKbdbSearch(q));

// acr list
program
  .command('list')
  .description('列出 CF KV 中所有已部署的 workflow')
  .action(() => cmdList());

// acr search <term> — 跨類統一搜尋（component / recipe / auth-recipe / workflow），免先選表
program
  .command('search <term>')
  .description('跨類搜尋能力（零件/recipe/auth-recipe/workflow），一次掃全部、依類別回 counts+命中')
  .action((term: string) => cmdSearch(term));

// acr logs <workflow_name>
program
  .command('logs <workflow>')
  .description('顯示 workflow 最近執行記錄')
  .action((workflow: string) => cmdLogs(workflow));

// acr update（self-hosted：拉新 release 重新部署零件/引擎）
program
  .command('update')
  .description('self-hosted：拉新 release 並重新部署到你的 Cloudflare')
  .option('--force', '強制重部所有 worker（忽略未變動跳過快取）')
  .action((opts: { force?: boolean }) => cmdUpdate({ force: opts.force }));

// acr install-harness（把 arcrun 的 CC harness 裝進當前專案）
program
  .command('install-harness')
  .description('把 arcrun 的 CC harness（mindset/提醒/防做歪 hook/指令）裝進當前專案')
  .action(() => cmdInstallHarness());

// acr mcp-setup（依 config 解析的 mcp_url 寫專案 .mcp.json，讓 Claude Code 連對的 MCP）
program
  .command('mcp-setup')
  .description('在目前資料夾寫 .mcp.json 連對的 arcrun MCP（依 config 的 mcp_url；接案切資料夾自動切）')
  .action(() => cmdMcpSetup());

program.parse(process.argv);
