import { ModelRegistry } from "../../models/ModelRegistry.js";
import { logger } from "../../utils/logger.js";
import { handleDeepSeekError } from "./Errors.js";
import { mapSystemMessages } from "../utils.js";
import { fetchWithTimeout } from "../../utils/fetch.js";
export class DeepSeekChat {
    baseUrl;
    apiKey;
    constructor(baseUrl, apiKey) {
        this.baseUrl = baseUrl;
        this.apiKey = apiKey;
    }
    async execute(request) {
        const { model, messages, tools, max_tokens, response_format, thinking: _thinking, headers: _headers, requestTimeout, ...rest } = request;
        const mappedMessages = mapSystemMessages(messages, false);
        const body = {
            model,
            messages: mappedMessages,
            ...rest
        };
        if (max_tokens)
            body.max_tokens = max_tokens;
        if (tools && tools.length > 0)
            body.tools = tools;
        if (max_tokens)
            body.max_tokens = max_tokens;
        if (tools && tools.length > 0)
            body.tools = tools;
        // Handle structured output for DeepSeek
        if (response_format) {
            if (response_format.type === "json_schema") {
                body.response_format = { type: "json_object" };
                // Append schema instructions to the system prompt or convert to a new system message
                const schema = response_format.json_schema;
                const schemaString = JSON.stringify(schema?.schema, null, 2);
                const instruction = `\n\nIMPORTANT: You must output strictly valid JSON conforming to the following schema:\n${schemaString}\n\nOutput only the JSON object.`;
                // Find system message or append to last user message
                const messagesList = body.messages;
                const systemMessage = messagesList.find((m) => m.role === "system" || m.role === "developer");
                if (systemMessage) {
                    systemMessage.content += instruction;
                }
                else {
                    // Insert system message at the beginning
                    messagesList.unshift({
                        role: "system",
                        content: "You are a helpful assistant." + instruction
                    });
                }
            }
            else {
                body.response_format = response_format;
            }
        }
        const url = `${this.baseUrl}/chat/completions`;
        logger.logRequest("DeepSeek", "POST", url, body);
        const response = await fetchWithTimeout(url, {
            method: "POST",
            headers: {
                Authorization: `Bearer ${this.apiKey}`,
                "Content-Type": "application/json",
                ...request.headers
            },
            body: JSON.stringify(body)
        }, requestTimeout);
        if (!response.ok) {
            await handleDeepSeekError(response, model);
        }
        const json = (await response.json());
        logger.logResponse("DeepSeek", response.status, response.statusText, json);
        const message = json.choices[0]?.message;
        const content = message?.content ?? null;
        const reasoning = message?.reasoning_content ?? null;
        const usage = {
            input_tokens: json.usage.prompt_tokens,
            output_tokens: json.usage.completion_tokens,
            total_tokens: json.usage.total_tokens
        };
        const toolCalls = message?.tool_calls?.map((tc) => ({
            id: tc.id,
            type: "function",
            function: {
                name: tc.function.name,
                arguments: tc.function.arguments
            }
        }));
        if (!content && !reasoning && (!toolCalls || toolCalls.length === 0)) {
            throw new Error("DeepSeek returned empty response");
        }
        // deepseek cost calculation if needed, otherwise just return usage
        const calculatedUsage = ModelRegistry.calculateCost(usage, model, "deepseek");
        const thinkingResult = reasoning ? { text: reasoning } : undefined;
        return {
            content,
            reasoning,
            usage: calculatedUsage,
            thinking: thinkingResult,
            tool_calls: toolCalls
        };
    }
}
