/**
 * target-search — POST /cypher/search 的「指定搜尋對象」名字搜尋（t159）
 *
 * leo 07-31：「search 節點名稱和 search 工作流名稱是同一個？一個死了另一個不能動？
 * 難道我不能指定要搜尋工作流或節點或 recipe 嗎？」
 *
 * ⇒ discover 入口加 `target`（component／recipe／workflow）＋`query`：
 *   - target=component → 轉發 registry GET /components/search（MCP arcrun_search_components 同一條路）
 *   - target=recipe    → 掃私庫 RECIPES KV（與 discover 混搜的第二庫**同一份讀法** listAllRecipes）；
 *                        公庫（多作者市場）另有 /public-recipes＝MCP arcrun_recipe_search，回應註明
 *   - target=workflow  → lib/workflow-search.ts（GET /workflows/search＝MCP arcrun_search_workflows 同一條路）
 *
 * 「外部 API 只有一條一致的路」：三個 target 各自對應**既有**搜尋機制，本檔只做轉接，
 * 不新造第二套搜尋。flag 安全：主動 pull，無輪詢。
 */

import { wasmWorkerUrl } from '../lib/component-loader';
import { fetchTenantWorkflowSearch } from '../lib/workflow-search';
import { listAllRecipes, buildPayloadHint, type SearchNodesEnv } from './search-nodes';
import { branchHintFor } from '../lib/branch-hints';

export type TargetQueryEnv = SearchNodesEnv & {
  KBDB_BASE_URL?: string;
  KBDB_INTERNAL_TOKEN?: string;
};

export type TargetQueryResult =
  | { ok: true; body: Record<string, unknown> }
  | { ok: false; status: 400 | 401 | 502; error: string };

export async function searchByTarget(
  target: 'component' | 'recipe' | 'workflow',
  query: string,
  env: TargetQueryEnv,
  apiKey?: string,
): Promise<TargetQueryResult> {
  if (target === 'component') {
    const sub = env.WORKER_SUBDOMAIN;
    const registryBase = env.REGISTRY_BASE_URL ?? (sub ? wasmWorkerUrl('registry', sub) : undefined);
    if (!registryBase) return { ok: false, status: 502, error: 'registry 位置未設定（WORKER_SUBDOMAIN／REGISTRY_BASE_URL 皆缺）' };
    try {
      const res = await fetch(
        `${registryBase}/components/search?q=${encodeURIComponent(query)}`,
        { signal: AbortSignal.timeout(10000) },
      );
      if (!res.ok) return { ok: false, status: 502, error: `registry 搜尋失敗（HTTP ${res.status}）` };
      const body = (await res.json()) as { data?: { results?: unknown[]; count?: number } };
      // 3.11：逐顆查零件（n8n 式「自己一顆一顆填」）時，會分岔的零件要自我說明分支用法。
      // leo 08-01：「它可以一一查詢自己手工填寫每個零件，就像在 n8n 那樣」——
      // 這條路徑若只回 input_schema，AI 拿到 if_control／switch 仍不知道兩條路怎麼接 ⇒ 回頭寫 code。
      const results = (body.data?.results ?? []).map(r => {
        if (!r || typeof r !== 'object') return r;
        const rec = r as Record<string, unknown>;
        const hint = branchHintFor(typeof rec.canonical_id === 'string' ? rec.canonical_id : undefined);
        return hint ? { ...rec, branch_hint: hint } : rec;
      });
      return {
        ok: true,
        body: {
          target,
          query,
          results,
          count: body.data?.count ?? 0,
        },
      };
    } catch (e) {
      return { ok: false, status: 502, error: `registry 查不通：${e instanceof Error ? e.message : String(e)}` };
    }
  }

  if (target === 'recipe') {
    if (!env.RECIPES) return { ok: false, status: 502, error: 'RECIPES KV 未綁定' };
    const all = await listAllRecipes(env.RECIPES);
    const q = query.toLowerCase();
    // 與 discover 混搜同一份庫（私庫＝workflow 實際引用得到的）；子字串比對、canonical 去重
    const seen = new Set<string>();
    const results: Array<{
      canonical_id: string; display_name?: string; description?: string; endpoint: string;
      payload_hint?: unknown;
    }> = [];
    for (const r of all) {
      if (seen.has(r.canonical_id)) continue;
      const hay = `${r.canonical_id} ${r.display_name ?? ''} ${r.description ?? ''}`.toLowerCase();
      if (!hay.includes(q)) continue;
      seen.add(r.canonical_id);
      results.push({
        canonical_id: r.canonical_id,
        display_name: r.display_name,
        description: r.description,
        endpoint: r.endpoint,
        // 3.12：逐顆查 recipe 時也要說得出「payload 怎麼填、回應怎麼取值」
        payload_hint: buildPayloadHint(r),
      });
    }
    return {
      ok: true,
      body: {
        target,
        query,
        results,
        count: results.length,
        note: '搜的是本部署私庫（workflow 可直接 component: <canonical_id> 引用）。公庫（多作者市場）走 MCP arcrun_recipe_search／GET /public-recipes。',
      },
    };
  }

  // target === 'workflow'：租戶隔離，必帶 API key（同 GET /workflows/search 的既有契約）
  if (!apiKey) return { ok: false, status: 401, error: 'target=workflow 需要 X-Arcrun-API-Key header（workflow 搜尋限本租戶）' };
  const res = await fetchTenantWorkflowSearch(env, apiKey, query);
  if (!res.ok) return { ok: false, status: 502, error: `workflow 搜尋失敗（KBDB HTTP ${res.status}）` };
  const body = (await res.json()) as Record<string, unknown>;
  return { ok: true, body: { target, query, ...body } };
}
