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

const {
  CLAUDE_OAUTH_TOOL_PREFIX,
  normalizeContentToString,
  openaiToClaudeRequest,
  openaiToClaudeRequestForAntigravity,
  stripEmptyTextBlocks,
} = await import("../../open-sse/translator/request/openai-to-claude.ts");
const { CLAUDE_SYSTEM_PROMPT } = await import("../../open-sse/config/constants.ts");
const { DEFAULT_THINKING_CLAUDE_SIGNATURE } =
  await import("../../open-sse/config/defaultThinkingSignature.ts");
const { getModelsByProviderId } = await import("../../open-sse/config/providerModels.ts");

function getClaudeEffortFixtures() {
  const claudeModels = getModelsByProviderId("claude");
  const xhighModel = claudeModels.find((model) => model.supportsXHighEffort === true);
  const standardModel = claudeModels.find((model) => model.supportsXHighEffort === false);
  assert.ok(xhighModel, "expected at least one Claude model with xhigh support");
  assert.ok(standardModel, "expected at least one Claude model without xhigh support");
  return { xhighModel, standardModel };
}

test("OpenAI -> Claude helpers normalize array content and strip empty nested text blocks", () => {
  const normalized = normalizeContentToString([
    { type: "text", text: "Line 1" },
    { type: "image_url", image_url: { url: "https://example.com/ignored.png" } },
    { type: "text", text: "Line 2" },
  ]);

  assert.equal(normalized, "Line 1\nLine 2");

  const stripped = stripEmptyTextBlocks([
    { type: "text", text: "" },
    { type: "text", text: "keep" },
    {
      type: "tool_result",
      content: [
        { type: "text", text: "" },
        { type: "text", text: "nested" },
      ],
    },
  ]);

  assert.deepEqual(stripped, [
    { type: "text", text: "keep" },
    {
      type: "tool_result",
      content: [{ type: "text", text: "nested" }],
    },
  ]);
});

test("OpenAI -> Claude maps system messages, parameters and assistant cache markers", () => {
  const result = openaiToClaudeRequest(
    "claude-4-sonnet",
    {
      messages: [
        { role: "system", content: "Rule A" },
        {
          role: "system",
          content: [
            { type: "text", text: "Rule B" },
            { type: "image_url", image_url: { url: "data:image/png;base64,abc" } },
            { type: "text", text: "Rule C" },
          ],
        },
        { role: "user", content: "Hello" },
        { role: "assistant", content: "Hi there" },
      ],
      max_completion_tokens: 33,
      temperature: 0.25,
      top_p: 0.8,
      stop: ["DONE"],
    },
    true
  );

  assert.equal(result.model, "claude-4-sonnet");
  assert.equal(result.stream, true);
  assert.equal(result.max_tokens, 33);
  assert.equal(result.temperature, 0.25);
  assert.equal(result.top_p, 0.8);
  assert.deepEqual(result.stop_sequences, ["DONE"]);
  assert.equal(result.system[0].text, CLAUDE_SYSTEM_PROMPT);
  assert.equal(result.system[1].text, "Rule A\nRule B\nRule C");
  assert.equal(result.messages[0].role, "user");
  assert.deepEqual(result.messages[0].content, [{ type: "text", text: "Hello" }]);
  assert.equal(result.messages[1].role, "assistant");
  assert.equal(result.messages[1].content[0].text, "Hi there");
  assert.deepEqual(result.messages[1].content[0].cache_control, { type: "ephemeral" });
});

