import { NextResponse } from "next/server";
import { loadOnlineAiConfig } from "@/lib/ai/onlineAiConfig";
import { openAiCompatibleChat, tryExtractJsonObject } from "@/lib/ai/openaiCompatibleChat";
import { buildDocumentBridgeContextWithActor } from "@/lib/documents/bridge";
import { executeRustBridgeTool } from "@/lib/documents/rust-runtime";
import { readMindmapLocal } from "@/lib/mindmap/mindmapLocalStore";

type RequestPayload = {
  documentId: string;
  mindmapId: string;
  targetUid: string;
  instruction?: string;
  sources?: { searxng?: boolean; rag?: boolean };
};

type SearxResult = { title: string; url: string; snippet?: string; engine?: string };

const defaultMindmapData = {
  data: { text: "中心主题" },
  children: [],
};

const findNodeByUid = (root: any, uid: string): any | null => {
  const target = String(uid || "");
  if (!target) return null;
  const walk = (node: any): any | null => {
    const nuid = String(node?.data?.uid || node?.uid || "");
    if (nuid === target) return node;
    const children = Array.isArray(node?.children) ? node.children : [];
    for (const c of children) {
      const hit = walk(c);
      if (hit) return hit;
    }
    return null;
  };
  return walk(root);
};

const safeUrlOrNull = (value: unknown) => {
  const s = typeof value === "string" ? value.trim() : "";
  if (!s) return null;
  try {
    const u = new URL(s);
    if (u.protocol !== "http:" && u.protocol !== "https:") return null;
    return u.toString();
  } catch {
    return null;
  }
};

const searchSearxng = async (q: string, count = 5): Promise<SearxResult[]> => {
  const base = (process.env.SEARXNG_BASE_URL ?? "http://127.0.0.1:8889").replace(/\/+$/, "");
  const token = (process.env.SEARXNG_API_TOKEN ?? "").trim();
  const url = `${base}/search?q=${encodeURIComponent(q)}&format=json&language=zh-CN&categories=general&safesearch=1`;

  const tryFetch = async (headers: Record<string, string>) => {
    const res = await fetch(url, { headers, method: "GET" });
    if (!res.ok) return null;
    return (await res.json().catch(() => null)) as any;
  };

  let json: any = null;
  if (token) {
    json =
      (await tryFetch({ Authorization: `Bearer ${token}` })) ??
      (await tryFetch({ "X-API-Key": token })) ??
      null;
  }
  if (!json) {
    json = await tryFetch({});
  }
  const results = Array.isArray(json?.results) ? json.results : [];
  const mapped: SearxResult[] = results
    .map((r: any) => ({
      title: String(r?.title ?? "").trim(),
      url: String(r?.url ?? "").trim(),
      snippet: String(r?.content ?? r?.snippet ?? "").trim(),
      engine: String(r?.engine ?? "").trim(),
    }))
    .filter((r: SearxResult) => r.title && safeUrlOrNull(r.url))
    .slice(0, Math.max(1, Math.min(10, count)));
  return mapped;
};

const coerceOpsFromAiJson = (raw: Record<string, unknown>) => {
  const ops = (raw as any)?.ops;
  return Array.isArray(ops) ? ops : [];
};

