import { v4 as uuidv4 } from 'uuid';
import { MODEL_PROTOCOL_PREFIX, getProtocolPrefix } from './common.js';
import {
  streamStateManager,
  generateResponseCreated,
  generateResponseInProgress,
  generateOutputItemAdded,
  generateContentPartAdded,
  generateOutputTextDelta,
  generateOutputTextDone,
  generateContentPartDone,
  generateOutputItemDone,
  generateResponseCompleted
} from './openai/openai-responses-core.mjs';

// =============================================================================
// 常量和辅助函数定义
// =============================================================================

// 定义默认常量
const DEFAULT_MAX_TOKENS = 8192;
const DEFAULT_GEMINI_MAX_TOKENS = 65535;
const DEFAULT_TEMPERATURE = 1;
const DEFAULT_TOP_P = 0.95;

// 辅助函数：判断值是否为 undefined 或 0，并返回默认值
function checkAndAssignOrDefault(value, defaultValue) {
    if (value !== undefined && value !== 0) {
        return value;
    }
    return defaultValue;
}

/**
 * 映射结束原因
 * @param {string} reason - 结束原因
 * @param {string} sourceFormat - 源格式
 * @param {string} targetFormat - 目标格式
 * @returns {string} 映射后的结束原因
 */
function _mapFinishReason(reason, sourceFormat, targetFormat) {
    const reasonMappings = {
        openai: {
            anthropic: {
                stop: "end_turn",
                length: "max_tokens",
                content_filter: "stop_sequence",
                tool_calls: "tool_use"
            }
        },
        gemini: {
            anthropic: {
                // 旧版本大写格式
                STOP: "end_turn",
                MAX_TOKENS: "max_tokens",
                SAFETY: "stop_sequence",
                RECITATION: "stop_sequence",
                // 新版本小写格式（v1beta/v1 API）
                stop: "end_turn",
                length: "max_tokens",
                safety: "stop_sequence",
                recitation: "stop_sequence",
                other: "end_turn"
            }
        }
    };

    try {
        return reasonMappings[sourceFormat][targetFormat][reason] || "end_turn";
    } catch (e) {
        return "end_turn";
    }
}

/**
 * 递归清理Gemini不支持的JSON Schema属性
 * @param {Object} schema - JSON Schema
 * @returns {Object} 清理后的JSON Schema
 */
function _cleanJsonSchemaProperties(schema) {
    if (!schema || typeof schema !== 'object') {
        return schema;
    }

    // 移除所有非标准属性
    const sanitized = {};
    for (const [key, value] of Object.entries(schema)) {
        if (["type", "description", "properties", "required", "enum", "items"].includes(key)) {
            sanitized[key] = value;
        }
    }

    if (sanitized.properties && typeof sanitized.properties === 'object') {
        const cleanProperties = {};
        for (const [propName, propSchema] of Object.entries(sanitized.properties)) {
            cleanProperties[propName] = _cleanJsonSchemaProperties(propSchema);
        }
        sanitized.properties = cleanProperties;
    }

    if (sanitized.items) {
        sanitized.items = _cleanJsonSchemaProperties(sanitized.items);
    }

    return sanitized;
}

/**
 * 根据budget_tokens智能判断OpenAI reasoning_effort等级
 * @param {number|null} budgetTokens - Anthropic thinking的budget_tokens值
 * @returns {string} OpenAI reasoning_effort等级 ("low", "medium", "high")
 */
function _determineReasoningEffortFromBudget(budgetTokens) {
    // 如果没有提供budget_tokens，默认为high
    if (budgetTokens === null || budgetTokens === undefined) {
        console.info("No budget_tokens provided, defaulting to reasoning_effort='high'");
        return "high";
    }

    // 使用固定阈值替代环境变量
    const LOW_THRESHOLD = 50;    // 低推理努力的阈值
    const HIGH_THRESHOLD = 200;  // 高推理努力的阈值

    console.debug(`Threshold configuration: low <= ${LOW_THRESHOLD}, medium <= ${HIGH_THRESHOLD}, high > ${HIGH_THRESHOLD}`);

    let effort;
    if (budgetTokens <= LOW_THRESHOLD) {
        effort = "low";
    } else if (budgetTokens <= HIGH_THRESHOLD) {
        effort = "medium";
    } else {
        effort = "high";
    }

    console.info(`🎯 Budget tokens ${budgetTokens} -> reasoning_effort '${effort}' (thresholds: low<=${LOW_THRESHOLD}, high<=${HIGH_THRESHOLD})`);
    return effort;
}

// 全局工具状态管理器
class ToolStateManager {
    constructor() {
        if (ToolStateManager.instance) {
            return ToolStateManager.instance;
        }
        ToolStateManager.instance = this;
        this._toolMappings = {};
        return this;
    }

    // 存储工具名到ID的映射
    storeToolMapping(funcName, toolId) {
        this._toolMappings[funcName] = toolId;
    }

    // 根据工具名获取ID
    getToolId(funcName) {
        return this._toolMappings[funcName] || null;
    }

    // 清除所有映射
    clearMappings() {
        this._toolMappings = {};
    }
}

// 全局工具状态管理器实例
const toolStateManager = new ToolStateManager();

// =============================================================================
// 主转换函数
// =============================================================================

/**
 * Generic data conversion function.
 * @param {object} data - The data to convert (request body or response).
 * @param {string} type - The type of conversion: 'request', 'response', 'streamChunk', 'modelList'.
 * @param {string} fromProvider - The source model provider (e.g., MODEL_PROVIDER.GEMINI_CLI).
 * @param {string} toProvider - The target model provider (e.g., MODEL_PROVIDER.OPENAI_CUSTOM).
 * @param {string} [model] - Optional model name for response conversions.
 * @returns {object} The converted data.
 * @throws {Error} If no suitable conversion function is found.
 */
export function convertData(data, type, fromProvider, toProvider, model) {
    // Define a map of conversion functions using protocol prefixes
    const conversionMap = {
        request: {
            [MODEL_PROTOCOL_PREFIX.OPENAI]: { // to OpenAI protocol
                [MODEL_PROTOCOL_PREFIX.GEMINI]: toOpenAIRequestFromGemini, // from Gemini protocol
                [MODEL_PROTOCOL_PREFIX.CLAUDE]: toOpenAIRequestFromClaude, // from Claude protocol
            },
            [MODEL_PROTOCOL_PREFIX.CLAUDE]: { // to Claude protocol
                [MODEL_PROTOCOL_PREFIX.OPENAI]: toClaudeRequestFromOpenAI, // from OpenAI protocol
                [MODEL_PROTOCOL_PREFIX.OPENAI_RESPONSES]: toClaudeRequestFromOpenAIResponses, // from OpenAI protocol (Responses format)
            },
            [MODEL_PROTOCOL_PREFIX.GEMINI]: { // to Gemini protocol
                [MODEL_PROTOCOL_PREFIX.OPENAI]: toGeminiRequestFromOpenAI, // from OpenAI protocol
                [MODEL_PROTOCOL_PREFIX.CLAUDE]: toGeminiRequestFromClaude, // from Claude protocol
                [MODEL_PROTOCOL_PREFIX.OPENAI_RESPONSES]: toGeminiRequestFromOpenAIResponses, // from OpenAI protocol (Responses format)
            },
        },
        response: {
            [MODEL_PROTOCOL_PREFIX.OPENAI]: { // to OpenAI protocol
                [MODEL_PROTOCOL_PREFIX.GEMINI]: toOpenAIChatCompletionFromGemini, // from Gemini protocol
                [MODEL_PROTOCOL_PREFIX.CLAUDE]: toOpenAIChatCompletionFromClaude, // from Claude protocol
            },
            [MODEL_PROTOCOL_PREFIX.CLAUDE]: { // to Claude protocol
                [MODEL_PROTOCOL_PREFIX.GEMINI]: toClaudeChatCompletionFromGemini, // from Gemini protocol
                [MODEL_PROTOCOL_PREFIX.OPENAI]: toClaudeChatCompletionFromOpenAI, // from OpenAI protocol
            },
            [MODEL_PROTOCOL_PREFIX.OPENAI_RESPONSES]: { // to OpenAI protocol (Responses format)
                [MODEL_PROTOCOL_PREFIX.GEMINI]: toOpenAIResponsesFromGemini, // from Gemini protocol
                [MODEL_PROTOCOL_PREFIX.CLAUDE]: toOpenAIResponsesFromClaude, // from Claude protocol
            },
        },
        streamChunk: {
            [MODEL_PROTOCOL_PREFIX.OPENAI]: { // to OpenAI protocol
                [MODEL_PROTOCOL_PREFIX.GEMINI]: toOpenAIStreamChunkFromGemini, // from Gemini protocol
                [MODEL_PROTOCOL_PREFIX.CLAUDE]: toOpenAIStreamChunkFromClaude, // from Claude protocol
            },
            [MODEL_PROTOCOL_PREFIX.CLAUDE]: { // to Claude protocol
                [MODEL_PROTOCOL_PREFIX.GEMINI]: toClaudeStreamChunkFromGemini, // from Gemini protocol
                [MODEL_PROTOCOL_PREFIX.OPENAI]: toClaudeStreamChunkFromOpenAI, // from OpenAI protocol
            },
            [MODEL_PROTOCOL_PREFIX.OPENAI_RESPONSES]: { // to OpenAI protocol (Responses format)
                [MODEL_PROTOCOL_PREFIX.GEMINI]: toOpenAIResponsesStreamChunkFromGemini, // from Gemini protocol
                [MODEL_PROTOCOL_PREFIX.CLAUDE]: toOpenAIResponsesStreamChunkFromClaude, // from Claude protocol
            },
        },
        modelList: {
            [MODEL_PROTOCOL_PREFIX.OPENAI]: { // to OpenAI protocol
                [MODEL_PROTOCOL_PREFIX.GEMINI]: toOpenAIModelListFromGemini, // from Gemini protocol
                [MODEL_PROTOCOL_PREFIX.CLAUDE]: toOpenAIModelListFromClaude, // from Claude protocol
            },
            [MODEL_PROTOCOL_PREFIX.CLAUDE]: { // to Claude protocol
                [MODEL_PROTOCOL_PREFIX.GEMINI]: toClaudeModelListFromGemini, // from Gemini protocol
                [MODEL_PROTOCOL_PREFIX.OPENAI]: toClaudeModelListFromOpenAI, // from OpenAI protocol
            },
        }
    };

    const targetConversions = conversionMap[type];
    if (!targetConversions) {
        throw new Error(`Unsupported conversion type: ${type}`);
    }

    const toConversions = targetConversions[getProtocolPrefix(toProvider)];
    if (!toConversions) {
        throw new Error(`No conversions defined for target protocol: ${getProtocolPrefix(toProvider)} for type: ${type}`);
    }

    const conversionFunction = toConversions[getProtocolPrefix(fromProvider)];
    if (!conversionFunction) {
        throw new Error(`No conversion function found from ${getProtocolPrefix(fromProvider)} to ${toProvider} for type: ${type}`);
    }

    console.log(conversionFunction);
    if (type === 'response' || type === 'streamChunk' || type === 'modelList') {
        return conversionFunction(data, model);
    } else {
        return conversionFunction(data);
    }
}

