/**
 * Recipe tools（kbdb-base §7.5.i）— MCP 薄殼補齊 recipe 能力。
 *
 * rule 07 §5：CLI + MCP 覆蓋同一組 API 能力，MCP 不可長期落後。
 * CLI 已有 recipe push/list/delete/search/pull/submit-p（cli/src/commands/recipe.ts）；
 * 此檔把同六能力暴露為 MCP 工具，**薄殼**：只 cypherFetch + 格式化，無業務邏輯。
 *
 * 私庫操作（push/list/delete/pull-install）→ cypherFetch 打用戶 cypher（= 私庫）。
 * 公庫操作（search/pull-fetch/submit-p）→ 同樣經 cypher（MCP 連平台 cypher = 公庫；
 *   self-hosted account-source 是 §5.2 已知違反，pre-existing，本檔沿用既有 cypherFetch 模式）。
 */

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { toolName } from "../brand.js";
import { z } from "zod";
import type { Env } from "../types.js";
import { cypherFetch, errorResponse, successResponse } from "../lib/cypher-client.js";

const apiKeyDesc = "你（用戶）的 arcrun api_key (ak_xxx)。從 https://arcrun.dev/me 取得";

/** 註冊全部 recipe 工具（kbdb-base §7.5.i，與 CLI 六能力對齊）。 */
export function registerAllRecipeTools(server: McpServer, env: Env) {
  registerRecipeSearch(server, env);
  registerRecipePull(server, env);
  registerRecipeSubmitP(server, env);
  registerRecipePush(server, env);
  registerRecipeList(server, env);
  registerRecipeDelete(server, env);
}

/** arcrun_recipe_search — 搜尋公庫 recipe（同名可多作者，附市場數據）。落空回創作引導。 */
export function registerRecipeSearch(server: McpServer, env: Env) {
  server.tool(
    toolName("recipe_search"),
    "搜尋公庫 recipe（API 整合配方）。同 canonical_id 可有多作者版本，各附市場數據（成功/失敗次數），依數據選最佳。找不到時會提示可自己做一個 recipe 投稿成為作者。",
    {
      api_key: z.string().describe(apiKeyDesc),
      query: z.string().describe("搜尋詞，如「gsheets append」「telegram send」"),
    },
    async ({ api_key, query }) => {
      try {
        const res = await cypherFetch(env, "/public-recipes", {
          apiKey: api_key,
          query: { q: query },
        });
        if (!res.ok) return errorResponse("search_failed", `搜尋公庫失敗`, ["稍後再試"], await res.text());
        const data = await res.json();
        return successResponse(data, [
          "found:false → 公庫沒有，可自己做：建 recipe → arcrun_recipe_push（私庫）→ arcrun_recipe_submit_p（投稿）",
          "多作者版本依 market_stat 選成功率最高的 → arcrun_recipe_pull",
        ]);
      } catch (e) {
        return errorResponse("internal_error", e instanceof Error ? e.message : String(e), []);
      }
    },
  );
}

/** arcrun_recipe_pull — 從公庫取一份 recipe 寫進自己私庫。 */
export function registerRecipePull(server: McpServer, env: Env) {
  server.tool(
    toolName("recipe_pull"),
    "從公庫取一份 recipe 寫進自己私庫（按需取用，非全量同步）。不指定 author 取市場最佳版本。取回後可在 workflow 用 component: <canonical_id>。",
    {
      api_key: z.string().describe(apiKeyDesc),
      canonical_id: z.string().describe("要取的 recipe canonical_id，如 gsheets_append"),
      author: z.string().optional().describe("指定作者版本（不指定取市場最佳）"),
    },
    async ({ api_key, canonical_id, author }) => {
      try {
        // 1. 公庫取全文
        const pubRes = await cypherFetch(env, `/public-recipes/${encodeURIComponent(canonical_id)}`, {
          apiKey: api_key,
          query: author ? { author } : undefined,
        });
        if (!pubRes.ok) return errorResponse("pull_failed", `公庫取 recipe 失敗`, [], await pubRes.text());
        const pub = await pubRes.json() as
          | { found: true; recipe: Record<string, unknown> & { uuid?: string } }
          | { found: false; canonical_id: string; hint: string };
        if (!pub.found) {
          return successResponse(pub, [
            "公庫沒有此 recipe。可自己做：arcrun_recipe_push（私庫）→ arcrun_recipe_submit_p（投稿成為作者）",
          ]);
        }
        // 2. 寫進私庫（帶 derived_from 溯源 + pull 級暴露同意）
        const installRes = await cypherFetch(env, "/recipes", {
          apiKey: api_key,
          method: "POST",
          body: {
            ...pub.recipe,
            derived_from: pub.recipe.uuid,
            exposure_consent: {
              confirmed_by_human: true,
              understood: `pull from public library: ${canonical_id}`,
              confirmed_at: new Date().toISOString(),
            },
          },
        });
        if (!installRes.ok) return errorResponse("install_failed", `寫入私庫失敗`, [], await installRes.text());
        const inst = await installRes.json();
        return successResponse(inst, [`已拉進私庫，workflow 可用 component: ${canonical_id}`]);
      } catch (e) {
        return errorResponse("internal_error", e instanceof Error ? e.message : String(e), []);
      }
    },
  );
}

