import test from "node:test";
import assert from "node:assert/strict";

async function importLlmIntentModule() {
  const savedPromptUrl = process.env.PROMPT_SUPABASE_URL;
  const savedPromptKey = process.env.PROMPT_SUPABASE_SERVICE_ROLE_KEY;

  try {
    delete process.env.PROMPT_SUPABASE_URL;
    delete process.env.PROMPT_SUPABASE_SERVICE_ROLE_KEY;

    return await import(new URL(`../src/llm-intent.js?case=${Date.now()}-${Math.random()}`, import.meta.url).href);
  } finally {
    if (savedPromptUrl === undefined) {
      delete process.env.PROMPT_SUPABASE_URL;
    } else {
      process.env.PROMPT_SUPABASE_URL = savedPromptUrl;
    }

    if (savedPromptKey === undefined) {
      delete process.env.PROMPT_SUPABASE_SERVICE_ROLE_KEY;
    } else {
      process.env.PROMPT_SUPABASE_SERVICE_ROLE_KEY = savedPromptKey;
    }
  }
}

async function withEnv(overrides, fn) {
  const original = { ...process.env };
  process.env = { ...original, ...overrides };
  for (const [key, value] of Object.entries(overrides)) {
    if (value === undefined) {
      delete process.env[key];
    }
  }

  try {
    return await fn();
  } finally {
    process.env = original;
  }
}

test("buildSystemPrompt 在缺少 prompt store 配置时会报错", async () => {
  const intent = await importLlmIntentModule();
  await assert.rejects(() => intent.buildSystemPrompt(1), /PROMPT_SUPABASE_URL|PROMPT_SUPABASE_SERVICE_ROLE_KEY/);
});

test("buildGenericRoundSystemPrompt 会渲染 generic round 变量", async () => {
  const intent = await importLlmIntentModule();
  const prompt = intent.buildGenericRoundSystemPrompt(
    5,
    {
      name: "补充确认",
      templateText: "可以先打样吗？",
      passCondition: "商家确认支持打样",
    },
    "第 {{current_round}} 轮，本轮名称：{{round_name}}，话术：{{template_text}}，条件：{{pass_condition}}",
  );

  assert.match(prompt, /第 5 轮/);
  assert.match(prompt, /本轮名称：补充确认/);
  assert.match(prompt, /可以先打样吗？/);
  assert.match(prompt, /商家确认支持打样/);
});

test("resolveChatbotIntentModel 优先使用 CHATBOT_INTENT_LLM_MODEL 并默认 MiMo", async () => {
  await withEnv({
    CHATBOT_INTENT_LLM_MODEL: "chatbot-intent-model",
  }, async () => {
    const intent = await importLlmIntentModule();
    assert.equal(intent.resolveChatbotIntentModel(), "chatbot-intent-model");
  });

  await withEnv({
    CHATBOT_INTENT_LLM_MODEL: "  ",
  }, async () => {
    const intent = await importLlmIntentModule();
    assert.equal(intent.resolveChatbotIntentModel(), "mimo-v2.5");
  });

  await withEnv({
    CHATBOT_INTENT_LLM_MODEL: "",
  }, async () => {
    const intent = await importLlmIntentModule();
    assert.equal(intent.resolveChatbotIntentModel(), "mimo-v2.5");
  });
});

test("Prompt scope 使用客服意图阶段最终模型", async () => {
  await withEnv({
    PROMPT_PROVIDER: "prompt-provider",
    CHATBOT_INTENT_LLM_MODEL: "chatbot-intent-model",
  }, async () => {
    const intent = await importLlmIntentModule();
    assert.deepEqual(intent.getPromptScope(), {
      provider: "prompt-provider",
      model: "chatbot-intent-model",
    });
  });
});