// =============================================================================
// OpenAI 相关转换函数
// =============================================================================

/**
 * Converts a Gemini API request body to an OpenAI chat completion request body.
 * Handles system instructions and role mapping with multimodal support.
 * @param {Object} geminiRequest - The request body from the Gemini API.
 * @returns {Object} The formatted request body for the OpenAI API.
 */
export function toOpenAIRequestFromGemini(geminiRequest) {
    const openaiRequest = {
        messages: [],
        model: geminiRequest.model, // Default model if not specified in Gemini request
        max_tokens: checkAndAssignOrDefault(geminiRequest.max_tokens, DEFAULT_MAX_TOKENS),
        temperature: checkAndAssignOrDefault(geminiRequest.temperature, DEFAULT_TEMPERATURE),
        top_p: checkAndAssignOrDefault(geminiRequest.top_p, DEFAULT_TOP_P),
    };

    // Process system instruction
    if (geminiRequest.systemInstruction && Array.isArray(geminiRequest.systemInstruction.parts)) {
        const systemContent = processGeminiPartsToOpenAIContent(geminiRequest.systemInstruction.parts);
        if (systemContent) {
            openaiRequest.messages.push({
                role: 'system',
                content: systemContent
            });
        }
    }

    // Process contents
    if (geminiRequest.contents && Array.isArray(geminiRequest.contents)) {
        geminiRequest.contents.forEach(content => {
            if (content && Array.isArray(content.parts)) {
                const openaiContent = processGeminiPartsToOpenAIContent(content.parts);
                if (openaiContent && openaiContent.length > 0) {
                    const openaiRole = content.role === 'model' ? 'assistant' : content.role;
                    openaiRequest.messages.push({
                        role: openaiRole,
                        content: openaiContent
                    });
                }
            }
        });
    }

    return openaiRequest;
}


/**
 * Processes Gemini parts to OpenAI content format with multimodal support.
 * @param {Array} parts - Array of Gemini parts.
 * @returns {Array|string} OpenAI content format.
 */
function processGeminiPartsToOpenAIContent(parts) {
    if (!parts || !Array.isArray(parts)) return '';
    
    const contentArray = [];
    
    parts.forEach(part => {
        if (!part) return;
        
        // Handle text content
        if (typeof part.text === 'string') {
            contentArray.push({
                type: 'text',
                text: part.text
            });
        }
        
        // Handle inline data (images, audio)
        if (part.inlineData) {
            const { mimeType, data } = part.inlineData;
            if (mimeType && data) {
                contentArray.push({
                    type: 'image_url',
                    image_url: {
                        url: `data:${mimeType};base64,${data}`
                    }
                });
            }
        }
        
        // Handle file data
        if (part.fileData) {
            const { mimeType, fileUri } = part.fileData;
            if (mimeType && fileUri) {
                // For file URIs, we need to determine if it's an image or audio
                if (mimeType.startsWith('image/')) {
                    contentArray.push({
                        type: 'image_url',
                        image_url: {
                            url: fileUri
                        }
                    });
                } else if (mimeType.startsWith('audio/')) {
                    // For audio, we'll use a placeholder or handle as text description
                    contentArray.push({
                        type: 'text',
                        text: `[Audio file: ${fileUri}]`
                    });
                }
            }
        }
    });
    
    // Return as array for multimodal, or string for simple text
    return contentArray.length === 1 && contentArray[0].type === 'text'
        ? contentArray[0].text
        : contentArray;
}

export function toOpenAIModelListFromGemini(geminiModels) {
    return {
        object: "list",
        data: geminiModels.models.map(m => ({
            id: m.name.startsWith('models/') ? m.name.substring(7) : m.name, // 移除 'models/' 前缀作为 id
            object: "model",
            created: Math.floor(Date.now() / 1000),
            owned_by: "google",
        })),
    };
}

export function toOpenAIChatCompletionFromGemini(geminiResponse, model) {
    const content = processGeminiResponseContent(geminiResponse);
    
    return {
        id: `chatcmpl-${uuidv4()}`,
        object: "chat.completion",
        created: Math.floor(Date.now() / 1000),
        model: model,
        choices: [{
            index: 0,
            message: {
                role: "assistant",
                content: content
            },
            finish_reason: "stop",
        }],
        usage: geminiResponse.usageMetadata ? {
            prompt_tokens: geminiResponse.usageMetadata.promptTokenCount || 0,
            completion_tokens: geminiResponse.usageMetadata.candidatesTokenCount || 0,
            total_tokens: geminiResponse.usageMetadata.totalTokenCount || 0,
        } : {
            prompt_tokens: 0,
            completion_tokens: 0,
            total_tokens: 0,
        },
    };
}

/**
 * Processes Gemini response content to OpenAI format with multimodal support.
 * @param {Object} geminiResponse - The Gemini API response.
 * @returns {string|Array} Processed content.
 */
function processGeminiResponseContent(geminiResponse) {
    if (!geminiResponse || !geminiResponse.candidates) return '';
    
    const contents = [];
    
    geminiResponse.candidates.forEach(candidate => {
        if (candidate.content && candidate.content.parts) {
            candidate.content.parts.forEach(part => {
                if (part.text) {
                    contents.push(part.text);
                }
                // Note: Gemini response typically doesn't include multimodal content in responses
                // but we handle it for completeness
            });
        }
    });
    
    return contents.join('\n');
}

export function toOpenAIStreamChunkFromGemini(geminiChunk, model) {
    return {
        id: `chatcmpl-${uuidv4()}`, // uuidv4 needs to be imported or handled
        object: "chat.completion.chunk",
        created: Math.floor(Date.now() / 1000),
        model: model,
        choices: [{
            index: 0,
            delta: { content: geminiChunk },
            finish_reason: null,
        }],
        usage: geminiChunk.usageMetadata ? {
            prompt_tokens: geminiChunk.usageMetadata.promptTokenCount || 0,
            completion_tokens: geminiChunk.usageMetadata.candidatesTokenCount || 0,
            total_tokens: geminiChunk.usageMetadata.totalTokenCount || 0,
        } : {
            prompt_tokens: 0,
            completion_tokens: 0,
            total_tokens: 0,
        },
    };
}

/**
 * Converts a Claude API messages response to an OpenAI chat completion response.
 * @param {Object} claudeResponse - The Claude API messages response object.
 * @param {string} model - The model name to include in the response.
 * @returns {Object} The formatted OpenAI chat completion response.
 */
export function toOpenAIChatCompletionFromClaude(claudeResponse, model) {
    if (!claudeResponse || !claudeResponse.content || claudeResponse.content.length === 0) {
        return {
            id: `chatcmpl-${uuidv4()}`,
            object: "chat.completion",
            created: Math.floor(Date.now() / 1000),
            model: model,
            choices: [{
                index: 0,
                message: {
                    role: "assistant",
                    content: "",
                },
                finish_reason: "stop",
            }],
            usage: {
                prompt_tokens: claudeResponse.usage?.input_tokens || 0,
                completion_tokens: claudeResponse.usage?.output_tokens || 0,
                total_tokens: (claudeResponse.usage?.input_tokens || 0) + (claudeResponse.usage?.output_tokens || 0),
            },
        };
    }

    const content = processClaudeResponseContent(claudeResponse.content);
    const finishReason = claudeResponse.stop_reason === 'end_turn' ? 'stop' : claudeResponse.stop_reason;

    return {
        id: `chatcmpl-${uuidv4()}`,
        object: "chat.completion",
        created: Math.floor(Date.now() / 1000),
        model: model,
        choices: [{
            index: 0,
            message: {
                role: "assistant",
                content: content
            },
            finish_reason: finishReason,
        }],
        usage: {
            prompt_tokens: claudeResponse.usage?.input_tokens || 0,
            completion_tokens: claudeResponse.usage?.output_tokens || 0,
            total_tokens: (claudeResponse.usage?.input_tokens || 0) + (claudeResponse.usage?.output_tokens || 0),
        },
    };
}

/**
 * Processes Claude response content to OpenAI format with multimodal support.
 * @param {Array} content - Array of Claude content blocks.
 * @returns {string|Array} Processed content.
 */
function processClaudeResponseContent(content) {
    if (!content || !Array.isArray(content)) return '';
    
    const contentArray = [];
    
    content.forEach(block => {
        if (!block) return;
        
        switch (block.type) {
            case 'text':
                contentArray.push({
                    type: 'text',
                    text: block.text || ''
                });
                break;
                
            case 'image':
                // Handle image blocks from Claude
                if (block.source && block.source.type === 'base64') {
                    contentArray.push({
                        type: 'image_url',
                        image_url: {
                            url: `data:${block.source.media_type};base64,${block.source.data}`
                        }
                    });
                }
                break;
                
            default:
                // Handle other content types as text
                if (block.text) {
                    contentArray.push({
                        type: 'text',
                        text: block.text
                    });
                }
        }
    });
    
    // Return as array for multimodal, or string for simple text
    return contentArray.length === 1 && contentArray[0].type === 'text'
        ? contentArray[0].text
        : contentArray;
}

/**
 * Converts a Claude API messages stream chunk to an OpenAI chat completion stream chunk.
 * Based on the official Claude Messages API stream events.
 * @param {Object} claudeChunk - The Claude API messages stream chunk object.
 * @param {string} [model] - Optional model name to include in the response.
 * @returns {Object} The formatted OpenAI chat completion stream chunk, or an empty object for events that don't map.
 */
export function toOpenAIStreamChunkFromClaude(claudeChunk, model) {
    if (!claudeChunk) {
        return null;
    }
    return {
        id: `chatcmpl-${uuidv4()}`, // uuidv4 needs to be imported or handled
        object: "chat.completion.chunk",
        created: Math.floor(Date.now() / 1000),
        model: model,
        system_fingerprint: "",
        choices: [{
            index: 0,
            delta: { 
                content: claudeChunk,
                reasoning_content: ""
            },
            finish_reason: !claudeChunk ? 'stop' : null,
            message: {
                content: claudeChunk,
                reasoning_content: ""
            }
        }],
        usage:{
            prompt_tokens: 0,
            completion_tokens: 0,
            total_tokens: 0,
        },
    };
}