test("OpenAI -> Claude converts multimodal content, tool declarations, tool calls and tool results", () => {
  const result = openaiToClaudeRequest(
    "claude-4-sonnet",
    {
      messages: [
        {
          role: "user",
          content: [
            { type: "text", text: "Inspect this" },
            { type: "image_url", image_url: { url: "data:image/png;base64,abc" } },
            { type: "image_url", image_url: { url: "https://example.com/cat.png" } },
          ],
        },
        {
          role: "assistant",
          reasoning_content: "Need a tool",
          content: [{ type: "text", text: "Calling tool" }],
          tool_calls: [
            {
              id: "call_weather",
              type: "function",
              function: {
                name: "weather.get",
                arguments: '{"city":"Tokyo"}',
              },
            },
            {
              id: "call_skip",
              type: "function",
              function: {
                name: "",
                arguments: "{}",
              },
            },
          ],
        },
        {
          role: "tool",
          tool_call_id: "call_weather",
          content: [
            { type: "text", text: "" },
            { type: "text", text: "20C" },
          ],
        },
      ],
      tools: [
        {
          type: "function",
          function: {
            name: "weather.get",
            description: "Read weather data",
            parameters: { type: "object" },
          },
        },
        {
          type: "function",
          function: {
            name: "",
            description: "skip me",
            parameters: { type: "object" },
          },
        },
      ],
    },
    false
  );

  assert.equal(result.tools.length, 1);
  assert.equal(result.tools[0].name, `${CLAUDE_OAUTH_TOOL_PREFIX}weather.get`);
  assert.deepEqual(result.tools[0].input_schema, { type: "object", properties: {} });
  assert.deepEqual(result.tools[0].cache_control, { type: "ephemeral", ttl: "1h" });
  assert.equal(result._toolNameMap.get(`${CLAUDE_OAUTH_TOOL_PREFIX}weather.get`), "weather.get");

  assert.equal(result.messages[0].role, "user");
  assert.equal(result.messages[0].content.length, 3);
  assert.deepEqual(result.messages[0].content[1], {
    type: "image",
    source: { type: "base64", media_type: "image/png", data: "abc" },
  });
  assert.deepEqual(result.messages[0].content[2], {
    type: "image",
    source: { type: "url", url: "https://example.com/cat.png" },
  });

  const assistantMessage = result.messages.find((message) => message.role === "assistant");
  assert.ok(assistantMessage, "expected an assistant message");
  assert.equal(assistantMessage.content[0].type, "thinking");
  assert.equal(assistantMessage.content[0].thinking, "Need a tool");
  assert.equal(assistantMessage.content[0].signature, DEFAULT_THINKING_CLAUDE_SIGNATURE);
  assert.equal(assistantMessage.content[1].text, "Calling tool");
  assert.equal(assistantMessage.content[2].type, "tool_use");
  assert.equal(assistantMessage.content[2].name, `${CLAUDE_OAUTH_TOOL_PREFIX}weather.get`);
  assert.deepEqual(assistantMessage.content[2].input, { city: "Tokyo" });
  assert.deepEqual(assistantMessage.content[2].cache_control, { type: "ephemeral" });

  const toolResultMessage = result.messages.find(
    (message) =>
      message.role === "user" && message.content.some((block) => block.type === "tool_result")
  );
  assert.ok(toolResultMessage, "expected a translated tool_result message");
  assert.deepEqual(toolResultMessage.content[0], {
    type: "tool_result",
    tool_use_id: "call_weather",
    content: [{ type: "text", text: "20C" }],
  });
});

test("OpenAI -> Claude maps tool_choice and injects response_format instructions into system", () => {
  const schemaResult = openaiToClaudeRequest(
    "claude-4-sonnet",
    {
      messages: [{ role: "user", content: "Return JSON" }],
      tool_choice: "required",
      response_format: {
        type: "json_schema",
        json_schema: {
          schema: {
            type: "object",
            properties: { answer: { type: "string" } },
            required: ["answer"],
          },
        },
      },
    },
    false
  );

  assert.deepEqual(schemaResult.tool_choice, { type: "any" });
  assert.match(schemaResult.system[1].text, /strictly follows this JSON schema/i);
  assert.match(schemaResult.system[1].text, /"answer"/);

  const jsonObjectResult = openaiToClaudeRequest(
    "claude-4-sonnet",
    {
      messages: [{ role: "user", content: "Return JSON" }],
      tool_choice: { function: { name: "emit_json" } },
      response_format: { type: "json_object" },
    },
    false
  );

  assert.deepEqual(jsonObjectResult.tool_choice, { type: "tool", name: "emit_json" });
  assert.match(jsonObjectResult.system[1].text, /Respond ONLY with a JSON object/i);
});

