/**
 * OpenAI 兼容 API 格式构建工具
 *
 * 将 MetonaRequest 转换为 OpenAI /chat/completions 兼容的原生请求格式。
 * DeepSeek、Agnes AI 和 MiMo 共享此工具，各自 Adapter 只需处理 Provider 特有的差异参数。
 *
 * @see electron/harness/types/metona-request.ts — MetonaRequest 定义
 * @see apis/deepseek-api-docs-20260518.html
 * @see apis/agnes-ai-api-docs-20260625.html
 * @see apis/mimo-api-docs-20260715.html
 */

import type { MetonaRequest, MetonaToolDef } from '../../types';

/**
 * 构建 OpenAI 兼容的 messages 数组
 *
 * 处理：
 * - System Prompt 拼接（静态区 + 动态区 + 安全准则）
 * - 工具调用历史保留（reasoning_content + tool_calls）
 * - 工具结果注入（tool_call_id + content）
 *
 * 注意：图片（多模态）处理不属于此共享函数。
 * 各 Provider 对多模态的支持不同（DeepSeek 不支持，Agnes/Ollama 支持但格式各异），
 * 应在各自 Adapter 的 toNativeRequest 中处理。
 */
export function buildOpenAICompatibleMessages(
  request: MetonaRequest,
): Array<Record<string, unknown>> {
  const systemContent = [
    request.systemPrompt.roleDefinition,
    request.systemPrompt.outputConstraints,
    request.systemPrompt.safetyGuidelines,
    request.systemPrompt.dynamicReminders,
  ]
    .filter(Boolean)
    .join('\n\n');

  const nonSystemMessages = request.messages
    .filter((m) => m.role !== 'system')
    .map((m) => {
      // v0.3.0 修复: assistant 消息有 tool_calls 但 content 为空时，content 设为 null
      // DeepSeek/OpenAI API 要求有 tool_calls 的 assistant 消息 content 必须为 null 而非空字符串
      const msg: Record<string, unknown> = {
        role: m.role,
        content: m.content,
      };

      // 注意：图片（多模态）处理不在此共享函数中。
      // DeepSeek 不支持多模态，images 被静默丢弃是正确行为。
      // Agnes/MiMo 各自的 toNativeRequest 中有独立的 images 处理。
      // 审查修复: #27 曾在此添加 images 处理，但 DeepSeek 不支持多模态会导致 API 400，已撤销。

      // === Assistant 消息 ===
      if (m.role === 'assistant') {
        // 工具调用历史
        if (m.toolCalls?.length) {
          msg.tool_calls = m.toolCalls.map((tc) => ({
            id: tc.id,
            type: 'function',
            function: { name: tc.name, arguments: JSON.stringify(tc.args) },
          }));
          // 有 tool_calls 时 content 必须为 null（API 规范）
          if (!m.content) msg.content = null;
        }
        // 推理内容（无论是否有工具调用，都保留 reasoning_content）
        if (m.reasoningContent) {
          msg.reasoning_content = m.reasoningContent;
        }
      }

      // === 工具执行结果 ===
      if (m.role === 'tool' && m.toolResult) {
        msg.tool_call_id = m.toolResult.toolCallId;
        // CE-2 修复: 工具失败时 result 为 null，优先用 error 字段作为 content
        // 否则 LLM 看到 "null" 不知道失败原因，可能重复调用导致死循环
        msg.content = m.toolResult.error
          ? m.toolResult.error
          : (typeof m.toolResult.result === 'string'
            ? m.toolResult.result
            : JSON.stringify(m.toolResult.result));
        // #26 修复: 确保 tool 消息 content 不为 undefined
        // JSON.stringify(undefined) 返回 undefined（非字符串），会导致 content 字段在序列化后消失
        // OpenAI/DeepSeek/Agnes API 严格要求 tool 消息必须有 content 字段，缺失会返回 400
        if (msg.content === undefined) msg.content = '';
      }

      return msg;
    });

  return [{ role: 'system', content: systemContent }, ...nonSystemMessages];
}

/**
 * 构建 OpenAI 兼容的 tools 数组
 */
export function buildOpenAICompatibleTools(
  tools?: MetonaToolDef[],
): Array<Record<string, unknown>> | undefined {
  if (!tools?.length) return undefined;
  return tools.map((t) => ({
    type: 'function',
    function: {
      name: t.name,
      description: t.description,
      parameters: t.parameters,
    },
  }));
}
