"use strict";
/**
 * Real Chat Service
 * Integrates with LLM Gateway and manages real chat conversations
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.chatService = exports.ChatService = void 0;
class ChatService {
    constructor(config = {}) {
        this.conversations = new Map();
        this.currentConversationId = null;
        this.config = {
            apiBaseUrl: process.env.REACT_APP_LLM_GATEWAY_URL || 'http://localhost:3000',
            timeout: 30000,
            enableStreaming: true,
            ...config
        };
    }
    /**
     * Send a message to the AI model
     */
    async sendMessage(content, model, conversationId) {
        const targetModel = model || this.config.defaultModel || 'gpt-4';
        const sessionId = conversationId || this.currentConversationId || this.createConversation(targetModel);
        const userMessage = {
            id: this.generateId(),
            role: 'user',
            content,
            timestamp: new Date()
        };
        // Add user message to conversation
        this.addMessageToConversation(sessionId, userMessage);
        try {
            const conversation = this.conversations.get(sessionId);
            if (!conversation) {
                throw new Error('Conversation not found');
            }
            const response = await fetch(`${this.config.apiBaseUrl}/v1/chat/completions`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${this.config.apiKey}`,
                    'X-Request-ID': this.generateId()
                },
                body: JSON.stringify({
                    model: targetModel,
                    messages: conversation.messages.map(msg => ({
                        role: msg.role,
                        content: msg.content
                    })),
                    stream: false, // For now, handle streaming separately
                    max_tokens: 2048,
                    temperature: 0.7
                }),
                signal: AbortSignal.timeout(this.config.timeout)
            });
            if (!response.ok) {
                const errorData = await response.json().catch(() => ({}));
                throw new Error(`API Error: ${response.status} - ${errorData.message || 'Unknown error'}`);
            }
            const data = await response.json();
            const choice = data.choices?.[0];
            if (!choice) {
                throw new Error('No response from AI model');
            }
            const assistantMessage = {
                id: this.generateId(),
                role: 'assistant',
                content: choice.message.content,
                timestamp: new Date(),
                metadata: {
                    model: targetModel,
                    provider: this.getProviderFromModel(targetModel),
                    tokens: data.usage?.total_tokens
                }
            };
            // Add assistant message to conversation
            this.addMessageToConversation(sessionId, assistantMessage);
            return {
                id: data.id || this.generateId(),
                message: assistantMessage,
                usage: data.usage ? {
                    inputTokens: data.usage.prompt_tokens,
                    outputTokens: data.usage.completion_tokens,
                    totalTokens: data.usage.total_tokens,
                    cost: this.calculateCost(data.usage, targetModel)
                } : undefined,
                model: targetModel,
                provider: this.getProviderFromModel(targetModel),
                finishReason: choice.finish_reason || 'stop'
            };
        }
        catch (error) {
            console.error('Error sending message:', error);
            // Add error message to conversation
            const errorMessage = {
                id: this.generateId(),
                role: 'assistant',
                content: `Sorry, I encountered an error: ${error instanceof Error ? error.message : 'Unknown error'}`,
                timestamp: new Date(),
                metadata: {
                    error: true,
                    model: targetModel
                }
            };
            this.addMessageToConversation(sessionId, errorMessage);
            throw error;
        }
    }
    /**
     * Send a streaming message
     */
    async *sendStreamingMessage(content, model, conversationId) {
        const targetModel = model || this.config.defaultModel || 'gpt-4';
        const sessionId = conversationId || this.currentConversationId || this.createConversation(targetModel);
        const userMessage = {
            id: this.generateId(),
            role: 'user',
            content,
            timestamp: new Date()
        };
        this.addMessageToConversation(sessionId, userMessage);
        try {
            const conversation = this.conversations.get(sessionId);
            if (!conversation) {
                throw new Error('Conversation not found');
            }
            const response = await fetch(`${this.config.apiBaseUrl}/v1/chat/completions`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${this.config.apiKey}`,
                    'Accept': 'text/event-stream'
                },
                body: JSON.stringify({
                    model: targetModel,
                    messages: conversation.messages.map(msg => ({
                        role: msg.role,
                        content: msg.content
                    })),
                    stream: true,
                    max_tokens: 2048,
                    temperature: 0.7
                })
            });
            if (!response.ok) {
                throw new Error(`Streaming API Error: ${response.status}`);
            }
            const reader = response.body?.getReader();
            if (!reader) {
                throw new Error('No response stream available');
            }
            const decoder = new TextDecoder();
            let accumulatedContent = '';
            try {
                while (true) {
                    const { done, value } = await reader.read();
                    if (done) {
                        // Add final message to conversation
                        const assistantMessage = {
                            id: this.generateId(),
                            role: 'assistant',
                            content: accumulatedContent,
                            timestamp: new Date(),
                            metadata: {
                                model: targetModel,
                                provider: this.getProviderFromModel(targetModel),
                                streaming: true
                            }
                        };
                        this.addMessageToConversation(sessionId, assistantMessage);
                        yield { content: accumulatedContent, done: true };
                        break;
                    }
                    const chunk = decoder.decode(value);
                    const lines = chunk.split('\n');
                    for (const line of lines) {
                        if (line.startsWith('data: ')) {
                            const data = line.slice(6);
                            if (data === '[DONE]') {
                                yield { content: accumulatedContent, done: true };
                                return;
                            }
                            try {
                                const parsed = JSON.parse(data);
                                const content = parsed.choices?.[0]?.delta?.content;
                                if (content) {
                                    accumulatedContent += content;
                                    yield { content: accumulatedContent, done: false };
                                }
                            }
                            catch (parseError) {
                                // Ignore parse errors for malformed chunks
                                console.warn('Failed to parse streaming chunk:', parseError);
                            }
                        }
                    }
                }
            }
            finally {
                reader.releaseLock();
            }
        }
        catch (error) {
            console.error('Error in streaming message:', error);
            throw error;
        }
    }
    /**
     * Get available models
     */
    async getAvailableModels() {
        try {
            const response = await fetch(`${this.config.apiBaseUrl}/v1/models`, {
                headers: {
                    'Authorization': `Bearer ${this.config.apiKey}`
                }
            });
            if (!response.ok) {
                throw new Error(`Failed to fetch models: ${response.status}`);
            }
            const data = await response.json();
            return data.data?.map((model) => ({
                id: model.id,
                name: model.name || model.id,
                provider: this.getProviderFromModel(model.id),
                capabilities: model.capabilities || ['chat'],
                maxTokens: model.max_tokens || 4096,
                pricing: model.pricing
            })) || [];
        }
        catch (error) {
            console.error('Error fetching models:', error);
            // Return default models as fallback
            return [
                {
                    id: 'gpt-4',
                    name: 'GPT-4',
                    provider: 'OpenAI',
                    capabilities: ['chat', 'completion'],
                    maxTokens: 8192
                },
                {
                    id: 'gpt-3.5-turbo',
                    name: 'GPT-3.5 Turbo',
                    provider: 'OpenAI',
                    capabilities: ['chat', 'completion'],
                    maxTokens: 4096
                }
            ];
        }
    }
    /**
     * Create a new conversation
     */
    createConversation(model, title) {
        const id = this.generateId();
        const conversation = {
            id,
            title: title || `Conversation ${new Date().toLocaleDateString()}`,
            messages: [],
            model,
            createdAt: new Date(),
            updatedAt: new Date(),
            metadata: {}
        };
        this.conversations.set(id, conversation);
        this.currentConversationId = id;
        return id;
    }
    /**
     * Get a conversation by ID
     */
    getConversation(id) {
        return this.conversations.get(id) || null;
    }
    /**
     * Get all conversations
     */
    getAllConversations() {
        return Array.from(this.conversations.values()).sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
    }
    /**
     * Set current conversation
     */
    setCurrentConversation(id) {
        if (this.conversations.has(id)) {
            this.currentConversationId = id;
        }
    }
    /**
     * Delete a conversation
     */
    deleteConversation(id) {
        const deleted = this.conversations.delete(id);
        if (this.currentConversationId === id) {
            this.currentConversationId = null;
        }
        return deleted;
    }
    /**
     * Clear all conversations
     */
    clearConversations() {
        this.conversations.clear();
        this.currentConversationId = null;
    }
    /**
     * Export conversation to various formats
     */
    exportConversation(id, format = 'json') {
        const conversation = this.conversations.get(id);
        if (!conversation) {
            throw new Error('Conversation not found');
        }
        switch (format) {
            case 'markdown':
                return this.exportToMarkdown(conversation);
            case 'txt':
                return this.exportToText(conversation);
            default:
                return JSON.stringify(conversation, null, 2);
        }
    }
    /**
     * Get conversation statistics
     */
    getConversationStats(id) {
        const conversation = this.conversations.get(id);
        if (!conversation) {
            return null;
        }
        const messageCount = conversation.messages.length;
        const totalTokens = conversation.messages.reduce((sum, msg) => sum + (msg.metadata?.tokens || 0), 0);
        const estimatedCost = this.calculateConversationCost(conversation);
        const duration = conversation.updatedAt.getTime() - conversation.createdAt.getTime();
        return { messageCount, totalTokens, estimatedCost, duration };
    }
    /**
     * Private helper methods
     */
    addMessageToConversation(conversationId, message) {
        const conversation = this.conversations.get(conversationId);
        if (conversation) {
            conversation.messages.push(message);
            conversation.updatedAt = new Date();
        }
    }
    generateId() {
        return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    }
    getProviderFromModel(model) {
        if (model.includes('gpt'))
            return 'OpenAI';
        if (model.includes('claude'))
            return 'Anthropic';
        if (model.includes('apple'))
            return 'Apple';
        if (model.includes('gemini') || model.includes('palm'))
            return 'Google';
        return 'Unknown';
    }
    calculateCost(usage, model) {
        // Simple cost calculation - in production, use real pricing data
        const inputCostPer1K = this.getModelInputCost(model);
        const outputCostPer1K = this.getModelOutputCost(model);
        return (usage.prompt_tokens / 1000) * inputCostPer1K +
            (usage.completion_tokens / 1000) * outputCostPer1K;
    }
    calculateConversationCost(conversation) {
        return conversation.messages.reduce((sum, msg) => {
            if (msg.metadata?.tokens) {
                return sum + this.calculateCost({ prompt_tokens: 0, completion_tokens: msg.metadata.tokens }, conversation.model);
            }
            return sum;
        }, 0);
    }
    getModelInputCost(model) {
        const costs = {
            'gpt-4': 0.03,
            'gpt-4-turbo': 0.01,
            'gpt-3.5-turbo': 0.0015,
            'claude-3-opus': 0.015,
            'claude-3-sonnet': 0.003
        };
        return costs[model] || 0.01;
    }
    getModelOutputCost(model) {
        const costs = {
            'gpt-4': 0.06,
            'gpt-4-turbo': 0.03,
            'gpt-3.5-turbo': 0.002,
            'claude-3-opus': 0.075,
            'claude-3-sonnet': 0.015
        };
        return costs[model] || 0.02;
    }
    exportToMarkdown(conversation) {
        const header = `# ${conversation.title}\n\n**Model:** ${conversation.model}\n**Created:** ${conversation.createdAt.toLocaleString()}\n\n---\n\n`;
        const messages = conversation.messages.map(msg => {
            const role = msg.role === 'user' ? '**You:**' : '**Assistant:**';
            return `${role}\n${msg.content}\n\n`;
        }).join('');
        return header + messages;
    }
    exportToText(conversation) {
        const header = `${conversation.title}\nModel: ${conversation.model}\nCreated: ${conversation.createdAt.toLocaleString()}\n\n`;
        const messages = conversation.messages.map(msg => {
            const role = msg.role === 'user' ? 'You:' : 'Assistant:';
            return `${role}\n${msg.content}\n\n`;
        }).join('');
        return header + messages;
    }
}
exports.ChatService = ChatService;
// Export singleton instance
exports.chatService = new ChatService();
exports.default = exports.chatService;
//# sourceMappingURL=ChatService.js.map