/**
 * Converts a Claude API model list response to an OpenAI model list response.
 * @param {Array<Object>} claudeModels - The array of model objects from Claude API.
 * @returns {Object} The formatted OpenAI model list response.
 */
export function toOpenAIModelListFromClaude(claudeModels) {
    return {
        object: "list",
        data: claudeModels.models.map(m => ({
            id: m.id || m.name, // Claude models might use 'name' instead of 'id'
            object: "model",
            created: Math.floor(Date.now() / 1000), // Claude may not provide 'created' timestamp
            owned_by: "anthropic",
            // You can add more properties here if they exist in Claude's model response
            // and you want to map them to OpenAI's format, e.g., permissions.
        })),
    };
}

/**
 * Converts an OpenAI chat completion response to a Claude API messages response.
 * @param {Object} openaiResponse - The OpenAI API chat completion response object.
 * @param {string} model - The model name to include in the response.
 * @returns {Object} The formatted Claude API messages response.
 */
export function toClaudeChatCompletionFromOpenAI(openaiResponse, model) {
    if (!openaiResponse || !openaiResponse.choices || openaiResponse.choices.length === 0) {
        return {
            id: `msg_${uuidv4()}`,
            type: "message",
            role: "assistant",
            content: [],
            model: model,
            stop_reason: "end_turn",
            stop_sequence: null,
            usage: {
                input_tokens: openaiResponse?.usage?.prompt_tokens || 0,
                output_tokens: openaiResponse?.usage?.completion_tokens || 0
            }
        };
    }

    const choice = openaiResponse.choices[0];
    const contentList = [];

    // Handle tool calls
    const toolCalls = choice.message?.tool_calls || [];
    for (const toolCall of toolCalls.filter(tc => tc && typeof tc === 'object')) {
        if (toolCall.function) {
            const func = toolCall.function;
            const argStr = func.arguments || "{}";
            let argObj;
            try {
                argObj = typeof argStr === 'string' ? JSON.parse(argStr) : argStr;
            } catch (e) {
                argObj = {};
            }
            contentList.push({
                type: "tool_use",
                id: toolCall.id || "",
                name: func.name || "",
                input: argObj,
            });
        }
    }

    // Handle text content
    const contentText = choice.message?.content || "";
    if (contentText) {
        // 使用 _extractThinkingFromOpenAIText 提取 thinking 内容
        const extractedContent = _extractThinkingFromOpenAIText(contentText);
        if (Array.isArray(extractedContent)) {
            contentList.push(...extractedContent);
        } else {
            contentList.push({ type: "text", text: extractedContent });
        }
    }

    // Map OpenAI finish reason to Claude stop reason
    const stopReason = _mapFinishReason(
        choice.finish_reason || "stop",
        "openai",
        "anthropic"
    );

    return {
        id: `msg_${uuidv4()}`,
        type: "message",
        role: "assistant",
        content: contentList,
        model: model,
        stop_reason: stopReason,
        stop_sequence: null,
        usage: {
            input_tokens: openaiResponse.usage?.prompt_tokens || 0,
            output_tokens: openaiResponse.usage?.completion_tokens || 0
        }
    };
}

/**
 * Converts a Claude API request body to an OpenAI chat completion request body.
 * Handles system instructions and multimodal content.
 * @param {Object} claudeRequest - The request body from the Claude API.
 * @returns {Object} The formatted request body for the OpenAI API.
 */
export function toOpenAIRequestFromClaude(claudeRequest) {
    const openaiMessages = [];
    let systemMessageContent = '';

    // Add system message if present
    if (claudeRequest.system) {
        systemMessageContent = claudeRequest.system;
    }

    // Process messages
    if (claudeRequest.messages && Array.isArray(claudeRequest.messages)) {
        const tempOpenAIMessages = [];
        for (const msg of claudeRequest.messages) {
            const role = msg.role;

            // 处理用户的工具结果消息
            if (role === "user" && Array.isArray(msg.content)) {
                const hasToolResult = msg.content.some(
                    item => item && typeof item === 'object' && item.type === "tool_result"
                );

                if (hasToolResult) {
                    for (const item of msg.content) {
                        if (item && typeof item === 'object' && item.type === "tool_result") {
                            const toolUseId = item.tool_use_id || item.id || "";
                            const contentStr = String(item.content || "");
                            tempOpenAIMessages.push({
                                role: "tool",
                                tool_call_id: toolUseId,
                                content: contentStr,
                            });
                        }
                    }
                    continue; // 已处理工具结果，跳过后续处理
                }
            }

            // 处理 assistant 消息中的工具调用
            if (role === "assistant" && Array.isArray(msg.content) && msg.content.length > 0) {
                const firstPart = msg.content[0];
                if (firstPart.type === "tool_use") {
                    const funcName = firstPart.name || "";
                    const funcArgs = firstPart.input || {};
                    tempOpenAIMessages.push({
                        role: "assistant",
                        content: '',
                        tool_calls: [
                            {
                                id: firstPart.id || `call_${funcName}_1`,
                                type: "function",
                                function: {
                                    name: funcName,
                                    arguments: JSON.stringify(funcArgs)
                                },
                                index: firstPart.index || 0
                            }
                        ]
                    });
                    continue; // 已处理
                }
            }

            // 普通文本消息
            const contentConverted = processClaudeContentToOpenAIContent(msg.content || "");
            // 跳过空消息，避免在历史中插入空字符串导致模型误判
            if (contentConverted && (Array.isArray(contentConverted) ? contentConverted.length > 0 : contentConverted.trim().length > 0)) {
                tempOpenAIMessages.push({
                    role: role,
                    content: contentConverted
                });
            }
        }

        // ---------------- OpenAI 兼容性校验 ----------------
        // 确保所有 assistant.tool_calls 均有后续 tool 响应消息；否则移除不匹配的 tool_call
        const validatedMessages = [];
        for (let idx = 0; idx < tempOpenAIMessages.length; idx++) {
            const m = tempOpenAIMessages[idx];
            if (m.role === "assistant" && m.tool_calls) {
                const callIds = m.tool_calls.map(tc => tc.id).filter(id => id);
                // 统计后续是否有对应的 tool 消息
                let unmatched = new Set(callIds);
                for (let laterIdx = idx + 1; laterIdx < tempOpenAIMessages.length; laterIdx++) {
                    const later = tempOpenAIMessages[laterIdx];
                    if (later.role === "tool" && unmatched.has(later.tool_call_id)) {
                        unmatched.delete(later.tool_call_id);
                    }
                    if (unmatched.size === 0) {
                        break;
                    }
                }
                if (unmatched.size > 0) {
                    // 移除无匹配的 tool_call
                    m.tool_calls = m.tool_calls.filter(tc => !unmatched.has(tc.id));
                    // 如果全部被移除，则降级为普通 assistant 文本消息
                    if (m.tool_calls.length === 0) {
                        delete m.tool_calls;
                        if (m.content === null) {
                            m.content = "";
                        }
                    }
                }
            }
            validatedMessages.push(m);
        }
        openaiMessages.push(...validatedMessages);
    }

    const openaiRequest = {
        model: claudeRequest.model, // Default OpenAI model
        messages: openaiMessages,
        max_tokens: checkAndAssignOrDefault(claudeRequest.max_tokens, DEFAULT_MAX_TOKENS),
        temperature: checkAndAssignOrDefault(claudeRequest.temperature, DEFAULT_TEMPERATURE),
        top_p: checkAndAssignOrDefault(claudeRequest.top_p, DEFAULT_TOP_P),
        stream: claudeRequest.stream, // Stream mode is handled by different endpoint
    };

    // Process tools
    if (claudeRequest.tools) {
        const openaiTools = [];
        for (const tool of claudeRequest.tools) {
            openaiTools.push({
                type: "function",
                function: {
                    name: tool.name || "",
                    description: tool.description || "",
                    parameters: _cleanJsonSchemaProperties(tool.input_schema || {}) // 使用清理函数
                }
            });
        }
        openaiRequest.tools = openaiTools;
        openaiRequest.tool_choice = "auto";
    }

    // 处理思考预算转换 (Anthropic thinking -> OpenAI reasoning_effort + max_completion_tokens)
    if (claudeRequest.thinking && claudeRequest.thinking.type === "enabled") {
        const budgetTokens = claudeRequest.thinking.budget_tokens;
        // 根据budget_tokens智能判断reasoning_effort等级
        const reasoningEffort = _determineReasoningEffortFromBudget(budgetTokens);
        openaiRequest.reasoning_effort = reasoningEffort;

        // 处理max_completion_tokens的优先级逻辑
        let maxCompletionTokens = null;

        // 优先级1：客户端传入的max_tokens
        if (claudeRequest.max_tokens !== undefined) {
            maxCompletionTokens = claudeRequest.max_tokens;
            delete openaiRequest.max_tokens; // 移除max_tokens，使用max_completion_tokens
            console.info(`Using client max_tokens as max_completion_tokens: ${maxCompletionTokens}`);
        } else {
            // 优先级2：环境变量OPENAI_REASONING_MAX_TOKENS
            const envMaxTokens = process.env.OPENAI_REASONING_MAX_TOKENS;
            if (envMaxTokens) {
                try {
                    maxCompletionTokens = parseInt(envMaxTokens, 10);
                    console.info(`Using OPENAI_REASONING_MAX_TOKENS from environment: ${maxCompletionTokens}`);
                } catch (e) {
                    console.warn(`Invalid OPENAI_REASONING_MAX_TOKENS value '${envMaxTokens}', must be integer`);
                }
            }

            if (!envMaxTokens) {
                // 优先级3：都没有则报错
                throw new Error("For OpenAI reasoning models, max_completion_tokens is required. Please specify max_tokens in the request or set OPENAI_REASONING_MAX_TOKENS environment variable.");
            }
        }
        openaiRequest.max_completion_tokens = maxCompletionTokens;
        console.info(`Anthropic thinking enabled -> OpenAI reasoning_effort='${reasoningEffort}', max_completion_tokens=${maxCompletionTokens}`);
        if (budgetTokens) {
            console.info(`Budget tokens: ${budgetTokens} -> reasoning_effort: '${reasoningEffort}'`);
        }
    }

    // Add system message at the beginning if present
    if (systemMessageContent) {
        let stringifiedSystemMessageContent = systemMessageContent;
        if(Array.isArray(systemMessageContent)){
            stringifiedSystemMessageContent = systemMessageContent.map(item =>
                    typeof item === 'string' ? item : item.text).join('\n');
        }
        openaiRequest.messages.unshift({ role: 'system', content: stringifiedSystemMessageContent });
    }

    return openaiRequest;
}


