import * as https from 'https';
import * as http from 'http';
import { ChatMessage, AIConfig, AIResponse, ToolDefinition, ToolCall } from '../common/types';

export class OpenAICompatClient {

    async chat(
        messages: ChatMessage[],
        config: AIConfig,
        tools?: ToolDefinition[],
        onChunk?: (content: string) => void
    ): Promise<AIResponse> {
        const url = new URL(`${config.baseUrl}/v1/chat/completions`);
        const isHttps = url.protocol === 'https:';
        const mod = isHttps ? https : http;

        const bodyObj: Record<string, unknown> = {
            model: config.model,
            messages: messages.map(m => {
                const msg: Record<string, unknown> = { role: m.role, content: m.content };
                if (m.toolCalls && m.toolCalls.length > 0) {
                    msg.tool_calls = m.toolCalls.map(tc => ({
                        id: tc.id,
                        type: 'function',
                        function: { name: tc.name, arguments: tc.arguments }
                    }));
                }
                if (m.toolCallId) {
                    msg.tool_call_id = m.toolCallId;
                }
                if (m.role === 'assistant' && m.reasoningContent) {
                    msg.reasoning_content = m.reasoningContent;
                }
                return msg;
            }),
            max_tokens: config.maxTokens,
            temperature: config.temperature,
            stream: true
        };
        if (tools && tools.length > 0) {
            bodyObj.tools = tools.map(t => ({
                type: 'function',
                function: { name: t.name, description: t.description, parameters: t.parameters }
            }));
        }

        const body = JSON.stringify(bodyObj);

        return new Promise<AIResponse>((resolve, reject) => {
            const req = mod.request(url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${config.apiKey}`,
                    'Accept': 'text/event-stream'
                }
            }, (res) => {
                if (res.statusCode !== 200) {
                    let errBody = '';
                    res.on('data', (chunk: Buffer) => { errBody += chunk.toString(); });
                    res.on('end', () => reject(new Error(`API error ${res.statusCode}: ${errBody}`)));
                    return;
                }

                let fullContent = '';
                let fullReasoningContent = '';
                let buffer = '';
                const toolCallMap = new Map<number, { id: string; name: string; arguments: string }>();

                res.on('data', (chunk: Buffer) => {
                    buffer += chunk.toString();
                    const lines = buffer.split('\n');
                    buffer = lines.pop() || '';

                    for (const line of lines) {
                        const trimmed = line.trim();
                        if (!trimmed || !trimmed.startsWith('data: ')) continue;
                        const data = trimmed.slice(6);
                        if (data === '[DONE]') continue;
                        try {
                            const parsed = JSON.parse(data);
                            const delta = parsed.choices?.[0]?.delta;
                            if (!delta) continue;

                            if (delta.content) {
                                fullContent += delta.content;
                                if (onChunk) onChunk(delta.content);
                            }

                            // Capture reasoning_content from all possible locations
                            const rc = delta.reasoning_content || delta.reasoning ||
                                parsed.choices?.[0]?.reasoning_content || parsed.choices?.[0]?.reasoning;
                            if (rc) fullReasoningContent += rc;

                            if (delta.tool_calls) {
                                for (const tc of delta.tool_calls) {
                                    const idx = tc.index;
                                    if (!toolCallMap.has(idx)) {
                                        toolCallMap.set(idx, { id: tc.id || '', name: '', arguments: '' });
                                    }
                                    const entry = toolCallMap.get(idx)!;
                                    if (tc.id) entry.id = tc.id;
                                    if (tc.function?.name) entry.name = tc.function.name;
                                    if (tc.function?.arguments) entry.arguments += tc.function.arguments;
                                }
                            }
                        } catch { /* skip malformed chunks */ }
                    }
                });

                res.on('end', () => {
                    // Process remaining buffer
                    if (buffer.trim()) {
                        const trimmed = buffer.trim();
                        if (trimmed.startsWith('data: ') && trimmed.slice(6) !== '[DONE]') {
                            try {
                                const parsed = JSON.parse(trimmed.slice(6));
                                const delta = parsed.choices?.[0]?.delta;
                                if (delta?.content) {
                                    fullContent += delta.content;
                                    if (onChunk) onChunk(delta.content);
                                }
                                const rc2 = delta?.reasoning_content || delta?.reasoning ||
                                    parsed.choices?.[0]?.reasoning_content || parsed.choices?.[0]?.reasoning;
                                if (rc2) fullReasoningContent += rc2;
                                if (delta?.tool_calls) {
                                    for (const tc of delta.tool_calls) {
                                        const idx = tc.index;
                                        if (!toolCallMap.has(idx)) {
                                            toolCallMap.set(idx, { id: tc.id || '', name: '', arguments: '' });
                                        }
                                        const entry = toolCallMap.get(idx)!;
                                        if (tc.id) entry.id = tc.id;
                                        if (tc.function?.name) entry.name = tc.function.name;
                                        if (tc.function?.arguments) entry.arguments += tc.function.arguments;
                                    }
                                }
                            } catch { /* skip */ }
                        }
                    }

                    const toolCalls: ToolCall[] = [];
                    for (const entry of toolCallMap.values()) {
                        toolCalls.push({ id: entry.id, name: entry.name, arguments: entry.arguments });
                    }

                    // Log if reasoning_content was found
                    if (fullReasoningContent) {
                        console.log(`[VibeDev] Captured reasoning_content (len=${fullReasoningContent.length})`);
                    }

                    resolve({
                        content: fullContent,
                        toolCalls,
                        reasoningContent: fullReasoningContent || undefined
                    });
                });

                res.on('error', reject);
            });

            req.on('error', reject);
            req.write(body);
            req.end();
        });
    }
}