test("OpenAI -> Claude turns reasoning settings into thinking budgets and expands max tokens", () => {
  const effortResult = openaiToClaudeRequest(
    "claude-4-sonnet",
    {
      messages: [{ role: "user", content: "Think harder" }],
      max_tokens: 10,
      reasoning_effort: "low",
    },
    false
  );

  assert.deepEqual(effortResult.thinking, { type: "enabled", budget_tokens: 1024 });
  assert.equal(effortResult.max_tokens, 9216);

  const explicitThinkingResult = openaiToClaudeRequest(
    "claude-4-sonnet",
    {
      messages: [{ role: "user", content: "Think harder" }],
      max_completion_tokens: 1000,
      thinking: { type: "enabled", budget_tokens: 2000, max_tokens: 3000 },
    },
    false
  );

  assert.deepEqual(explicitThinkingResult.thinking, {
    type: "enabled",
    budget_tokens: 2000,
    max_tokens: 3000,
  });
  assert.equal(explicitThinkingResult.max_tokens, 10192);
});

test("OpenAI -> Claude preserves xhigh only for Claude models that expose it", () => {
  const { xhighModel, standardModel } = getClaudeEffortFixtures();
  const preserved = openaiToClaudeRequest(
    xhighModel.id,
    {
      messages: [{ role: "user", content: "Think harder" }],
      reasoning_effort: "xhigh",
    },
    false
  );
  const downgraded = openaiToClaudeRequest(
    standardModel.id,
    {
      messages: [{ role: "user", content: "Think harder" }],
      max_tokens: 10,
      reasoning_effort: "xhigh",
    },
    false
  );

  assert.deepEqual(preserved.thinking, { type: "adaptive" });
  assert.deepEqual(preserved.output_config, { effort: "xhigh" });
  assert.deepEqual(downgraded.thinking, { type: "enabled", budget_tokens: 131072 });
  assert.equal(downgraded.output_config, undefined);
  assert.equal(downgraded.max_tokens, 139264);
});

test("OpenAI -> Claude can disable OAuth prefixes and Antigravity strips Claude-only prompting", () => {
  const baseBody = {
    messages: [
      { role: "system", content: "User rules" },
      { role: "user", content: "Run a tool" },
      {
        role: "assistant",
        tool_calls: [
          {
            id: "call_1",
            type: "function",
            function: { name: "read_file", arguments: "{}" },
          },
        ],
      },
    ],
    tools: [
      {
        type: "function",
        function: {
          name: "read_file",
          description: "Read a file",
          parameters: { type: "object", properties: {} },
        },
      },
    ],
  };

  const noPrefix = openaiToClaudeRequest(
    "claude-4-sonnet",
    { ...baseBody, _disableToolPrefix: true },
    false
  );

  assert.equal(noPrefix.tools[0].name, "read_file");
  assert.equal(noPrefix._toolNameMap, undefined);
  assert.equal(
    noPrefix.messages[1].content.find((block) => block.type === "tool_use").name,
    "read_file"
  );

  const antigravity = openaiToClaudeRequestForAntigravity("claude-4-sonnet", baseBody, false);
  assert.equal(
    antigravity.system.some((block) => String(block.text).includes("Claude Code")),
    false
  );
  assert.equal(antigravity.system[0].text, "User rules");
  assert.equal(antigravity.tools[0].name, "read_file");
  assert.equal(
    antigravity.messages[1].content.find((block) => block.type === "tool_use").name,
    "read_file"
  );
});