/**
 * Processes Claude content to OpenAI content format with multimodal support.
 * @param {Array} content - Array of Claude content blocks.
 * @returns {Array} OpenAI content format.
 */
function processClaudeContentToOpenAIContent(content) {
    if (!content || !Array.isArray(content)) return [];
    
    const contentArray = [];
    
    content.forEach(block => {
        if (!block) return;
        
        switch (block.type) {
            case 'text':
                if (block.text) {
                    contentArray.push({
                        type: 'text',
                        text: block.text
                    });
                }
                break;
                
            case 'image':
                // Handle image blocks from Claude
                if (block.source && block.source.type === 'base64') {
                    contentArray.push({
                        type: 'image_url',
                        image_url: {
                            url: `data:${block.source.media_type};base64,${block.source.data}`
                        }
                    });
                }
                break;
                
            case 'tool_use':
                // Handle tool use as text
                contentArray.push({
                    type: 'text',
                    text: `[Tool use: ${block.name}]`
                });
                break;
                
            case 'tool_result':
                // Handle tool results as text
                contentArray.push({
                    type: 'text',
                    text: typeof block.content === 'string' ? block.content : JSON.stringify(block.content)
                });
                break;
                
            default:
                // Handle any other content types as text
                if (block.text) {
                    contentArray.push({
                        type: 'text',
                        text: block.text
                    });
                }
        }
    });
    
    return contentArray;
}

// =============================================================================
// Gemini 相关转换函数
// =============================================================================

/**
 * Converts an OpenAI chat completion request body to a Gemini API request body.
 * Handles system instructions and merges consecutive messages of the same role with multimodal support.
 * @param {Object} openaiRequest - The request body from the OpenAI API.
 * @returns {Object} The formatted request body for the Gemini API.
 */
export function toGeminiRequestFromOpenAI(openaiRequest) {
    const messages = openaiRequest.messages || [];
    const { systemInstruction, nonSystemMessages } = extractAndProcessSystemMessages(messages);
    
    // Process messages with role conversion and multimodal support
    const processedMessages = [];
    let lastMessage = null;
    
    for (const message of nonSystemMessages) {
        const geminiRole = message.role === 'assistant' ? 'model' : message.role;
        
        // Handle tool responses
        if (geminiRole === 'tool') {
            if (lastMessage) processedMessages.push(lastMessage);
            processedMessages.push({
                role: 'function',
                parts: [{
                    functionResponse: {
                        name: message.name,
                        response: { content: safeParseJSON(message.content) }
                    }
                }]
            });
            lastMessage = null;
            continue;
        }
        
        // Process multimodal content
        const processedContent = processOpenAIContentToGeminiParts(message.content);
        
        // Merge consecutive text messages
        if (lastMessage && lastMessage.role === geminiRole && !message.tool_calls &&
            Array.isArray(processedContent) && processedContent.every(p => p.text) &&
            Array.isArray(lastMessage.parts) && lastMessage.parts.every(p => p.text)) {
            lastMessage.parts.push(...processedContent);
            continue;
        }
        
        if (lastMessage) processedMessages.push(lastMessage);
        lastMessage = { role: geminiRole, parts: processedContent };
    }
    if (lastMessage) processedMessages.push(lastMessage);
    
    // Build Gemini request
    const geminiRequest = {
        contents: processedMessages.filter(item => item.parts && item.parts.length > 0)
    };
    
    if (systemInstruction) geminiRequest.systemInstruction = systemInstruction;
    
    // Handle tools
    if (openaiRequest.tools?.length) {
        geminiRequest.tools = [{
            functionDeclarations: openaiRequest.tools.map(t => {
                // Ensure tool is a valid object and has function property
                if (!t || typeof t !== 'object' || !t.function) {
                    console.warn("Skipping invalid tool declaration in openaiRequest.tools.");
                    return null; // Return null for invalid tools, filter out later
                }

                const func = t.function;
                // Clean parameters schema for Gemini compatibility
                const parameters = _cleanJsonSchemaProperties(func.parameters || {});

                return {
                    name: String(func.name || ''), // Ensure name is string
                    description: String(func.description || ''), // Ensure description is string
                    parameters: parameters // Use cleaned parameters
                };
            }).filter(Boolean) // Filter out any nulls from invalid tool declarations
        }];
        // If no valid functionDeclarations, remove the tools array
        if (geminiRequest.tools[0].functionDeclarations.length === 0) {
            delete geminiRequest.tools;
        }
    }
    
    if (openaiRequest.tool_choice) {
        geminiRequest.toolConfig = buildToolConfig(openaiRequest.tool_choice);
    }
    
    // Add generation config
    const config = buildGenerationConfig(openaiRequest);
    if (Object.keys(config).length) geminiRequest.generationConfig = config;
    
    // Validation
    if (geminiRequest.contents[0]?.role !== 'user') {
        console.warn(`[Request Conversion] Warning: Conversation does not start with a 'user' role.`);
    }
    
    return geminiRequest;
}

/**
 * Processes OpenAI content to Gemini parts format with multimodal support.
 * @param {string|Array} content - OpenAI message content.
 * @returns {Array} Array of Gemini parts.
 */
function processOpenAIContentToGeminiParts(content) {
    if (!content) return [];
    
    // Handle string content
    if (typeof content === 'string') {
        return [{ text: content }];
    }
    
    // Handle array content (multimodal)
    if (Array.isArray(content)) {
        const parts = [];
        
        content.forEach(item => {
            if (!item) return;
            
            switch (item.type) {
                case 'text':
                    if (item.text) {
                        parts.push({ text: item.text });
                    }
                    break;
                    
                case 'image_url':
                    if (item.image_url) {
                        const imageUrl = typeof item.image_url === 'string'
                            ? item.image_url
                            : item.image_url.url;
                            
                        if (imageUrl.startsWith('data:')) {
                            // Handle base64 data URL
                            const [header, data] = imageUrl.split(',');
                            const mimeType = header.match(/data:([^;]+)/)?.[1] || 'image/jpeg';
                            parts.push({
                                inlineData: {
                                    mimeType,
                                    data
                                }
                            });
                        } else {
                            // Handle regular URL
                            parts.push({
                                fileData: {
                                    mimeType: 'image/jpeg', // Default MIME type
                                    fileUri: imageUrl
                                }
                            });
                        }
                    }
                    break;
                    
                case 'audio':
                    // Handle audio content
                    if (item.audio_url) {
                        const audioUrl = typeof item.audio_url === 'string'
                            ? item.audio_url
                            : item.audio_url.url;
                            
                        if (audioUrl.startsWith('data:')) {
                            const [header, data] = audioUrl.split(',');
                            const mimeType = header.match(/data:([^;]+)/)?.[1] || 'audio/wav';
                            parts.push({
                                inlineData: {
                                    mimeType,
                                    data
                                }
                            });
                        } else {
                            parts.push({
                                fileData: {
                                    mimeType: 'audio/wav', // Default MIME type
                                    fileUri: audioUrl
                                }
                            });
                        }
                    }
                    break;
            }
        });
        
        return parts;
    }
    
    return [];
}

function safeParseJSON(str) {
    if (!str) {
        return str;
    }
    let cleanedStr = str;

    // 处理可能被截断的转义序列
    if (cleanedStr.endsWith('\\') && !cleanedStr.endsWith('\\\\')) {
        cleanedStr = cleanedStr.substring(0, cleanedStr.length - 1); // 移除悬挂的反斜杠
    } else if (cleanedStr.endsWith('\\u') || cleanedStr.endsWith('\\u0') || cleanedStr.endsWith('\\u00')) {
        // 不完整的Unicode转义序列
        const idx = cleanedStr.lastIndexOf('\\u');
        cleanedStr = cleanedStr.substring(0, idx);
    }

    try {
        return JSON.parse(cleanedStr || '{}');
    } catch (e) {
        // 如果清理后仍然无法解析，则返回原始字符串或进行其他错误处理
        return str;
    }
}

function buildToolConfig(toolChoice) {
    if (typeof toolChoice === 'string' && ['none', 'auto'].includes(toolChoice)) {
        return { functionCallingConfig: { mode: toolChoice.toUpperCase() } };
    }
    if (typeof toolChoice === 'object' && toolChoice.function) {
        return { functionCallingConfig: { mode: 'ANY', allowedFunctionNames: [toolChoice.function.name] } };
    }
    return null;
}

/**
 * 根据 tool_result 字段构造 Gemini functionResponse
 * @param {Object} item - 工具结果项
 * @returns {Object|null} functionResponse 对象
 */
function _buildFunctionResponse(item) {
    if (!item || typeof item !== 'object') {
        return null;
    }

    // 判定是否为工具结果
    const isResult = (
        item.type === "tool_result" ||
        item.tool_use_id !== undefined ||
        item.tool_output !== undefined ||
        item.result !== undefined ||
        item.content !== undefined
    );
    if (!isResult) {
        return null;
    }

    // 提取函数名
    let funcName = null;

    // 方法1：从映射表中获取（Anthropic格式）
    const toolUseId = item.tool_use_id || item.id;
    // 这里需要注意，AnthropicConverter内部维护的_toolUseMapping是类的私有属性，在convert.js中无法直接访问
    // 因此，这里需要依赖全局的toolStateManager
    // if (toolUseId && this._toolUseMapping) { // 这行代码在convert.js中将无法使用
    //     funcName = this._toolUseMapping[toolUseId];
    // }

    // 方法1.5：使用全局工具状态管理器
    if (!funcName && toolUseId) {
        // 先尝试从ID中提取可能的函数名
        let potentialFuncName = null;
        if (String(toolUseId).startsWith("call_")) {
            const nameAndHash = toolUseId.substring(4); // 去掉 "call_" 前缀
            potentialFuncName = nameAndHash.substring(0, nameAndHash.lastIndexOf("_"));
        }

        // 检查全局管理器中是否有对应的映射
        if (potentialFuncName) {
            const storedId = toolStateManager.getToolId(potentialFuncName);
            if (storedId === toolUseId) {
                funcName = potentialFuncName;
            }
        }
    }

    // 方法2：从 tool_use_id 中提取（OpenAI格式）
    if (!funcName && toolUseId && String(toolUseId).startsWith("call_")) {
        // 格式: call_<function_name>_<hash> ，函数名可能包含多个下划线
        const nameAndHash = toolUseId.substring(4); // 去掉 "call_" 前缀
        funcName = nameAndHash.substring(0, nameAndHash.lastIndexOf("_")); // 去掉最后一个 hash 段
    }

    // 方法3：直接从字段获取
    if (!funcName) {
        funcName = (
            item.tool_name ||
            item.name ||
            item.function_name
        );
    }

    if (!funcName) {
        return null;
    }

    // 提取结果内容
    let funcResponse = null;

    // 尝试多个可能的结果字段
    for (const key of ["content", "tool_output", "output", "response", "result"]) {
        if (item[key] !== undefined) {
            funcResponse = item[key];
            break;
        }
    }

    // 如果 content 是列表，尝试提取文本
    if (Array.isArray(funcResponse) && funcResponse.length > 0) {
        const textParts = funcResponse
            .filter(p => p && typeof p === 'object' && p.type === "text")
            .map(p => p.text || "");
        if (textParts.length > 0) {
            funcResponse = textParts.join("");
        }
    }

    // 确保有响应内容
    if (funcResponse === null || funcResponse === undefined) {
        funcResponse = "";
    }

    // Gemini 要求 response 为 JSON 对象，若为原始字符串则包装
    if (typeof funcResponse !== 'object') {
        funcResponse = { content: String(funcResponse) };
    }

    return {
        functionResponse: {
            name: funcName,
            response: funcResponse
        }
    };
}