export async function POST(request: Request) {
  const payload = (await request.json().catch(() => null)) as RequestPayload | null;
  if (!payload?.documentId || !payload?.mindmapId || !payload?.targetUid) {
    return NextResponse.json({ error: "缺少 documentId/mindmapId/targetUid" }, { status: 400 });
  }

  return NextResponse.json({ error: "当前仅支持 Convex 模式" }, { status: 501 });

  /*
  const supabase = await createSupabaseRouteClient();
  const {
    data: { session },
  } = await supabase.auth.getSession();
  if (!session) {
    return NextResponse.json({ error: "未登录" }, { status: 401 });
  }

  // 校验页面归属
  const { data: doc, error: docError } = await supabase
    .from("documents")
    .select("id,title,mindmap_data")
    .eq("id", payload.documentId)
    .eq("user_id", session.user.id)
    .maybeSingle();
  if (docError) {
    return NextResponse.json({ error: docError.message }, { status: 400 });
  }
  if (!doc) {
    return NextResponse.json({ error: "页面不存在" }, { status: 404 });
  }

  const local = await readMindmapLocal(payload.documentId, payload.mindmapId);
  const baseData = (local.ok ? local.data : (doc.mindmap_data ?? defaultMindmapData)) as MindmapTreeNode;

  const target = findNodeByUid(baseData, payload.targetUid);
  if (!target) {
    return NextResponse.json({ error: "未找到目标节点（uid 不存在）" }, { status: 404 });
  }

  const targetText = String(target?.data?.text ?? "").trim();
  const currentChildren = Array.isArray(target?.children)
    ? target.children
        .map((c: any) => String(c?.data?.text ?? "").trim())
        .filter(Boolean)
        .slice(0, 20)
    : [];

  const instruction = String(payload.instruction ?? "").trim();
  const query = [targetText, instruction].filter(Boolean).join(" ");

  const useSearx = payload.sources?.searxng !== false;
  const searxResults = useSearx && query ? await searchSearxng(query, 6).catch(() => []) : [];

  const cfg = await loadOnlineAiConfig().catch(() => null);
  if (!cfg) {
    return NextResponse.json({ error: "未找到在线 AI 配置（ai.md 或环境变量）" }, { status: 500 });
  }

  const system = [
    "你是一个“思维导图补完器”。",
    "你必须输出严格 JSON（不要 Markdown/不要代码块/不要解释）。",
    "你只能输出 {\"ops\": MindmapOp[]} 这一个对象。",
    "默认策略：为 targetUid 新增 3~6 个子节点（addChild）。",
    "每个新增节点必须提供 text，并尽量提供 hyperlink 与 refs（引用来自搜索结果 URL）。",
    "不要删除/改名已有节点；不要输出 addSiblingAfter/updateText/deleteNode。",
  ].join("\n");

  const user = [
    `documentId=${payload.documentId}`,
    `mindmapId=${payload.mindmapId}`,
    `targetUid=${payload.targetUid}`,
    "",
    `目标节点：${targetText || "(empty)"}`,
    currentChildren.length ? `当前子节点（供去重）：${currentChildren.join("；")}` : "",
    instruction ? `用户要求：${instruction}` : "",
    "",
    "可用证据（搜索结果）：",
    ...(searxResults.length
      ? searxResults.map((r, idx) => {
          const snip = (r.snippet || "").replace(/\s+/g, " ").slice(0, 180);
          return `${idx + 1}. ${r.title}\n   url: ${r.url}\n   snippet: ${snip}`;
        })
      : ["(无)"]),
    "",
    "MindmapOp JSON Schema（仅供理解）：",
    '{ "ops": [ { "op": "addChild", "parentUid": string, "node": { "text": string, "hyperlink"?: string, "refs"?: NodeRef[] } } ] }',
    'NodeRef 示例：{ "kind": "url", "fileUrl": "https://example.com", "title": "来源标题", "snippet": "..." }',
    "",
    "硬性约束：",
    "- 仅输出 addChild；parentUid 必须等于 targetUid。",
    "- 新增节点 text 不要与当前子节点重复。",
    "- hyperlink 必须是 http(s) URL。",
    "- 每个新增节点 refs 至少 1 条（kind=url, fileUrl=来源url）。",
    "- 输出规模控制：最多 6 个节点。",
  ]
    .filter(Boolean)
    .join("\n");

  let finishReason = "";
  let ops: MindmapOp[] = [];
  try {
    const { text, raw } = await openAiCompatibleChat(
      [
        { role: "system", content: system },
        { role: "user", content: user },
      ],
      {
        baseUrl: cfg.baseUrl,
        apiKey: cfg.apiKey,
        model: cfg.model,
        timeoutMs: 40_000,
        maxTokens: 1800,
        maxCompletionTokens: 1800,
        responseFormat: "json_object",
      },
    );

    finishReason = String((raw as any)?.choices?.[0]?.finish_reason ?? "");

    const json = tryExtractJsonObject(text);
    if (json) {
      ops = coerceOpsFromAiJson(json);
      // 安全收敛：仅允许 addChild 且 parentUid==targetUid
      ops = ops
        .filter((op) => op && typeof op === "object" && (op as any).op === "addChild")
        .filter((op) => String((op as any).parentUid || "") === payload.targetUid)
        .slice(0, 8);
    }
  } catch {
    // ignore: 后续走兜底策略
    ops = [];
  }

  // 再做一次补齐/校验：refs/hyperlink
  const fallbackRefsFrom = (r: SearxResult): NodeRef[] => [
    {
      kind: "url",
      fileUrl: r.url,
      title: r.title,
      snippet: r.snippet ? r.snippet.slice(0, 300) : undefined,
    },
  ];

  const existed = new Set(currentChildren);
  const fixed: MindmapOp[] = [];
  for (const op of ops) {
    const node = (op as any).node ?? {};
    const textVal = String(node.text ?? "").trim();
    if (!textVal) continue;
    if (existed.has(textVal)) continue;
    existed.add(textVal);

    const href = safeUrlOrNull(node.hyperlink) ?? safeUrlOrNull(node.url) ?? null;
    const refs = Array.isArray(node.refs) ? (node.refs as NodeRef[]) : [];
    const hasRefUrl = refs.some((x) => x && x.kind === "url" && safeUrlOrNull((x as any).fileUrl));

    let finalRefs = refs;
    if (!hasRefUrl && searxResults.length) {
      finalRefs = fallbackRefsFrom(searxResults[0]);
    }

    fixed.push({
      op: "addChild",
      parentUid: payload.targetUid,
      node: {
        text: textVal,
        ...(href ? { hyperlink: href } : {}),
        ...(finalRefs.length ? { refs: finalRefs } : {}),
      },
    });
    if (fixed.length >= 6) break;
  }

  // 兜底：若 AI 没产出有效 ops，则直接用搜索结果生成节点（保证功能可用 + 可追溯）
  if (!fixed.length && searxResults.length) {
    for (const r of searxResults.slice(0, 6)) {
      const title = String(r.title || "").trim();
      const url = safeUrlOrNull(r.url);
      if (!title || !url) continue;
      if (existed.has(title)) continue;
      existed.add(title);
      fixed.push({
        op: "addChild",
        parentUid: payload.targetUid,
        node: {
          text: title,
          hyperlink: url,
          refs: fallbackRefsFrom(r),
        },
      });
      if (fixed.length >= 6) break;
    }
  }

  if (!fixed.length) {
    // 最后兜底：至少给出 3 个“待核验”节点（无引用）
    const base = targetText || "补完";
    for (let i = 1; i <= 3; i++) {
      fixed.push({
        op: "addChild",
        parentUid: payload.targetUid,
        node: {
          text: `${base}（待核验）${i}`,
        },
      });
    }
  }

  const context = buildDocumentBridgeContextWithActor({
    request,
    actor: {
      actorType: "service",
      actorId: "mindmap-expand-node",
      sessionId: null,
    },
    workspaceId: (doc as any).workspace_id ?? null,
    source: {
      channel: "mindmap-expand-route",
      client: "wolai-frontend",
    },
  });

  const result = await executeRustBridgeTool<{
    ok: boolean;
    applied?: number;
    errors?: string[];
    ops?: unknown[];
    data?: unknown;
    meta?: unknown;
  }>({
    context,
    toolName: "mindmap_expand_node",
    invocationKind: "command",
    args: {
      documentId: payload.documentId,
      mindmapId: payload.mindmapId,
      targetUid: payload.targetUid,
      instruction: payload.instruction ?? "",
      ops: fixed,
      searchResults: searxResults.map((r) => ({
        title: r.title,
        url: r.url,
        snippet: r.snippet ?? "",
      })),
      reason: payload.instruction ?? "",
    },
    data: {
      data: baseData,
      source: "mindmap-expand-node",
    },
    mode: "result",
  });

  return NextResponse.json({
    ok: true,
    providerUsed: "online",
    applied: (result.result as any)?.applied ?? 0,
    errors: (result.result as any)?.errors ?? [],
    ops: (result.result as any)?.ops ?? fixed,
    data: (result.result as any)?.data ?? baseData,
    meta: {
      finishReason,
      searched: useSearx,
      searxCount: searxResults.length,
    },
  });
  */
}
