'use strict';

let geminiToolCallSeq = 0;
let openAIToolCallSeq = 0;

// ============================================================
// Tool definition converters
// ============================================================

/**
 * Convert Anthropic tool definitions to OpenAI function-calling format.
 * @param {Array} tools - Anthropic-format tools ({ name, description, input_schema })
 * @returns {Array|undefined}
 */
function toOpenAI(tools) {
  if (!tools) return undefined;
  return tools.map((t) => ({
    type: 'function',
    function: {
      name: t.name,
      description: t.description,
      parameters: t.input_schema,
    },
  }));
}

/**
 * Convert Anthropic tool definitions to Gemini format.
 * @param {Array} tools
 * @returns {Array|undefined}
 */
function toGemini(tools) {
  if (!tools) return undefined;
  if (tools.length === 0) return [];
  return [
    {
      functionDeclarations: tools.map((t) => ({
        name: t.name,
        description: t.description,
        parameters: t.input_schema,
      })),
    },
  ];
}

/**
 * Identity pass-through for Anthropic tools.
 * @param {Array} tools
 * @returns {Array|undefined}
 */
function toAnthropic(tools) {
  return tools;
}

// ============================================================
// Message converters
// ============================================================

/**
 * Convert Anthropic-format messages to OpenAI chat format.
 * Handles: simple string content, tool_use blocks, tool_result blocks.
 * @param {Array} messages
 * @returns {Array}
 */
function messagesToOpenAI(messages) {
  const out = [];
  const pendingToolCallIds = [];

  for (const msg of messages) {
    // Simple string content — pass through
    if (typeof msg.content === 'string') {
      const converted = { role: msg.role, content: msg.content };
      if (msg.role === 'assistant' && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
        converted.tool_calls = normalizeOpenAIToolCalls(msg.tool_calls, pendingToolCallIds);
      }
      if (msg.role === 'tool') {
        converted.tool_call_id = consumeToolCallId(msg.tool_call_id, pendingToolCallIds);
      }
      out.push(converted);
      continue;
    }

    // Array content blocks
    if (!Array.isArray(msg.content)) {
      out.push({ role: msg.role, content: msg.content });
      continue;
    }

    // Check if this is a tool_result message (user role with tool_result blocks)
    const toolResults = msg.content.filter((b) => b.type === 'tool_result');
    if (toolResults.length > 0) {
      for (const tr of toolResults) {
        out.push({
          role: 'tool',
          tool_call_id: consumeToolCallId(tr.tool_use_id || tr.id || tr.toolCallId, pendingToolCallIds),
          content: typeof tr.content === 'string' ? tr.content : JSON.stringify(tr.content),
        });
      }
      continue;
    }

    // Assistant message with text + tool_use blocks
    const textParts = msg.content.filter((b) => b.type === 'text');
    const reasoningParts = msg.content.filter((b) => b.type === 'reasoning');
    const toolUses = msg.content.filter((b) => b.type === 'tool_use');
    const images = msg.content.filter((b) => b.type === 'image');
    const audios = msg.content.filter((b) => b.type === 'audio');

    const converted = { role: msg.role };

    if (msg.role === 'user' && (images.length > 0 || audios.length > 0)) {
      // OpenAI multimodal user message: array of typed parts. Convert our
      // internal Anthropic-shaped blocks into OpenAI's native shapes.
      //   image → { type:'image_url',  image_url:{url:'data:<mt>;base64,<d>'} }
      //   audio → { type:'input_audio',input_audio:{data:<base64>, format:'mp3'|'wav'|...} }
      const openAIParts = [];
      for (const t of textParts) openAIParts.push({ type: 'text', text: t.text });
      for (const im of images) {
        const src = im.source || {};
        if (src.type === 'base64' && src.media_type && src.data) {
          openAIParts.push({
            type: 'image_url',
            image_url: { url: `data:${src.media_type};base64,${src.data}` },
          });
        } else if (src.type === 'url' && src.url) {
          openAIParts.push({ type: 'image_url', image_url: { url: src.url } });
        }
      }
      for (const au of audios) {
        const src = au.source || {};
        if (src.type === 'base64' && src.data) {
          // OpenAI input_audio expects {data, format}. Format derives
          // from media_type ('audio/mp3' → 'mp3'); attachments.js sets
          // a `format` hint on the block when known. mp3/mpeg → 'mp3',
          // wav → 'wav'. Fallback 'mp3' for unknown formats.
          let fmt = au.format || (src.media_type ? src.media_type.split('/')[1] : 'mp3');
          if (fmt === 'mpeg') fmt = 'mp3';
          if (fmt === 'mp4') fmt = 'm4a';
          openAIParts.push({
            type: 'input_audio',
            input_audio: { data: src.data, format: fmt },
          });
        }
      }
      converted.content = openAIParts;
    } else {
      converted.content = textParts.map((b) => b.text).join('\n') || null;
    }

    if (toolUses.length > 0) {
      converted.tool_calls = toolUses.map((tu, index) => {
        const id = tu.id || tu.tool_use_id || tu.toolCallId || synthesizeOpenAIToolCallId(index);
        pendingToolCallIds.push(id);
        return {
          id,
          type: 'function',
          function: {
            name: tu.name,
            arguments: JSON.stringify(tu.input ?? {}),
          },
        };
      });
    }

    if (reasoningParts.length > 0) {
      converted.reasoning_content = reasoningParts.map((b) => b.text || b.content || '').join('\n');
    }

    out.push(converted);
  }
  return out;
}