/**
 * Converts a Gemini API model list response to a Claude API model list response.
 * @param {Object} geminiModels - The Gemini API model list response object.
 * @returns {Object} The formatted Claude API model list response.
 */
export function toClaudeModelListFromGemini(geminiModels) {
    return {
        models: geminiModels.models.map(m => ({
            name: m.name.startsWith('models/') ? m.name.substring(7) : m.name, // 移除 'models/' 前缀作为 name
            // Claude models 可能包含其他字段，这里使用默认值
            description: "", // Gemini models 不提供描述
            // Claude API 可能需要其他字段，根据实际 API 文档调整
        })),
    };
}

/**
 * Converts an OpenAI API model list response to a Claude API model list response.
 * @param {Object} openaiModels - The OpenAI API model list response object.
 * @returns {Object} The formatted Claude API model list response.
 */
export function toClaudeModelListFromOpenAI(openaiModels) {
    return {
        models: openaiModels.data.map(m => ({
            name: m.id, // OpenAI 的 id 映射为 Claude 的 name
            // Claude models 可能包含其他字段，这里使用默认值
            description: "", // OpenAI models 不提供描述
            // Claude API 可能需要其他字段，根据实际 API 文档调整
        })),
    };
}

/**
 * 从OpenAI文本中提取thinking内容，返回Anthropic格式的content blocks
 * @param {string} text - 文本内容
 * @returns {string|Array} 提取后的内容
 */
function _extractThinkingFromOpenAIText(text) {
    // 匹配 <thinking>...</thinking> 标签
    const thinkingPattern = /<thinking>\s*(.*?)\s*<\/thinking>/gs;
    const matches = [...text.matchAll(thinkingPattern)];

    const contentBlocks = [];
    let lastEnd = 0;

    for (const match of matches) {
        // 添加thinking标签之前的文本（如果有）
        const beforeText = text.substring(lastEnd, match.index).trim();
        if (beforeText) {
            contentBlocks.push({
                type: "text",
                text: beforeText
            });
        }

        // 添加thinking内容
        const thinkingText = match[1].trim();
        if (thinkingText) {
            contentBlocks.push({
                type: "thinking",
                thinking: thinkingText
            });
        }

        lastEnd = match.index + match[0].length;
    }

    // 添加最后一个thinking标签之后的文本（如果有）
    const afterText = text.substring(lastEnd).trim();
    if (afterText) {
        contentBlocks.push({
            type: "text",
            text: afterText
        });
    }

    // 如果没有找到thinking标签，返回原文本
    if (contentBlocks.length === 0) {
        return text;
    }

    // 如果只有一个文本块，返回字符串
    if (contentBlocks.length === 1 && contentBlocks[0].type === "text") {
        return contentBlocks[0].text;
    }

    return contentBlocks;
}

/**
 * Converts an OpenAI chat completion stream chunk to a Claude API messages stream chunk.
 * @param {Object} openaiChunk - The OpenAI API chat completion stream chunk object.
 * @param {string} [model] - Optional model name to include in the response.
 * @returns {Object} The formatted Claude API messages stream chunk.
 */
export function toClaudeStreamChunkFromOpenAI(openaiChunk, model) {
    if (!openaiChunk) {
        return null;
    }

    // 工具调用
    if ( Array.isArray(openaiChunk)) {
        const toolCall = openaiChunk[0]; // 假设每次只处理一个工具调用
        if (toolCall) {
            if (toolCall.function && toolCall.function.name) {
                const toolUseBlock = {
                    type: "tool_use",
                    id: toolCall.id || `call_${toolCall.function.name}_${Date.now()}`,
                    name: toolCall.function.name,
                    input: toolCall.function.arguments ? JSON.parse(toolCall.function.arguments) : {}
                };
                return { type: "content_block_start", index: 1, content_block: toolUseBlock };
            }
        }
    }

    // 文本内容
    if (typeof openaiChunk === 'string') {
        return {
            type: "content_block_delta",
            index: 0,
            delta: {
                type: "text_delta",
                text: openaiChunk
            }
        };
    }
    return null;
}

function buildGenerationConfig({ temperature, max_tokens, top_p, stop }) {
    const config = {};
    config.temperature = checkAndAssignOrDefault(temperature, DEFAULT_TEMPERATURE);
    config.maxOutputTokens = checkAndAssignOrDefault(max_tokens, DEFAULT_GEMINI_MAX_TOKENS);
    config.topP = checkAndAssignOrDefault(top_p, DEFAULT_TOP_P);
    if (stop !== undefined) config.stopSequences = Array.isArray(stop) ? stop : [stop];
    return config;
}

/**
 * Converts an OpenAI chat completion request body to a Claude API request body.
 * Handles system instructions, tool calls, and multimodal content.
 * @param {Object} openaiRequest - The request body from the OpenAI API.
 * @returns {Object} The formatted request body for the Claude API.
 */
export function toClaudeRequestFromOpenAI(openaiRequest) {
    const messages = openaiRequest.messages || [];
    const { systemInstruction, nonSystemMessages } = extractAndProcessSystemMessages(messages);

    const claudeMessages = [];

    for (const message of nonSystemMessages) {
        const role = message.role === 'assistant' ? 'assistant' : 'user';
        let content = [];

        if (message.role === 'tool') {
            // Claude expects tool_result to be in a 'user' message
            // The content of a tool message is a single tool_result block
            content.push({
                type: 'tool_result',
                tool_use_id: message.tool_call_id, // Use tool_call_id from OpenAI tool message
                content: safeParseJSON(message.content) // Parse content as JSON if possible
            });
            claudeMessages.push({ role: 'user', content: content });
        } else if (message.role === 'assistant' && message.tool_calls?.length) {
            // Assistant message with tool calls - properly format as tool_use blocks
            // Claude expects tool_use to be in an 'assistant' message
            const toolUseBlocks = message.tool_calls.map(tc => ({
                type: 'tool_use',
                id: tc.id,
                name: tc.function.name,
                input: safeParseJSON(tc.function.arguments)
            }));
            claudeMessages.push({ role: 'assistant', content: toolUseBlocks });
        } else {
            // Regular user or assistant message (text and multimodal)
            if (typeof message.content === 'string') {
                if (message.content) {
                    content.push({ type: 'text', text: message.content });
                }
            } else if (Array.isArray(message.content)) {
                message.content.forEach(item => {
                    if (!item) return;
                    switch (item.type) {
                        case 'text':
                            if (item.text) {
                                content.push({ type: 'text', text: item.text });
                            }
                            break;
                        case 'image_url':
                            if (item.image_url) {
                                const imageUrl = typeof item.image_url === 'string'
                                    ? item.image_url
                                    : item.image_url.url;
                                if (imageUrl.startsWith('data:')) {
                                    const [header, data] = imageUrl.split(',');
                                    const mediaType = header.match(/data:([^;]+)/)?.[1] || 'image/jpeg';
                                    content.push({
                                        type: 'image',
                                        source: {
                                            type: 'base64',
                                            media_type: mediaType,
                                            data: data
                                        }
                                    });
                                } else {
                                    // Claude requires base64 for images, so for URLs, we'll represent as text
                                    content.push({ type: 'text', text: `[Image: ${imageUrl}]` });
                                }
                            }
                            break;
                        case 'audio':
                            // Handle audio content as text placeholder
                            if (item.audio_url) {
                                const audioUrl = typeof item.audio_url === 'string'
                                    ? item.audio_url
                                    : item.audio_url.url;
                                content.push({ type: 'text', text: `[Audio: ${audioUrl}]` });
                            }
                            break;
                    }
                });
            }
            // Only add message if content is not empty
            if (content.length > 0) {
                claudeMessages.push({ role: role, content: content });
            }
        }
    }

    const claudeRequest = {
        model: openaiRequest.model,
        messages: claudeMessages,
        max_tokens: checkAndAssignOrDefault(openaiRequest.max_tokens, DEFAULT_MAX_TOKENS),
        temperature: checkAndAssignOrDefault(openaiRequest.temperature, DEFAULT_TEMPERATURE),
        top_p: checkAndAssignOrDefault(openaiRequest.top_p, DEFAULT_TOP_P),
    };

    if (systemInstruction) {
        claudeRequest.system = extractTextFromMessageContent(systemInstruction.parts[0].text);
    }

    if (openaiRequest.tools?.length) {
        claudeRequest.tools = openaiRequest.tools.map(t => ({
            name: t.function.name,
            description: t.function.description || '',
            input_schema: t.function.parameters || { type: 'object', properties: {} }
        }));
        claudeRequest.tool_choice = buildClaudeToolChoice(openaiRequest.tool_choice);
    }

    return claudeRequest;
}

function buildClaudeToolChoice(toolChoice) {
    if (typeof toolChoice === 'string') {
        const mapping = { auto: 'auto', none: 'none', required: 'any' };
        return { type: mapping[toolChoice] };
    }
    if (typeof toolChoice === 'object' && toolChoice.function) {
        return { type: 'tool', name: toolChoice.function.name };
    }
    return undefined;
}

/**
 * Extracts and combines all 'system' role messages into a single system instruction.
 * Filters out system messages and returns the remaining non-system messages.
 * @param {Array<Object>} messages - Array of message objects from OpenAI request.
 * @returns {{systemInstruction: Object|null, nonSystemMessages: Array<Object>}}
 *          An object containing the system instruction and an array of non-system messages.
 */
export function extractAndProcessSystemMessages(messages) {
    const systemContents = [];
    const nonSystemMessages = [];

    for (const message of messages) {
        if (message.role === 'system') {
            systemContents.push(extractTextFromMessageContent(message.content));
        } else {
            nonSystemMessages.push(message);
        }
    }

    let systemInstruction = null;
    if (systemContents.length > 0) {
        systemInstruction = {
            parts: [{
                text: systemContents.join('\n')
            }]
        };
    }
    return { systemInstruction, nonSystemMessages };
}