test("callLLM 请求体使用 MiMo 客服意图阶段模型", async () => {
  await withEnv({
    CHATBOT_INTENT_LLM_PROVIDER: "mimo",
    CHATBOT_INTENT_LLM_MODEL: "mimo-v2.5",
    MIMO_LLM_API_KEY: "mimo-key",
    MIMO_LLM_BASE_URL: "https://mimo.example.test/v1/",
    DEEPSEEK_LLM_API_KEY: "deepseek-key",
    DEEPSEEK_LLM_BASE_URL: "https://deepseek.example.test",
  }, async () => {
    const intent = await importLlmIntentModule();
    const originalFetch = globalThis.fetch;
    let capturedUrl = "";
    let capturedBody = {};
    let capturedHeaders = {};
    globalThis.fetch = async (url, init) => {
      capturedUrl = String(url);
      capturedBody = JSON.parse(init.body);
      capturedHeaders = init.headers;
      return {
        ok: true,
        json: async () => ({
          choices: [{ message: { content: "{\"passed\":true}" } }],
        }),
      };
    };

    try {
      const raw = await intent.callLLM("system", "user");
      assert.equal(raw, "{\"passed\":true}");
      assert.equal(capturedUrl, "https://mimo.example.test/v1/chat/completions");
      assert.equal(capturedBody.model, "mimo-v2.5");
      assert.equal(capturedHeaders["api-key"], "mimo-key");
    } finally {
      globalThis.fetch = originalFetch;
    }
  });
});

test("callLLM 在 MiMo 失败时降级到 DeepSeek", async () => {
  await withEnv({
    CHATBOT_INTENT_LLM_PROVIDER: "mimo",
    CHATBOT_INTENT_LLM_MODEL: "mimo-v2.5",
    CHATBOT_INTENT_LLM_FALLBACK_PROVIDER: "deepseek",
    CHATBOT_INTENT_LLM_FALLBACK_MODEL: "deepseek-v4-flash",
    MIMO_LLM_API_KEY: "mimo-key",
    MIMO_LLM_BASE_URL: "https://mimo.example.test/v1",
    DEEPSEEK_LLM_API_KEY: "deepseek-key",
    DEEPSEEK_LLM_BASE_URL: "https://deepseek.example.test",
  }, async () => {
    const intent = await importLlmIntentModule();
    const originalFetch = globalThis.fetch;
    const urls = [];
    globalThis.fetch = async (url, init) => {
      urls.push({ url: String(url), body: JSON.parse(init.body), headers: init.headers });
      if (String(url).includes("mimo.example.test")) {
        return { ok: false, text: async () => "rate limit" };
      }
      return {
        ok: true,
        json: async () => ({
          choices: [{ message: { content: "{\"passed\":true,\"fallback\":true}" } }],
        }),
      };
    };

    try {
      const raw = await intent.callLLM("system", "user");
      assert.equal(raw, "{\"passed\":true,\"fallback\":true}");
      assert.equal(urls[0].url, "https://mimo.example.test/v1/chat/completions");
      assert.equal(urls[1].url, "https://deepseek.example.test/chat/completions");
      assert.equal(urls[1].body.model, "deepseek-v4-flash");
      assert.equal(urls[1].headers.Authorization, "Bearer deepseek-key");
    } finally {
      globalThis.fetch = originalFetch;
    }
  });
});

test("callLLM 在 LOG_LEVEL=debug 时打印结构化摘要且不泄露 API Key", async () => {
  await withEnv({
    LOG_LEVEL: "debug",
    CHATBOT_INTENT_LLM_PROVIDER: "mimo",
    CHATBOT_INTENT_LLM_MODEL: "mimo-v2.5",
    MIMO_LLM_API_KEY: "test-key",
    MIMO_LLM_BASE_URL: "https://mimo.example.test/v1/",
  }, async () => {
    const intent = await importLlmIntentModule();
    const originalFetch = globalThis.fetch;
    const originalDebug = console.debug;
    const debugLines = [];
    globalThis.fetch = async () => ({
      ok: true,
      json: async () => ({
        choices: [{ finish_reason: "stop", message: { content: "{\"passed\":true}" } }],
        usage: { prompt_tokens: 3, completion_tokens: 2 },
      }),
    });
    console.debug = (...args) => {
      debugLines.push(args.map(String).join(" "));
    };

    try {
      await intent.callLLM("system prompt", "user message");
      const output = debugLines.join("\n");
      assert.match(output, /"event":"llm\.request"/);
      assert.match(output, /"event":"llm\.response"/);
      assert.match(output, /"stage":"chatbot_intent"/);
      assert.match(output, /"textPreview":"system prompt"/);
      assert.doesNotMatch(output, /test-key/);
    } finally {
      globalThis.fetch = originalFetch;
      console.debug = originalDebug;
    }
  });
});
