"use strict";
/**
 * useAIConversation Hook - Advanced AI conversation management
 * Features: Message persistence, provider switching, context management
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.useAIConversation = void 0;
const react_1 = require("react");
const uuid_1 = require("uuid");
// Default local storage persistence adapter
class LocalStoragePersistenceAdapter {
    constructor() {
        this.prefix = 'ai-conversation-';
    }
    async save(conversation) {
        try {
            const data = JSON.stringify(conversation, (key, value) => {
                if (value instanceof Date) {
                    return { __type: 'Date', value: value.toISOString() };
                }
                return value;
            });
            localStorage.setItem(`${this.prefix}${conversation.id}`, data);
        }
        catch (error) {
            console.error('Failed to save conversation:', error);
        }
    }
    async load(conversationId) {
        try {
            const data = localStorage.getItem(`${this.prefix}${conversationId}`);
            if (!data)
                return null;
            return JSON.parse(data, (key, value) => {
                if (value && typeof value === 'object' && value.__type === 'Date') {
                    return new Date(value.value);
                }
                return value;
            });
        }
        catch (error) {
            console.error('Failed to load conversation:', error);
            return null;
        }
    }
    async delete(conversationId) {
        localStorage.removeItem(`${this.prefix}${conversationId}`);
    }
    async list() {
        const conversations = [];
        for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            if (key && key.startsWith(this.prefix)) {
                const conversationId = key.replace(this.prefix, '');
                const conversation = await this.load(conversationId);
                if (conversation) {
                    conversations.push(conversation);
                }
            }
        }
        return conversations.sort((a, b) => (b.metadata?.updatedAt?.getTime() || 0) - (a.metadata?.updatedAt?.getTime() || 0));
    }
}
const useAIConversation = ({ conversationId, initialConversation, provider = 'auto', model = 'auto', onConversationUpdated, onMessageSent, onError, autoSave = true, maxMessages = 100, persistenceAdapter = new LocalStoragePersistenceAdapter() } = {}) => {
    const [conversation, setConversation] = (0, react_1.useState)(null);
    const [isLoading, setIsLoading] = (0, react_1.useState)(false);
    const [error, setError] = (0, react_1.useState)(null);
    const [currentProvider, setCurrentProvider] = (0, react_1.useState)(provider);
    const [currentModel, setCurrentModel] = (0, react_1.useState)(model);
    const conversationRef = (0, react_1.useRef)(null);
    const abortControllerRef = (0, react_1.useRef)(null);
    // Update ref when conversation changes
    (0, react_1.useEffect)(() => {
        conversationRef.current = conversation;
    }, [conversation]);
    // Initialize conversation
    (0, react_1.useEffect)(() => {
        const initializeConversation = async () => {
            try {
                let loadedConversation = null;
                // Try to load existing conversation
                if (conversationId) {
                    loadedConversation = await persistenceAdapter.load(conversationId);
                }
                // Create new conversation if none exists
                if (!loadedConversation) {
                    const newId = conversationId || (0, uuid_1.v4)();
                    loadedConversation = {
                        id: newId,
                        title: initialConversation?.title || 'New Conversation',
                        messages: initialConversation?.messages || [],
                        participants: [
                            {
                                id: 'user',
                                name: 'User',
                                role: 'user',
                                isActive: true
                            },
                            {
                                id: 'ai',
                                name: 'AI Assistant',
                                role: 'ai',
                                isActive: true
                            },
                            ...(initialConversation?.participants || [])
                        ],
                        context: initialConversation?.context,
                        settings: {
                            allowVoice: true,
                            enableCollaboration: true,
                            showContext: true,
                            autoSave: autoSave,
                            theme: 'system',
                            aiProvider: currentProvider,
                            aiModel: currentModel,
                            ...initialConversation?.settings
                        },
                        metadata: {
                            createdAt: new Date(),
                            updatedAt: new Date(),
                            version: 1,
                            tokensUsed: 0,
                            totalCost: 0,
                            ...initialConversation?.metadata
                        }
                    };
                }
                setConversation(loadedConversation);
                onConversationUpdated?.(loadedConversation);
            }
            catch (err) {
                const error = err instanceof Error ? err : new Error('Failed to initialize conversation');
                setError(error.message);
                onError?.(error);
            }
        };
        initializeConversation();
    }, [conversationId, initialConversation, currentProvider, currentModel, autoSave, persistenceAdapter, onConversationUpdated, onError]);
    // Auto-save conversation
    (0, react_1.useEffect)(() => {
        if (conversation && autoSave) {
            const saveTimeout = setTimeout(async () => {
                try {
                    await persistenceAdapter.save(conversation);
                }
                catch (err) {
                    console.error('Auto-save failed:', err);
                }
            }, 1000);
            return () => clearTimeout(saveTimeout);
        }
    }, [conversation, autoSave, persistenceAdapter]);
    // Update conversation helper
    const updateConversation = (0, react_1.useCallback)((updates) => {
        setConversation(prev => {
            if (!prev)
                return null;
            const updated = {
                ...prev,
                ...updates,
                metadata: {
                    ...prev.metadata,
                    ...updates.metadata,
                    updatedAt: new Date(),
                    version: (prev.metadata?.version || 0) + 1
                }
            };
            onConversationUpdated?.(updated);
            return updated;
        });
    }, [onConversationUpdated]);
    // Send message to AI
    const sendMessage = (0, react_1.useCallback)(async (messageData) => {
        if (!conversation) {
            throw new Error('No active conversation');
        }
        setIsLoading(true);
        setError(null);
        // Cancel any ongoing request
        abortControllerRef.current?.abort();
        abortControllerRef.current = new AbortController();
        try {
            // Create user message
            const userMessage = {
                id: messageData.id || (0, uuid_1.v4)(),
                role: messageData.role || 'user',
                content: messageData.content || '',
                timestamp: messageData.timestamp || new Date(),
                metadata: messageData.metadata,
                attachments: messageData.attachments,
                reactions: {},
                isStreaming: false,
                isEditing: false
            };
            // Add user message to conversation
            const updatedMessages = [...conversation.messages, userMessage];
            updateConversation({ messages: updatedMessages });
            // Trigger message sent callback
            onMessageSent?.(userMessage);
            // Simulate AI response (in real implementation, call actual AI service)
            const aiResponse = await generateAIResponse(updatedMessages, currentProvider, currentModel, abortControllerRef.current.signal);
            // Add AI response to conversation
            const finalMessages = [...updatedMessages, aiResponse];
            updateConversation({
                messages: finalMessages,
                metadata: {
                    tokensUsed: (conversation.metadata?.tokensUsed || 0) + (aiResponse.metadata?.tokens || 0),
                    totalCost: (conversation.metadata?.totalCost || 0) + (aiResponse.metadata?.cost || 0)
                }
            });
            return userMessage;
        }
        catch (err) {
            if (err instanceof Error && err.name === 'AbortError') {
                throw new Error('Request was cancelled');
            }
            const error = err instanceof Error ? err : new Error('Failed to send message');
            setError(error.message);
            onError?.(error);
            throw error;
        }
        finally {
            setIsLoading(false);
        }
    }, [conversation, currentProvider, currentModel, onMessageSent, onError, updateConversation]);
    // Edit existing message
    const editMessage = (0, react_1.useCallback)(async (messageId, content) => {
        if (!conversation)
            return;
        const messageIndex = conversation.messages.findIndex(m => m.id === messageId);
        if (messageIndex === -1)
            return;
        const updatedMessages = [...conversation.messages];
        updatedMessages[messageIndex] = {
            ...updatedMessages[messageIndex],
            content,
            metadata: {
                ...updatedMessages[messageIndex].metadata,
                editedAt: new Date()
            }
        };
        updateConversation({ messages: updatedMessages });
    }, [conversation, updateConversation]);
    // Delete message
    const deleteMessage = (0, react_1.useCallback)(async (messageId) => {
        if (!conversation)
            return;
        const updatedMessages = conversation.messages.filter(m => m.id !== messageId);
        updateConversation({ messages: updatedMessages });
    }, [conversation, updateConversation]);
    // Clear conversation
    const clearConversation = (0, react_1.useCallback)(async () => {
        if (!conversation)
            return;
        updateConversation({
            messages: [],
            metadata: {
                tokensUsed: 0,
                totalCost: 0
            }
        });
    }, [conversation, updateConversation]);
    // Regenerate AI message
    const regenerateMessage = (0, react_1.useCallback)(async (messageId) => {
        if (!conversation) {
            throw new Error('No active conversation');
        }
        const messageIndex = conversation.messages.findIndex(m => m.id === messageId);
        if (messageIndex === -1 || conversation.messages[messageIndex].role !== 'assistant') {
            throw new Error('Invalid message for regeneration');
        }
        setIsLoading(true);
        setError(null);
        try {
            // Get messages up to the point before the message to regenerate
            const contextMessages = conversation.messages.slice(0, messageIndex);
            // Generate new AI response
            const newResponse = await generateAIResponse(contextMessages, currentProvider, currentModel);
            // Replace the message
            const updatedMessages = [...conversation.messages];
            updatedMessages[messageIndex] = newResponse;
            updateConversation({ messages: updatedMessages });
            return newResponse;
        }
        catch (err) {
            const error = err instanceof Error ? err : new Error('Failed to regenerate message');
            setError(error.message);
            onError?.(error);
            throw error;
        }
        finally {
            setIsLoading(false);
        }
    }, [conversation, currentProvider, currentModel, onError, updateConversation]);
    // Fork conversation from a specific message
    const forkConversation = (0, react_1.useCallback)(async (fromMessageId) => {
        if (!conversation) {
            throw new Error('No active conversation to fork');
        }
        let messagesToInclude = conversation.messages;
        if (fromMessageId) {
            const messageIndex = conversation.messages.findIndex(m => m.id === fromMessageId);
            if (messageIndex !== -1) {
                messagesToInclude = conversation.messages.slice(0, messageIndex + 1);
            }
        }
        const forkedConversation = {
            ...conversation,
            id: (0, uuid_1.v4)(),
            title: `${conversation.title} (Fork)`,
            messages: messagesToInclude,
            metadata: {
                ...conversation.metadata,
                createdAt: new Date(),
                updatedAt: new Date(),
                version: 1,
                parentConversationId: conversation.id
            }
        };
        await persistenceAdapter.save(forkedConversation);
        return forkedConversation;
    }, [conversation, persistenceAdapter]);
    // Export conversation
    const exportConversation = (0, react_1.useCallback)(async (format) => {
        if (!conversation) {
            throw new Error('No conversation to export');
        }
        switch (format) {
            case 'json':
                return JSON.stringify(conversation, null, 2);
            case 'markdown':
                return exportToMarkdown(conversation);
            case 'pdf':
                return await exportToPDF(conversation);
            default:
                throw new Error(`Unsupported export format: ${format}`);
        }
    }, [conversation]);
    // Import conversation
    const importConversation = (0, react_1.useCallback)(async (data) => {
        try {
            let conversationData;
            if (data instanceof File) {
                conversationData = await data.text();
            }
            else {
                conversationData = data;
            }
            const parsed = JSON.parse(conversationData, (key, value) => {
                if (value && typeof value === 'object' && value.__type === 'Date') {
                    return new Date(value.value);
                }
                return value;
            });
            // Validate imported data
            if (!parsed.id || !parsed.messages || !Array.isArray(parsed.messages)) {
                throw new Error('Invalid conversation format');
            }
            const importedConversation = {
                ...parsed,
                id: (0, uuid_1.v4)(), // Generate new ID to avoid conflicts
                metadata: {
                    ...parsed.metadata,
                    importedAt: new Date(),
                    originalId: parsed.id
                }
            };
            await persistenceAdapter.save(importedConversation);
            setConversation(importedConversation);
            return importedConversation;
        }
        catch (err) {
            const error = err instanceof Error ? err : new Error('Failed to import conversation');
            setError(error.message);
            onError?.(error);
            throw error;
        }
    }, [persistenceAdapter, onError]);
    // Switch AI provider/model
    const switchProvider = (0, react_1.useCallback)((newProvider, newModel) => {
        setCurrentProvider(newProvider);
        if (newModel) {
            setCurrentModel(newModel);
        }
        if (conversation) {
            updateConversation({
                settings: {
                    ...conversation.settings,
                    aiProvider: newProvider,
                    aiModel: newModel || currentModel
                }
            });
        }
    }, [conversation, currentModel, updateConversation]);
    // Get conversation statistics
    const getConversationStats = (0, react_1.useCallback)(() => {
        if (!conversation) {
            return {
                messageCount: 0,
                totalTokens: 0,
                totalCost: 0,
                avgResponseTime: 0,
                providerUsage: {},
                topicDistribution: []
            };
        }
        const messageCount = conversation.messages.length;
        const totalTokens = conversation.metadata?.tokensUsed || 0;
        const totalCost = conversation.metadata?.totalCost || 0;
        // Calculate average response time
        const responseTimes = conversation.messages
            .filter(m => m.metadata?.latency)
            .map(m => m.metadata.latency);
        const avgResponseTime = responseTimes.length > 0
            ? responseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length
            : 0;
        // Calculate provider usage
        const providerUsage = {};
        conversation.messages.forEach(message => {
            if (message.metadata?.provider) {
                providerUsage[message.metadata.provider] = (providerUsage[message.metadata.provider] || 0) + 1;
            }
        });
        // Calculate topic distribution (simplified)
        const topicDistribution = extractTopics(conversation.messages);
        return {
            messageCount,
            totalTokens,
            totalCost,
            avgResponseTime,
            providerUsage,
            topicDistribution
        };
    }, [conversation]);
    return {
        conversation,
        messages: conversation?.messages || [],
        isLoading,
        error,
        sendMessage,
        editMessage,
        deleteMessage,
        clearConversation,
        regenerateMessage,
        forkConversation,
        exportConversation,
        importConversation,
        switchProvider,
        getConversationStats
    };
};
exports.useAIConversation = useAIConversation;
// Helper functions
async function generateAIResponse(messages, provider, model, signal) {
    // Simulate AI API call (replace with actual implementation)
    await new Promise(resolve => setTimeout(resolve, 1000 + Math.random() * 2000));
    if (signal?.aborted) {
        throw new Error('Request aborted');
    }
    const responses = [
        "I understand your question. Let me help you with that.",
        "That's an interesting point. Here's what I think about it.",
        "Based on the information provided, I can suggest the following approach.",
        "Let me break this down for you step by step.",
        "I see what you're asking. Here's a comprehensive answer."
    ];
    const response = responses[Math.floor(Math.random() * responses.length)];
    const tokens = Math.floor(response.length / 4);
    const cost = tokens * 0.00002; // Simplified cost calculation
    return {
        id: (0, uuid_1.v4)(),
        role: 'assistant',
        content: response,
        timestamp: new Date(),
        metadata: {
            model,
            provider,
            tokens,
            cost,
            latency: 1000 + Math.random() * 2000,
            confidence: 0.8 + Math.random() * 0.2
        },
        reactions: {},
        isStreaming: false,
        isEditing: false
    };
}
function exportToMarkdown(conversation) {
    let markdown = `# ${conversation.title}\n\n`;
    markdown += `**Created:** ${conversation.metadata?.createdAt?.toLocaleString()}\n`;
    markdown += `**Last Updated:** ${conversation.metadata?.updatedAt?.toLocaleString()}\n\n`;
    conversation.messages.forEach(message => {
        markdown += `## ${message.role.charAt(0).toUpperCase() + message.role.slice(1)}\n`;
        markdown += `*${message.timestamp.toLocaleString()}*\n\n`;
        markdown += `${message.content}\n\n`;
        if (message.metadata) {
            markdown += `*Model: ${message.metadata.model || 'unknown'}, `;
            markdown += `Tokens: ${message.metadata.tokens || 0}, `;
            markdown += `Cost: $${(message.metadata.cost || 0).toFixed(4)}*\n\n`;
        }
    });
    return markdown;
}
async function exportToPDF(conversation) {
    // Simplified PDF export (in real implementation, use a PDF library)
    const content = exportToMarkdown(conversation);
    return new Blob([content], { type: 'application/pdf' });
}
function extractTopics(messages) {
    // Simplified topic extraction
    const content = messages.map(m => m.content).join(' ');
    const words = content.toLowerCase().split(/\s+/);
    const wordCounts = {};
    words.forEach(word => {
        if (word.length > 3) {
            wordCounts[word] = (wordCounts[word] || 0) + 1;
        }
    });
    return Object.entries(wordCounts)
        .sort(([, a], [, b]) => b - a)
        .slice(0, 10)
        .map(([topic, count]) => ({
        topic,
        weight: count / words.length
    }));
}
exports.default = exports.useAIConversation;
//# sourceMappingURL=useAIConversation.js.map