/**
 * Extracts text from various forms of message content.
 * @param {string|Array<Object>} content - The content from a message object.
 * @returns {string} The extracted text.
 */
export function extractTextFromMessageContent(content) {
    if (typeof content === 'string') {
        return content;
    }
    if (Array.isArray(content)) {
        return content
            .filter(part => part.type === 'text' && part.text)
            .map(part => part.text)
            .join('\n');
    }
    return '';
}

/**
 * Converts a Claude API request body to a Gemini API request body.
 * Handles system instructions and multimodal content.
 * @param {Object} claudeRequest - The request body from the Claude API.
 * @returns {Object} The formatted request body for the Gemini API.
 */
export function toGeminiRequestFromClaude(claudeRequest) {
    // Ensure claudeRequest is a valid object
    if (!claudeRequest || typeof claudeRequest !== 'object') {
        console.warn("Invalid claudeRequest provided to toGeminiRequestFromClaude.");
        return { contents: [] };
    }

    const geminiRequest = {
        contents: []
    };

    // Handle system instruction
    if (claudeRequest.system) {
        let incomingSystemText = null;
        if (typeof claudeRequest.system === 'string') {
            incomingSystemText = claudeRequest.system;
        } else if (typeof claudeRequest.system === 'object') {
            incomingSystemText = JSON.stringify(claudeRequest.system);
        } else if (claudeRequest.messages?.length > 0) {
            // Fallback to first user message if no system property
            const userMessage = claudeRequest.messages.find(m => m.role === 'user');
            if (userMessage) {
                if (Array.isArray(userMessage.content)) {
                    incomingSystemText = userMessage.content.map(block => block.text).join('');
                } else {
                    incomingSystemText = userMessage.content;
                }
            }
        }
        geminiRequest.systemInstruction = {
            parts: [{ text: incomingSystemText}] // Ensure system is string
        };
    }

    // Process messages
    if (Array.isArray(claudeRequest.messages)) {
        claudeRequest.messages.forEach(message => {
            // Ensure message is a valid object and has a role and content
            if (!message || typeof message !== 'object' || !message.role || !message.content) {
                console.warn("Skipping invalid message in claudeRequest.messages.");
                return;
            }

            const geminiRole = message.role === 'assistant' ? 'model' : 'user';
            const processedParts = processClaudeContentToGeminiParts(message.content);

            // If the processed parts contain a function response, it should be a 'function' role message
            // Claude's tool_result block does not contain the function name, only tool_use_id.
            // We need to infer the function name from the previous tool_use message.
            // For simplicity in this conversion, we'll assume the tool_use_id is the function name
            // or that the tool_result is always preceded by a tool_use with the correct name.
            // A more robust solution would involve tracking tool_use_ids to function names.
            const functionResponsePart = processedParts.find(part => part.functionResponse);
            if (functionResponsePart) {
                geminiRequest.contents.push({
                    role: 'function',
                    parts: [functionResponsePart]
                });
            } else if (processedParts.length > 0) { // Only push if there are actual parts
                geminiRequest.contents.push({
                    role: geminiRole,
                    parts: processedParts
                });
            }
        });
    }

    // Add generation config
    const generationConfig = {};
    generationConfig.maxOutputTokens = checkAndAssignOrDefault(claudeRequest.max_tokens, DEFAULT_GEMINI_MAX_TOKENS);
    generationConfig.temperature = checkAndAssignOrDefault(claudeRequest.temperature, DEFAULT_TEMPERATURE);
    generationConfig.topP = checkAndAssignOrDefault(claudeRequest.top_p, DEFAULT_TOP_P);
    
    if (Object.keys(generationConfig).length > 0) {
        geminiRequest.generationConfig = generationConfig;
    }

    // Handle tools
    if (Array.isArray(claudeRequest.tools)) {
        geminiRequest.tools = [{
            functionDeclarations: claudeRequest.tools.map(tool => {
                // Ensure tool is a valid object and has a name
                if (!tool || typeof tool !== 'object' || !tool.name) {
                    console.warn("Skipping invalid tool declaration in claudeRequest.tools.");
                    return null; // Return null for invalid tools, filter out later
                }

                // Filter out TodoWrite tool
                // if (tool.name === 'TodoWrite') {
                //     console.log("Filtering out TodoWrite tool");
                //     return null;
                // }

                delete tool.input_schema.$schema;
                return {
                    name: String(tool.name), // Ensure name is string
                    description: String(tool.description || ''), // Ensure description is string
                    parameters: tool.input_schema && typeof tool.input_schema === 'object' ? tool.input_schema : { type: 'object', properties: {} }
                };
            }).filter(Boolean) // Filter out any nulls from invalid tool declarations
        }];
        // If no valid functionDeclarations, remove the tools array
        if (geminiRequest.tools[0].functionDeclarations.length === 0) {
            delete geminiRequest.tools;
        }
    }

    // Handle tool_choice
    if (claudeRequest.tool_choice) {
        geminiRequest.toolConfig = buildGeminiToolConfigFromClaude(claudeRequest.tool_choice);
    }

    return geminiRequest;
}

/**
 * Builds Gemini toolConfig from Claude tool_choice.
 * @param {Object} claudeToolChoice - The tool_choice object from Claude API.
 * @returns {Object|undefined} The formatted toolConfig for Gemini API, or undefined if invalid.
 */
function buildGeminiToolConfigFromClaude(claudeToolChoice) {
    if (!claudeToolChoice || typeof claudeToolChoice !== 'object' || !claudeToolChoice.type) {
        console.warn("Invalid claudeToolChoice provided to buildGeminiToolConfigFromClaude.");
        return undefined;
    }

    switch (claudeToolChoice.type) {
        case 'auto':
            return { functionCallingConfig: { mode: 'AUTO' } };
        case 'none':
            return { functionCallingConfig: { mode: 'NONE' } };
        case 'tool':
            if (claudeToolChoice.name && typeof claudeToolChoice.name === 'string') {
                return { functionCallingConfig: { mode: 'ANY', allowedFunctionNames: [claudeToolChoice.name] } };
            }
            console.warn("Invalid tool name in claudeToolChoice of type 'tool'.");
            return undefined;
        default:
            console.warn(`Unsupported claudeToolChoice type: ${claudeToolChoice.type}`);
            return undefined;
    }
}

/**
 * Processes Claude content to Gemini parts format with multimodal support.
 * @param {string|Array} content - Claude message content.
 * @returns {Array} Array of Gemini parts.
 */
function processClaudeContentToGeminiParts(content) {
    if (!content) return [];

    // Handle string content
    if (typeof content === 'string') {
        return [{ text: content }];
    }

    // Handle array content (multimodal)
    if (Array.isArray(content)) {
        const parts = [];

        content.forEach(block => {
            // Ensure block is a valid object and has a type
            if (!block || typeof block !== 'object' || !block.type) {
                console.warn("Skipping invalid content block in processClaudeContentToGeminiParts.");
                return;
            }

            switch (block.type) {
                case 'text':
                    if (typeof block.text === 'string') {
                        parts.push({ text: block.text });
                    } else {
                        console.warn("Invalid text content in Claude text block.");
                    }
                    break;

                case 'image':
                    if (block.source && typeof block.source === 'object' && block.source.type === 'base64' &&
                        typeof block.source.media_type === 'string' && typeof block.source.data === 'string') {
                        parts.push({
                            inlineData: {
                                mimeType: block.source.media_type,
                                data: block.source.data
                            }
                        });
                    } else {
                        console.warn("Invalid image source in Claude image block.");
                    }
                    break;

                case 'tool_use':
                    if (typeof block.name === 'string' && block.input && typeof block.input === 'object') {
                        // Filter out TodoWrite tool use
                        // if (block.name === 'TodoWrite') {
                        //     console.log("Filtering out TodoWrite tool use");
                        //     break; // Skip adding this tool to parts
                        // }
                        parts.push({
                            functionCall: {
                                name: block.name,
                                args: block.input
                            }
                        });
                    } else {
                        console.warn("Invalid tool_use block in Claude content.");
                    }
                    break;

                case 'tool_result':
                    // Claude's tool_result block does not contain the function name, only tool_use_id.
                    // Gemini's functionResponse requires a function name.
                    // For now, we'll use the tool_use_id as the name, but this is a potential point of failure
                    // if the tool_use_id is not the actual function name in Gemini's context.
                    // A more robust solution would involve tracking the function name from the tool_use block.
                    if (typeof block.tool_use_id === 'string') {
                        parts.push({
                            functionResponse: {
                                name: block.tool_use_id, // This might need to be the actual function name
                                response: { content: block.content } // content can be any JSON-serializable value
                            }
                        });
                    } else {
                        console.warn("Invalid tool_result block in Claude content: missing tool_use_id.");
                    }
                    break;

                default:
                    // Handle any other content types as text if they have a text property
                    if (typeof block.text === 'string') {
                        parts.push({ text: block.text });
                    } else {
                        console.warn(`Unsupported Claude content block type: ${block.type}. Skipping.`);
                    }
            }
        });

        return parts;
    }

    return [];
}

/**
 * Converts a Gemini API response to a Claude API messages response.
 * @param {Object} geminiResponse - The Gemini API response object.
 * @param {string} model - The model name to include in the response.
 * @returns {Object} The formatted Claude API messages response.
 */
export function toClaudeChatCompletionFromGemini(geminiResponse, model) {
    // Handle cases where geminiResponse or candidates are missing or empty
    if (!geminiResponse || !geminiResponse.candidates || geminiResponse.candidates.length === 0) {
        return {
            id: `msg_${uuidv4()}`,
            type: "message",
            role: "assistant",
            content: [], // Empty content for no candidates
            model: model,
            stop_reason: "end_turn", // Default stop reason
            stop_sequence: null,
            usage: {
                input_tokens: geminiResponse?.usageMetadata?.promptTokenCount || 0,
                output_tokens: geminiResponse?.usageMetadata?.candidatesTokenCount || 0
            }
        };
    }

    const candidate = geminiResponse.candidates[0];
    const content = processGeminiResponseToClaudeContent(geminiResponse);
    const finishReason = candidate.finishReason;
    let stopReason = "end_turn"; // Default stop reason

    if (finishReason) {
        switch (finishReason) {
            case 'STOP':
                stopReason = 'end_turn';
                break;
            case 'MAX_TOKENS':
                stopReason = 'max_tokens';
                break;
            case 'SAFETY':
                stopReason = 'safety';
                break;
            case 'RECITATION':
                stopReason = 'recitation';
                break;
            case 'OTHER':
                stopReason = 'other';
                break;
            default:
                stopReason = 'end_turn';
        }
    }

    return {
        id: `msg_${uuidv4()}`,
        type: "message",
        role: "assistant",
        content: content,
        model: model,
        stop_reason: stopReason,
        stop_sequence: null,
        usage: {
            input_tokens: geminiResponse.usageMetadata?.promptTokenCount || 0,
            output_tokens: geminiResponse.usageMetadata?.candidatesTokenCount || 0
        }
    };
}