// ============================================================
// Response normalizers
// ============================================================

/**
 * Normalize an Anthropic API response to a common shape.
 */
function responseFromAnthropic(resp) {
  const textParts = (resp.content || []).filter((b) => b.type === 'text');
  const toolUses = (resp.content || []).filter((b) => b.type === 'tool_use');

  return {
    content: textParts.map((b) => b.text).join('\n') || null,
    toolCalls: toolUses.map((tu) => ({
      id: tu.id,
      name: tu.name,
      input: tu.input,
    })),
    stopReason: resp.stop_reason,
    usage: resp.usage
      ? { input: resp.usage.input_tokens, output: resp.usage.output_tokens }
      : undefined,
  };
}

/**
 * Normalize an OpenAI API response to a common shape.
 */
function responseFromOpenAI(resp) {
  const choice = resp.choices?.[0];
  const msg = choice?.message || {};

  return {
    content: msg.content || null,
    reasoningContent: msg.reasoning_content || msg.reasoning || msg.thinking || null,
    toolCalls: (msg.tool_calls || []).map((tc, index) => ({
      id: tc.id || synthesizeOpenAIToolCallId(index),
      name: tc.function.name,
      input: safeJsonParse(tc.function.arguments),
    })),
    stopReason: choice?.finish_reason,
    usage: resp.usage
      ? { input: resp.usage.prompt_tokens, output: resp.usage.completion_tokens }
      : undefined,
  };
}

/**
 * Normalize a Google Gemini API response to a common shape.
 */
function responseFromGemini(resp) {
  const candidate = resp.candidates?.[0];
  const parts = candidate?.content?.parts || [];

  const textParts = parts.filter((p) => p.text);
  const fnCalls = parts.filter((p) => p.functionCall);

  return {
    content: textParts.map((p) => p.text).join('\n') || null,
    toolCalls: fnCalls.map((p) => ({
      id: `gemini_call_${++geminiToolCallSeq}`,
      name: p.functionCall.name,
      input: p.functionCall.args,
    })),
    stopReason: candidate?.finishReason || null,
    usage: resp.usageMetadata
      ? {
          input: resp.usageMetadata.promptTokenCount,
          output: resp.usageMetadata.candidatesTokenCount,
        }
      : undefined,
  };
}

// ============================================================
// Helpers
// ============================================================

function safeJsonParse(str) {
  try {
    return JSON.parse(str);
  } catch {
    return str;
  }
}

function synthesizeOpenAIToolCallId(index = 0) {
  openAIToolCallSeq += 1;
  return `call_walle_${openAIToolCallSeq}_${index}`;
}

function normalizeOpenAIToolCalls(toolCalls = [], pendingToolCallIds = []) {
  return toolCalls.map((tc, index) => {
    const id = tc.id || synthesizeOpenAIToolCallId(index);
    pendingToolCallIds.push(id);
    return { ...tc, id };
  });
}

function consumeToolCallId(explicitId, pendingToolCallIds = []) {
  if (explicitId) {
    const pendingIndex = pendingToolCallIds.indexOf(explicitId);
    if (pendingIndex >= 0) pendingToolCallIds.splice(pendingIndex, 1);
    return explicitId;
  }
  return pendingToolCallIds.shift() || synthesizeOpenAIToolCallId(0);
}

module.exports = {
  toOpenAI,
  toGemini,
  toAnthropic,
  messagesToOpenAI,
  responseFromAnthropic,
  responseFromOpenAI,
  responseFromGemini,
};