/** arcrun_recipe_submit_p — 把私庫某 recipe 投稿到公庫（新增作者版本）。 */
export function registerRecipeSubmitP(server: McpServer, env: Env) {
  server.tool(
    toolName("recipe_submit_p"),
    "把私庫某 recipe 投稿到公庫（app-store 模型：新增一個作者版本，不覆蓋別人的）。投稿 = 把 recipe 暴露給全網，需帶 exposure_consent 明示同意。別人能搜到並 pull，市場數據決定它被不被選用。",
    {
      api_key: z.string().describe(apiKeyDesc),
      canonical_id: z.string().describe("要投稿的私庫 recipe canonical_id"),
      author: z.string().optional().describe("署名作者（預設用 recipe 既有 author）"),
      exposure_consent: z.boolean().describe(
        "明示同意把此 recipe 暴露給公庫全網（投稿是暴露面，需人類同意）",
      ),
    },
    async ({ api_key, canonical_id, author, exposure_consent }) => {
      try {
        if (!exposure_consent) {
          return errorResponse("consent_required", "投稿到公庫是暴露面，需 exposure_consent=true 明示同意", [
            "確認要把 recipe 公開給全網後，帶 exposure_consent: true 再呼叫",
          ]);
        }
        // 1. 私庫取全文
        const myRes = await cypherFetch(env, `/recipes/${encodeURIComponent(canonical_id)}`, { apiKey: api_key });
        if (!myRes.ok) return errorResponse("not_found", `私庫找不到 recipe「${canonical_id}」`, ["先 arcrun_recipe_push 或 arcrun_recipe_pull"], await myRes.text());
        const my = await myRes.json() as { success: boolean; recipe?: Record<string, unknown> & { uuid?: string; author?: string; derived_from?: string } };
        if (!my.success || !my.recipe) return errorResponse("not_found", `私庫無此 recipe`, []);
        // 2. 投稿公庫（新增作者版本）
        const consent = {
          confirmed_by_human: true,
          understood: `submit recipe to public library: ${canonical_id}`,
          confirmed_at: new Date().toISOString(),
        };
        const subRes = await cypherFetch(env, "/recipes/submit", {
          apiKey: api_key,
          method: "POST",
          body: {
            ...my.recipe,
            author: author ?? my.recipe.author,
            derived_from: my.recipe.derived_from ?? my.recipe.uuid,
            submitter: author ?? api_key,
            exposure_consent: consent,
          },
        });
        if (!subRes.ok) return errorResponse("submit_failed", `投稿公庫失敗`, [], await subRes.text());
        const data = await subRes.json();
        return successResponse(data, ["已投稿公庫（新增作者版本）。市場數據累積後決定被不被選用"]);
      } catch (e) {
        return errorResponse("internal_error", e instanceof Error ? e.message : String(e), []);
      }
    },
  );
}

/** arcrun_recipe_push — 上傳/更新私庫 recipe（就地更新自己的版本）。 */
export function registerRecipePush(server: McpServer, env: Env) {
  server.tool(
    toolName("recipe_push"),
    "上傳一份 recipe 到自己私庫（或就地更新自己既有版本）。recipe = 「http_request + 參數模板」的具名封裝，不需 deploy Worker。要投稿到公庫用 arcrun_recipe_submit_p。",
    {
      api_key: z.string().describe(apiKeyDesc),
      recipe: z.object({
        canonical_id: z.string(),
        display_name: z.string().optional(),
        description: z.string().optional(),
        endpoint: z.string(),
        method: z.string().optional(),
        headers: z.record(z.string()).optional(),
        body: z.record(z.unknown()).optional(),
        auth_service: z.string().optional(),
        author: z.string().optional(),
      }).describe("recipe 定義（canonical_id + endpoint 必填）"),
    },
    async ({ api_key, recipe }) => {
      try {
        const res = await cypherFetch(env, "/recipes", { apiKey: api_key, method: "POST", body: recipe });
        if (!res.ok) return errorResponse("push_failed", `上傳 recipe 失敗`, [], await res.text());
        const data = await res.json();
        return successResponse(data, [`workflow 用 component: ${recipe.canonical_id}`, "要公開給全網 → arcrun_recipe_submit_p"]);
      } catch (e) {
        return errorResponse("internal_error", e instanceof Error ? e.message : String(e), []);
      }
    },
  );
}

/** arcrun_recipe_list — 列出自己私庫的 recipe。 */
export function registerRecipeList(server: McpServer, env: Env) {
  server.tool(
    toolName("recipe_list"),
    "列出自己私庫（本部署）的 recipe。要找公庫的用 arcrun_recipe_search。",
    {
      api_key: z.string().describe(apiKeyDesc),
    },
    async ({ api_key }) => {
      try {
        const res = await cypherFetch(env, "/recipes", { apiKey: api_key });
        if (!res.ok) return errorResponse("list_failed", `列出 recipe 失敗`, [], await res.text());
        const data = await res.json();
        return successResponse(data);
      } catch (e) {
        return errorResponse("internal_error", e instanceof Error ? e.message : String(e), []);
      }
    },
  );
}

/** arcrun_recipe_delete — 刪除私庫某 recipe。 */
export function registerRecipeDelete(server: McpServer, env: Env) {
  server.tool(
    toolName("recipe_delete"),
    "刪除自己私庫某 recipe（canonical_id / rec_hash / uuid）。不影響公庫別人的版本。",
    {
      api_key: z.string().describe(apiKeyDesc),
      id: z.string().describe("canonical_id 或 rec_hash 或 uuid"),
    },
    async ({ api_key, id }) => {
      try {
        const res = await cypherFetch(env, `/recipes/${encodeURIComponent(id)}`, { apiKey: api_key, method: "DELETE" });
        if (!res.ok) return errorResponse("delete_failed", `刪除 recipe 失敗`, [], await res.text());
        const data = await res.json();
        return successResponse(data);
      } catch (e) {
        return errorResponse("internal_error", e instanceof Error ? e.message : String(e), []);
      }
    },
  );
}