/**
 * Processes Gemini response content to Claude format.
 * @param {Object} geminiResponse - The Gemini API response.
 * @returns {Array} Array of Claude content blocks.
 */
function processGeminiResponseToClaudeContent(geminiResponse) {
    if (!geminiResponse || !geminiResponse.candidates || geminiResponse.candidates.length === 0) return [];

    const content = [];

    for (const candidate of geminiResponse.candidates) {
        // 检查完成原因是否为错误类型
        if (candidate.finishReason && candidate.finishReason !== 'STOP') {
            // console.log('Gemini response finishReason:', JSON.stringify(candidate));
            // console.warn('Gemini response contains malformed function call:', candidate.finishMessage || 'No finish message');
            
            // 将错误信息作为文本内容返回
            if (candidate.finishMessage) {
                content.push({
                    type: 'text',
                    text: `Error: ${candidate.finishMessage}`
                });
            }
            // console.log("Processed content:", content);
            continue; // 跳过当前候选的进一步处理
        }

        if (candidate.content && candidate.content.parts) {
            for (const part of candidate.content.parts) {
                if (part.text) {
                    content.push({
                        type: 'text',
                        text: part.text
                    });
                } else if (part.inlineData) {
                    content.push({
                        type: 'image',
                        source: {
                            type: 'base64',
                            media_type: part.inlineData.mimeType,
                            data: part.inlineData.data
                        }
                    });
                } else if (part.functionCall) {
                    // Convert Gemini functionCall to Claude tool_use
                    content.push({
                        type: 'tool_use',
                        id: uuidv4(), // Generate a new ID for the tool use
                        name: part.functionCall.name,
                        input: part.functionCall.args || {}
                    });
                }
            }
        }
    }

    return content;
}

/**
 * Converts a Gemini API stream chunk to a Claude API messages stream chunk.
 * @param {Object} geminiChunk - The Gemini API stream chunk object.
 * @param {string} [model] - Optional model name to include in the response.
 * @returns {Object} The formatted Claude API messages stream chunk.
 */
export function toClaudeStreamChunkFromGemini(geminiChunk, model) {
    if (!geminiChunk) {
        return null;
    }

    if (typeof geminiChunk === 'string') {
        return {
            type: "content_block_delta",
            index: 0,
            delta: {
                type: "text_delta",
                text: geminiChunk
            }
        };
    }

    return null;
}


/**
 * Converts a Claude API response to an OpenAI Responses API response.
 * @param {Object} claudeResponse - The Claude API response object.
 * @param {string} model - The model name to include in the response.
 * @returns {Object} The formatted OpenAI Responses API response.
 */
export function toOpenAIResponsesFromClaude(claudeResponse, model) {
    // 根据参考示例重构响应结构
    const content = processClaudeResponseContent(claudeResponse.content);
    const textContent = typeof content === 'string' ? content : JSON.stringify(content);

    // 将claude的内容转换为OpenAI Responses输出格式
    let output = [];

    // 添加文本内容
    output.push({
        type: "message",
        id: `msg_${uuidv4().replace(/-/g, '')}`,
        summary: [],
        type: "message",
        role: "assistant",
        status: "completed",
        content: [{
            annotations: [],
            logprobs: [],
            text: textContent,
            type: "output_text"
        }]
    });

    return {
        background: false,
        created_at: Math.floor(Date.now() / 1000),
        error: null,
        id: `resp_${uuidv4().replace(/-/g, '')}`,
        incomplete_details: null,
        max_output_tokens: null,
        max_tool_calls: null,
        metadata: {},
        model: model || claudeResponse.model,
        object: "response",
        output: output,
        parallel_tool_calls: true,
        previous_response_id: null,
        prompt_cache_key: null,
        reasoning: {
            // effort: "minimal",
            // summary: "detailed"
        },
        safety_identifier: "user-"+uuidv4().replace(/-/g, ''), // 示例值
        service_tier: "default",
        status: "completed",
        store: false,
        temperature: 1,
        text: {
            format: {type: "text"},
            // verbosity: "medium"
        },
        tool_choice: "auto",
        tools: [],
        top_logprobs: 0,
        top_p: 1,
        truncation: "disabled",
        usage: {
            input_tokens: claudeResponse.usage?.input_tokens || 0, // 示例值
            input_tokens_details: {
                cached_tokens: claudeResponse.usage?.cache_creation_input_tokens || 0, // 如果有缓存相关数据则使用
            },
            output_tokens: claudeResponse.usage?.output_tokens || 0, // 示例值
            output_tokens_details: {
                reasoning_tokens: 0
            },
            total_tokens: (claudeResponse.usage?.input_tokens || 0) + (claudeResponse.usage?.output_tokens || 0) // 示例值
        },
        user: null
    };
}

/**
 * Converts a Gemini API response to an OpenAI Responses API response.
 * @param {Object} geminiResponse - The Gemini API response object.
 * @param {string} model - The model name to include in the response.
 * @returns {Object} The formatted OpenAI Responses API response.
 */
export function toOpenAIResponsesFromGemini(geminiResponse, model) {
    // 根据参考示例重构响应结构
    const content = processGeminiResponseContent(geminiResponse);
    const textContent = typeof content === 'string' ? content : JSON.stringify(content);

    // 将gemini的内容转换为OpenAI Responses输出格式
    let output = [];

    // 添加文本内容
    output.push({
        id: `msg_${uuidv4().replace(/-/g, '')}`,
        summary: [],
        type: "message",
        role: "assistant",
        status: "completed",
        content: [{
            annotations: [],
            logprobs: [],
            text: textContent,
            type: "output_text"
        }]
    });

    return {
        background: false,
        created_at: Math.floor(Date.now() / 1000),
        error: null,
        id: `resp_${uuidv4().replace(/-/g, '')}`,
        incomplete_details: null,
        max_output_tokens: null,
        max_tool_calls: null,
        metadata: {},
        model: model,
        object: "response",
        output: output,
        parallel_tool_calls: true,
        previous_response_id: null,
        prompt_cache_key: null,
        reasoning: {
            // effort: "minimal",
            // summary: "detailed"
        },
        safety_identifier: "user-"+uuidv4().replace(/-/g, ''), // 示例值
        service_tier: "default",
        status: "completed",
        store: false,
        temperature: 1,
        text: {
            format: {type: "text"},
            // verbosity: "medium"
        },
        tool_choice: "auto",
        tools: [],
        top_logprobs: 0,
        top_p: 1,
        truncation: "disabled",
        usage: {
            input_tokens: geminiResponse.usageMetadata?.promptTokenCount || 0, // 示例值
            input_tokens_details: {
                cached_tokens: geminiResponse.usageMetadata?.cachedTokens || 0, // 使用正确的Gemini缓存字段
            },
            output_tokens: geminiResponse.usageMetadata?.candidatesTokenCount || 0, // 示例值
            output_tokens_details: {
                reasoning_tokens: 0
            },
            total_tokens: geminiResponse.usageMetadata?.totalTokenCount || 0, // 示例值
        },
        user: null
    };
}


/**
 * Converts an OpenAI Responses API request body to a Claude API request body.
 * @param {Object} responsesRequest - The request body from the OpenAI Responses API.
 * @returns {Object} The formatted request body for the Claude API.
 */
export function toClaudeRequestFromOpenAIResponses(responsesRequest) {
    // The OpenAI Responses API uses input and instructions instead of messages
    const claudeRequest = {
        model: responsesRequest.model,
        max_tokens: checkAndAssignOrDefault(responsesRequest.max_tokens, DEFAULT_MAX_TOKENS),
        temperature: checkAndAssignOrDefault(responsesRequest.temperature, DEFAULT_TEMPERATURE),
        top_p: checkAndAssignOrDefault(responsesRequest.top_p, DEFAULT_TOP_P),
    };

    // Process instructions as system message
    if (responsesRequest.instructions) {
        claudeRequest.system = [];
        claudeRequest.system.push({
            text: typeof responsesRequest.instructions === 'string' ? responsesRequest.instructions : JSON.stringify(responsesRequest.instructions)
        });
        
    }

    const claudeMessages = [];
    // Process input as user message content
    if (responsesRequest.input) {
        if (typeof responsesRequest.input === 'string') {
            // Create user message with the string content
            claudeMessages.push({
                role: 'user',
                content: [{
                    type: 'text',
                    text: responsesRequest.input
                }]
            });
        } else {
            // Handle array of messages or items - process the entire array
            for (const message of responsesRequest.input) {
                const role = message.role === 'assistant' ? 'assistant' : 'user';
                let content = [];

                if (message.role === 'tool') {
                    // Claude expects tool_result to be in a 'user' message
                    // The content of a tool message is a single tool_result block
                    content.push({
                        type: 'tool_result',
                        tool_use_id: message.tool_call_id, // Use tool_call_id from OpenAI tool message
                        content: safeParseJSON(message.content) // Parse content as JSON if possible
                    });
                    claudeMessages.push({ role: 'user', content: content });
                } else if (message.role === 'assistant' && message.tool_calls?.length) {
                    // Assistant message with tool calls - properly format as tool_use blocks
                    // Claude expects tool_use to be in an 'assistant' message
                    const toolUseBlocks = message.tool_calls.map(tc => ({
                        type: 'tool_use',
                        id: tc.id,
                        name: tc.function.name,
                        input: safeParseJSON(tc.function.arguments)
                    }));
                    claudeMessages.push({ role: 'assistant', content: toolUseBlocks });
                } else {
                    // Regular user or assistant message (text and multimodal)
                    if (typeof message.content === 'string') {
                        if (message.content) {
                            content.push({ type: 'text', text: message.content });
                        }
                    } else if (Array.isArray(message.content)) {
                        message.content.forEach(item => {
                            if (!item) return;
                            switch (item.type) {
                                case 'input_text':
                                    if (item.text) {
                                        content.push({ type: 'text', text: item.text });
                                    }
                                    break;
                                case 'output_text':
                                    if (item.text) {
                                        content.push({ type: 'text', text: item.text });
                                    }
                                    break;
                                case 'image_url':
                                    if (item.image_url) {
                                        const imageUrl = typeof item.image_url === 'string'
                                            ? item.image_url
                                            : item.image_url.url;
                                        if (imageUrl.startsWith('data:')) {
                                            const [header, data] = imageUrl.split(',');
                                            const mediaType = header.match(/data:([^;]+)/)?.[1] || 'image/jpeg';
                                            content.push({
                                                type: 'image',
                                                source: {
                                                    type: 'base64',
                                                    media_type: mediaType,
                                                    data: data
                                                }
                                            });
                                        } else {
                                            // Claude requires base64 for images, so for URLs, we'll represent as text
                                            content.push({ type: 'text', text: `[Image: ${imageUrl}]` });
                                        }
                                    }
                                    break;
                                case 'audio':
                                    // Handle audio content as text placeholder
                                    if (item.audio_url) {
                                        const audioUrl = typeof item.audio_url === 'string'
                                            ? item.audio_url
                                            : item.audio_url.url;
                                        content.push({ type: 'text', text: `[Audio: ${audioUrl}]` });
                                    }
                                    break;
                            }
                        });
                    }
                    // Only add message if content is not empty
                    if (content.length > 0) {
                        claudeMessages.push({ role: role, content: content });
                    }
                }
            }
        }
    } 

    // Process tools if present
    // if (responsesRequest.tools && Array.isArray(responsesRequest.tools)) {
    //     claudeRequest.tools = responsesRequest.tools.map(tool => ({
    //             name: tool.name,
    //             description: tool.description || '',
    //             input_schema: tool.parameters || { type: 'object', properties: {} }
    //         }));
    //     claudeRequest.tool_choice = buildClaudeToolChoice(responsesRequest.tool_choice);
    // }

    // Process messages
    claudeRequest.messages = claudeMessages;
    claudeRequest.stream = responsesRequest.stream || false;
    return claudeRequest;
}

