/**
 * acr search <term> — 跨類統一搜尋（component / recipe / auth-recipe / workflow）
 *
 * 為什麼存在（issue #13，leo 2026-06-29）：
 *   舊世界要找一個能力（如 "telegram"）必須**先決定**「它是零件？recipe？還是 workflow？」才能查對的清單。
 *   但查的人（人或 AI）在查到答案前**根本不知道**它屬哪一類 →「先知道分類」成了查詢的前置條件，倒因為果。
 *   leo:「連我都會查錯表。」所以這不是粗心，是搜尋設計缺陷。
 *   本指令一次掃全部類別、依類別分組回 counts + 命中 → 查的人不必先選表，看一眼就知道 telegram 是 recipe。
 *
 * 薄殼原則（rule 07 §2）：本指令只做 fan-out 呼叫既有清單來源 + 過濾 + 分組 + 印出（介面層的暴露/格式化）。
 *   - component：靜態（BUILTIN_COMPONENTS，PR-only，複用 parts.ts 同一份，不另存）。
 *   - recipe / auth-recipe / workflow：**動態**，從 store 端點即時抓（GET /recipes、/auth-recipes、/webhooks/named）。
 *   不在介面層拼裝任何能力；過濾是對 API 回傳值做的純客戶端格式化（§2.3 允許）。
 */
import chalk from 'chalk';
import { loadConfig, getCypherExecutorUrl } from '../lib/config.js';
import { BUILTIN_COMPONENTS } from './parts.js';

interface Hit {
  id: string;            // canonical_id / service / workflow name
  label: string;         // display_name / 描述用名稱
  detail?: string;       // description（截斷）
}

interface CategoryResult {
  key: 'component' | 'recipe' | 'auth-recipe' | 'workflow';
  title: string;
  dynamic: boolean;            // 是否來自 store（動態）
  listHint: string;            // 列全部的指令
  hits: Hit[];
  error?: string;              // 該來源抓取失敗（離線/服務不可用）→ 降級顯示，不中斷其他類
}

/** term 命中：id / label / detail 任一含 term（不分大小寫） */
function matches(term: string, ...fields: Array<string | undefined>): boolean {
  const t = term.toLowerCase();
  return fields.some((f) => (f ?? '').toLowerCase().includes(t));
}

function trim(s: string | undefined, n = 70): string | undefined {
  if (!s) return undefined;
  return s.length > n ? s.slice(0, n - 1) + '…' : s;
}

async function fetchJson(url: string, headers: Record<string, string>): Promise<unknown> {
  const res = await fetch(url, { method: 'GET', headers });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

export async function cmdSearch(term: string): Promise<void> {
  const q = (term ?? '').trim();
  if (!q) {
    console.error(chalk.red('  請提供搜尋關鍵字：acr search <term>'));
    process.exit(1);
  }

  const config = loadConfig();
  const baseUrl = getCypherExecutorUrl(config);
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
  if (config.api_key) headers['X-Arcrun-API-Key'] = config.api_key;

  // ── component（靜態，本地，永不失敗）──
  const componentRes: CategoryResult = {
    key: 'component',
    title: '零件 component（靜態 · PR-only · WASM）',
    dynamic: false,
    listHint: 'acr parts',
    hits: BUILTIN_COMPONENTS
      .filter((c) => matches(q, c.canonical_id, c.display_name, c.description))
      .map((c) => ({ id: c.canonical_id, label: c.display_name, detail: trim(c.description) })),
  };

  // ── recipe / auth-recipe / workflow（動態，store；各自獨立 try，互不連坐）──
  const dynamicSpecs: Array<{
    key: CategoryResult['key'];
    title: string;
    listHint: string;
    url: string;
    extract: (data: unknown) => Hit[];
  }> = [
    {
      key: 'recipe',
      title: 'API recipe（動態 · store · 打外部服務）',
      listHint: 'acr recipe list',
      url: `${baseUrl}/recipes`,
      extract: (data) => {
        const arr = (data as { recipes?: Array<{ canonical_id: string; display_name?: string; description?: string }> }).recipes ?? [];
        return arr
          .filter((r) => matches(q, r.canonical_id, r.display_name, r.description))
          .map((r) => ({ id: r.canonical_id, label: r.display_name ?? r.canonical_id, detail: trim(r.description) }));
      },
    },
    {
      key: 'auth-recipe',
      title: '第三方服務認證 auth-recipe（動態 · store）',
      listHint: 'acr auth-recipe list',
      url: `${baseUrl}/auth-recipes`,
      extract: (data) => {
        const arr = (data as { recipes?: Array<{ service: string; display_name?: string; description?: string }> }).recipes ?? [];
        return arr
          .filter((r) => matches(q, r.service, r.display_name, r.description))
          .map((r) => ({ id: r.service, label: r.display_name ?? r.service, detail: trim(r.description) }));
      },
    },
    {
      key: 'workflow',
      title: '已部署 workflow（動態 · store）',
      listHint: 'acr list',
      url: `${baseUrl}/webhooks/named`,
      extract: (data) => {
        const arr = (data as { workflows?: Array<{ name: string; description?: string }> }).workflows ?? [];
        return arr
          .filter((w) => matches(q, w.name, w.description))
          .map((w) => ({ id: w.name, label: w.name, detail: trim(w.description) }));
      },
    },
  ];

  const dynamicResults = await Promise.all(
    dynamicSpecs.map(async (spec): Promise<CategoryResult> => {
      try {
        const data = await fetchJson(spec.url, headers);
        return { key: spec.key, title: spec.title, dynamic: true, listHint: spec.listHint, hits: spec.extract(data) };
      } catch (e) {
        return { key: spec.key, title: spec.title, dynamic: true, listHint: spec.listHint, hits: [], error: e instanceof Error ? e.message : String(e) };
      }
    }),
  );

  const all: CategoryResult[] = [componentRes, ...dynamicResults];

  // ── 印出：先一行 counts 摘要（看一眼就知道屬哪類），再各類明細 ──
  console.log(chalk.bold(`\n  搜尋「${q}」\n`));

  const countLine = all
    .map((r) => {
      const n = r.error ? '?' : String(r.hits.length);
      const c = r.error ? chalk.yellow(`${r.key}:${n}`) : (r.hits.length > 0 ? chalk.green(`${r.key}:${n}`) : chalk.gray(`${r.key}:0`));
      return c;
    })
    .join('   ');
  console.log('  ' + countLine + '\n');

  let anyHit = false;
  for (const r of all) {
    if (r.error) {
      console.log(chalk.yellow(`  ${r.title} — 無法讀取（${r.error}）；離線時改用 ${chalk.cyan(r.listHint)}`));
      console.log('');
      continue;
    }
    if (r.hits.length === 0) continue;
    anyHit = true;
    console.log(chalk.bold.underline(`  ${r.title}`));
    for (const h of r.hits) {
      const label = h.label && h.label !== h.id ? `  ${h.label}` : '';
      console.log(`    ${chalk.cyan(h.id.padEnd(24))}${label}`);
      if (h.detail) console.log(chalk.gray(`      ${h.detail}`));
    }
    console.log('');
  }

  if (!anyHit && !all.some((r) => r.error)) {
    console.log(chalk.yellow(`  四類都沒有命中「${q}」。`));
    console.log(chalk.gray('  • 想新增打外部服務的能力 → acr recipe push（建 recipe）'));
    console.log(chalk.gray('  • 服務認證設定 → acr auth-recipe list 找對應服務'));
    console.log(chalk.gray('  • 零件（WASM）只能走 GitHub PR 新增（稀有）'));
    console.log('');
  }
}