/**
 * Converts an OpenAI Responses API request body to a Gemini API request body.
 * @param {Object} responsesRequest - The request body from the OpenAI Responses API.
 * @returns {Object} The formatted request body for the Gemini API.
 */
export function toGeminiRequestFromOpenAIResponses(responsesRequest) {
    // The OpenAI Responses API uses input and instructions instead of messages
    const geminiRequest = {
        contents: []
    };

    // Process instructions as system instruction
    if (responsesRequest.instructions) {
        let instructionsText = '';
        if (typeof responsesRequest.instructions === 'string') {
            instructionsText = responsesRequest.instructions;
        } else {
            instructionsText = JSON.stringify(responsesRequest.instructions);
        }
        geminiRequest.systemInstruction = {
            parts: [{ text: instructionsText }]
        };
    }

    // Process input as user content
    if (responsesRequest.input) {
        let inputContent = '';
        if (typeof responsesRequest.input === 'string') {
            inputContent = responsesRequest.input;
        } else if (Array.isArray(responsesRequest.input)) {
            // Handle array of messages or items
            if (responsesRequest.input.length > 0) {
                // For compatibility, take the content of the last item with text content
                const lastInputItem = [...responsesRequest.input].reverse().find(item =>
                    item && (
                        (item.content && typeof item.content === 'string') ||
                        (item.content && Array.isArray(item.content) && item.content.some(c => c && c.text)) ||
                        (item.role === 'user' && item.content)
                    )
                );

                if (lastInputItem) {
                    if (typeof lastInputItem.content === 'string') {
                        inputContent = lastInputItem.content;
                    } else if (Array.isArray(lastInputItem.content)) {
                        // Process array of content blocks
                        inputContent = lastInputItem.content
                            .filter(block => block && block.text)
                            .map(block => block.text)
                            .join(' ');
                    } else {
                        // General fallback
                        inputContent = JSON.stringify(lastInputItem.content || lastInputItem);
                    }
                }
            }
        }

        if (inputContent) {
            // Add user message with the input content
            geminiRequest.contents.push({
                role: 'user',
                parts: [{ text: inputContent }]
            });
        }
    } else {
        // If no input is provided, ensure we have at least one user message for Gemini
        geminiRequest.contents.push({
            role: 'user',
            parts: [{ text: 'Hello' }]  // Default content to satisfy Gemini API requirement
        });
    }

    // Add generation config
    const generationConfig = {};
    generationConfig.maxOutputTokens = checkAndAssignOrDefault(responsesRequest.max_tokens, DEFAULT_GEMINI_MAX_TOKENS);
    generationConfig.temperature = checkAndAssignOrDefault(responsesRequest.temperature, DEFAULT_TEMPERATURE);
    generationConfig.topP = checkAndAssignOrDefault(responsesRequest.top_p, DEFAULT_TOP_P);

    if (Object.keys(generationConfig).length > 0) {
        geminiRequest.generationConfig = generationConfig;
    }

    // Process tools if present
    if (responsesRequest.tools && Array.isArray(responsesRequest.tools)) {
        geminiRequest.tools = [{
            functionDeclarations: responsesRequest.tools
                .filter(tool => tool && (tool.type === 'function' || tool.function))
                .map(tool => {
                    const func = tool.function || tool;
                    return {
                        name: String(func.name || tool.name || ''),
                        description: String(func.description || tool.description || ''),
                        parameters: func.parameters || tool.parameters || { type: 'object', properties: {} }
                    };
                }).filter(Boolean) // Filter out any invalid tools
        }];

        // If no valid functionDeclarations, remove the tools array
        if (geminiRequest.tools[0].functionDeclarations.length === 0) {
            delete geminiRequest.tools;
        }
    }

    return geminiRequest;
}

/**
 * Converts a Claude API stream chunk to an OpenAI Responses API stream chunk.
 * @param {Object} claudeChunk - The Claude API stream chunk object.
 * @param {string} [model] - Optional model name to include in the response.
 * @param {string} [requestId] - Optional request ID to maintain stream state across chunks.
 * @returns {Array} The formatted OpenAI Responses API stream chunks as an array of events.
 */
export function toOpenAIResponsesStreamChunkFromClaude(claudeChunk, model, requestId = null) {
    if (!claudeChunk) {
        return [];
    }

    // 如果没有提供requestId，则生成一个（首次调用时）
    const id = requestId || Date.now().toString();

    // 设置模型信息（仅在新请求时设置）
    if (!requestId) {
        streamStateManager.setModel(id, model);
    }

    // Handle text content from Claude stream
    let content = '';
    if (typeof claudeChunk === 'string') {
        content = claudeChunk;
    } else if (claudeChunk && typeof claudeChunk === 'object' && claudeChunk.delta?.text) {
        content = claudeChunk.delta.text;
    } else if (claudeChunk && typeof claudeChunk === 'object') {
        content = claudeChunk;
    }

    // 对于第一个数据块（fullText为空），生成开始事件
    const state = streamStateManager.getOrCreateState(id);
    if (state.fullText === '' && !requestId) { // 只在首次调用时（未指定requestId时）生成开始事件
        // 在这种情况下，我们需要先添加内容到状态
        state.fullText = content;
        return [
            // ...getOpenAIResponsesStreamChunkBegin(id, model),
            generateOutputTextDelta(id, content),
            // ...getOpenAIResponsesStreamChunkEnd(id)
        ];
    } else if (content === '') {
        // 如果是结束块，生成结束事件
        const doneEvents = getOpenAIResponsesStreamChunkEnd(id);

        // 清理状态
        streamStateManager.cleanup(id);

        return doneEvents;
    } else {
        // 中间数据块，只返回delta事件，但也要更新状态
        streamStateManager.updateText(id, content);
        return [
            generateOutputTextDelta(id, content)
        ];
    }
}

/**
 * Converts a Gemini API stream chunk to an OpenAI Responses API stream chunk.
 * @param {Object} geminiChunk - The Gemini API stream chunk object.
 * @param {string} [model] - Optional model name to include in the response.
 * @param {string} [requestId] - Optional request ID to maintain stream state across chunks.
 * @returns {Array} The formatted OpenAI Responses API stream chunks as an array of events.
 */
export function toOpenAIResponsesStreamChunkFromGemini(geminiChunk, model, requestId = null) {
    if (!geminiChunk) {
        return [];
    }

    // 如果没有提供requestId，则生成一个（首次调用时）
    const id = requestId || Date.now().toString();

    // 设置模型信息（仅在新请求时设置）
    if (!requestId) {
        streamStateManager.setModel(id, model);
    }

    // Handle text content in stream
    let content = '';
    if (typeof geminiChunk === 'string') {
        content = geminiChunk;
    } else if (geminiChunk && typeof geminiChunk === 'object') {
        // Extract content from Gemini chunk if it's an object
        content = geminiChunk.content || geminiChunk.text || geminiChunk;
    }

    // 对于第一个数据块（fullText为空），生成开始事件
    const state = streamStateManager.getOrCreateState(id);
    if (state.fullText === '' && !requestId) { // 只在首次调用时（未指定requestId时）生成开始事件
        // 在这种情况下，我们需要先添加内容到状态
        state.fullText = content;
        return [
            // ...getOpenAIResponsesStreamChunkBegin(id, model),
            generateOutputTextDelta(id, content),
            // ...getOpenAIResponsesStreamChunkEnd(id)
        ];
    } else if (content === '') {
        // 如果是结束块，生成结束事件
        const doneEvents = getOpenAIResponsesStreamChunkEnd(id);

        // 清理状态
        streamStateManager.cleanup(id);

        return doneEvents;
    } else {
        // 中间数据块，只返回delta事件，但也要更新状态
        streamStateManager.updateText(id, content);
        return [
            generateOutputTextDelta(id, content)
        ];
    }
}

export function getOpenAIStreamChunkStop(model) {
    return {
        id: `chatcmpl-${uuidv4()}`, // uuidv4 needs to be imported or handled
        object: "chat.completion.chunk",
        created: Math.floor(Date.now() / 1000),
        model: model,
        system_fingerprint: "",
        choices: [{
            index: 0,
            delta: { 
                content: "",
                reasoning_content: ""
            },
            finish_reason: 'stop',
            message: {
                content: "",
                reasoning_content: ""
            }
        }],
        usage:{
            prompt_tokens: 0,
            completion_tokens: 0,
            total_tokens: 0,
        },
    };
}

export function  getOpenAIResponsesStreamChunkBegin(id, model){

    return [
        generateResponseCreated(id, model),
        generateResponseInProgress(id),
        generateOutputItemAdded(id),
        generateContentPartAdded(id)
    ];
}

export function  getOpenAIResponsesStreamChunkEnd(id){

    return [
        generateOutputTextDone(id),
        generateContentPartDone(id),
        generateOutputItemDone(id),
        generateResponseCompleted(id)
    ];
}