import { CHAT_ACTIVE_CONVERSATION_ID_KEY } from "./ChatConstants.js";
import { AutopilotChatEvent, AutopilotChatInterceptableEvent, AutopilotChatInternalEvent } from "./ChatModel.js";
import { StorageService } from "./StorageService.js";
class LocalHistoryService {
    static CONVERSATIONS_DB_BASE_NAME = 'autopilot_conversations_db';
    static MESSAGES_DB_BASE_NAME = 'autopilot_messages_db';
    static DB_VERSION = 1;
    static ACTIVE_CONVERSATION_ID = null;
    static CONVERSATIONS_DB_NAME = '';
    static MESSAGES_DB_NAME = '';
    static UNSUBSCRIBE_CALLBACKS = new Map();
    static async getConversationsDb() {
        return new Promise((resolve, reject)=>{
            const request = indexedDB.open(LocalHistoryService.CONVERSATIONS_DB_NAME, LocalHistoryService.DB_VERSION);
            request.onerror = ()=>reject(request.error);
            request.onsuccess = ()=>resolve(request.result);
            request.onupgradeneeded = (event)=>{
                const db = event.target.result;
                if (!db.objectStoreNames.contains('conversations')) db.createObjectStore('conversations');
            };
        });
    }
    static async getMessagesDb() {
        return new Promise((resolve, reject)=>{
            const request = indexedDB.open(LocalHistoryService.MESSAGES_DB_NAME, LocalHistoryService.DB_VERSION);
            request.onerror = ()=>reject(request.error);
            request.onsuccess = ()=>resolve(request.result);
            request.onupgradeneeded = (event)=>{
                const db = event.target.result;
                if (!db.objectStoreNames.contains('messages')) db.createObjectStore('messages');
            };
        });
    }
    static async createConversation(conversationId, conversationName) {
        const db = await LocalHistoryService.getConversationsDb();
        const conversation = await LocalHistoryService.getConversation(conversationId);
        if (conversation) return conversationId;
        const data = {
            id: conversationId,
            name: conversationName,
            timestamp: new Date().toISOString(),
            lastUpdated: Date.now()
        };
        return new Promise((resolve, reject)=>{
            const transaction = db.transaction('conversations', 'readwrite');
            const store = transaction.objectStore('conversations');
            const request = store.put(data, conversationId);
            request.onerror = ()=>reject(request.error);
            request.onsuccess = ()=>resolve(conversationId);
        });
    }
    static async getAllConversations() {
        const db = await LocalHistoryService.getConversationsDb();
        return new Promise((resolve, reject)=>{
            const transaction = db.transaction('conversations', 'readonly');
            const store = transaction.objectStore('conversations');
            const request = store.getAll();
            request.onerror = ()=>reject(request.error);
            request.onsuccess = ()=>resolve(request.result);
        });
    }
    static async getConversation(conversationId) {
        const db = await LocalHistoryService.getConversationsDb();
        return new Promise((resolve, reject)=>{
            const transaction = db.transaction('conversations', 'readonly');
            const store = transaction.objectStore('conversations');
            const request = store.get(conversationId);
            request.onerror = ()=>reject(request.error);
            request.onsuccess = ()=>resolve(request.result || null);
        });
    }
    static async saveMessage(conversationId, message) {
        const db = await LocalHistoryService.getMessagesDb();
        const data = {
            conversationId,
            ...message
        };
        return new Promise((resolve, reject)=>{
            const transaction = db.transaction('messages', 'readwrite');
            const store = transaction.objectStore('messages');
            const request = store.put(data, `${conversationId}_${message.id}`);
            request.onerror = ()=>reject(request.error);
            request.onsuccess = ()=>resolve(message.id);
        });
    }
    static async patchMessage(conversationId, message) {
        const db = await LocalHistoryService.getMessagesDb();
        const messageKey = `${conversationId}_${message.id}`;
        const existingMessage = await new Promise((resolve, reject)=>{
            const transaction = db.transaction('messages', 'readonly');
            const store = transaction.objectStore('messages');
            const request = store.get(messageKey);
            request.onerror = ()=>reject(request.error);
            request.onsuccess = ()=>resolve(request.result);
        });
        if (!existingMessage) return null;
        const data = {
            ...existingMessage,
            ...message,
            content: `${existingMessage.content}${message.content}`
        };
        return new Promise((resolve, reject)=>{
            const transaction = db.transaction('messages', 'readwrite');
            const store = transaction.objectStore('messages');
            const request = store.put(data, messageKey);
            request.onerror = ()=>reject(request.error);
            request.onsuccess = ()=>resolve(message.id);
        });
    }
    static async getConversationMessages(conversationId) {
        const db = await LocalHistoryService.getMessagesDb();
        return new Promise((resolve, reject)=>{
            const transaction = db.transaction('messages', 'readonly');
            const store = transaction.objectStore('messages');
            const request = store.getAll();
            request.onerror = ()=>reject(request.error);
            request.onsuccess = ()=>{
                const messages = request.result.filter((msg)=>msg.conversationId === conversationId).sort((a, b)=>{
                    const timestampA = new Date(a.created_at).getTime();
                    const timestampB = new Date(b.created_at).getTime();
                    return timestampA - timestampB;
                });
                resolve(messages);
            };
        });
    }
    static async deleteConversation(conversationId) {
        const conversationsDb = await LocalHistoryService.getConversationsDb();
        const messagesDb = await LocalHistoryService.getMessagesDb();
        return new Promise((resolve, reject)=>{
            const conversationTransaction = conversationsDb.transaction('conversations', 'readwrite');
            const conversationStore = conversationTransaction.objectStore('conversations');
            const conversationRequest = conversationStore.delete(conversationId);
            conversationRequest.onerror = ()=>reject(conversationRequest.error);
            const messagesTransaction = messagesDb.transaction('messages', 'readwrite');
            const messagesStore = messagesTransaction.objectStore('messages');
            const getAllRequest = messagesStore.getAll();
            getAllRequest.onerror = ()=>reject(getAllRequest.error);
            getAllRequest.onsuccess = ()=>{
                const messages = getAllRequest.result;
                const deletePromises = [];
                messages.forEach((msg)=>{
                    if (msg.conversationId === conversationId) deletePromises.push(new Promise((resolveDelete, rejectDelete)=>{
                        const deleteRequest = messagesStore.delete(`${conversationId}_${msg.id}`);
                        deleteRequest.onerror = ()=>rejectDelete(deleteRequest.error);
                        deleteRequest.onsuccess = ()=>resolveDelete();
                    }));
                });
                Promise.all(deletePromises).then(()=>resolve()).catch((error)=>reject(error));
            };
        });
    }
    static async Initialize(instanceName, chatService) {
        const internalService = chatService.__internalService__;
        LocalHistoryService.CONVERSATIONS_DB_NAME = `${instanceName}_${LocalHistoryService.CONVERSATIONS_DB_BASE_NAME}`;
        LocalHistoryService.MESSAGES_DB_NAME = `${instanceName}_${LocalHistoryService.MESSAGES_DB_BASE_NAME}`;
        const cleanup = ()=>{
            LocalHistoryService.UNSUBSCRIBE_CALLBACKS.forEach((callback)=>callback());
            LocalHistoryService.UNSUBSCRIBE_CALLBACKS.clear();
        };
        const handleLocalHistoryChange = async (useLocalHistory)=>{
            if (useLocalHistory) {
                LocalHistoryService.ACTIVE_CONVERSATION_ID = StorageService.Instance.get(CHAT_ACTIVE_CONVERSATION_ID_KEY);
                const unsubscribeOpenConversation = chatService.on(AutopilotChatEvent.OpenConversation, async (id)=>{
                    LocalHistoryService.ACTIVE_CONVERSATION_ID = id;
                    StorageService.Instance.set(CHAT_ACTIVE_CONVERSATION_ID_KEY, id);
                    chatService.setConversation(await LocalHistoryService.getConversationMessages(id));
                });
                const unsubscribeSetHistory = chatService.on(AutopilotChatEvent.SetHistory, async ()=>{
                    if (LocalHistoryService.ACTIVE_CONVERSATION_ID) {
                        if (chatService.activeConversationId !== LocalHistoryService.ACTIVE_CONVERSATION_ID) chatService.openConversation(LocalHistoryService.ACTIVE_CONVERSATION_ID);
                    }
                });
                chatService.setHistory(await LocalHistoryService.getAllConversations());
                const handleNewMessage = async (message)=>{
                    LocalHistoryService.ACTIVE_CONVERSATION_ID = StorageService.Instance.get(CHAT_ACTIVE_CONVERSATION_ID_KEY);
                    if (LocalHistoryService.ACTIVE_CONVERSATION_ID) await LocalHistoryService.saveMessage(LocalHistoryService.ACTIVE_CONVERSATION_ID, message);
                    else {
                        LocalHistoryService.ACTIVE_CONVERSATION_ID = crypto.randomUUID();
                        await LocalHistoryService.createConversation(LocalHistoryService.ACTIVE_CONVERSATION_ID, message.content.slice(0, 50));
                        StorageService.Instance.set(CHAT_ACTIVE_CONVERSATION_ID_KEY, LocalHistoryService.ACTIVE_CONVERSATION_ID);
                        await LocalHistoryService.saveMessage(LocalHistoryService.ACTIVE_CONVERSATION_ID, message);
                        chatService.setHistory(await LocalHistoryService.getAllConversations());
                    }
                    return false;
                };
                const handleChunk = async (message)=>{
                    LocalHistoryService.ACTIVE_CONVERSATION_ID = StorageService.Instance.get(CHAT_ACTIVE_CONVERSATION_ID_KEY);
                    if (LocalHistoryService.ACTIVE_CONVERSATION_ID) {
                        const result = await LocalHistoryService.patchMessage(LocalHistoryService.ACTIVE_CONVERSATION_ID, message);
                        if (null === result) await LocalHistoryService.saveMessage(LocalHistoryService.ACTIVE_CONVERSATION_ID, message);
                    } else handleNewMessage(message);
                };
                const unsubscribeRequest = chatService.intercept(AutopilotChatInterceptableEvent.Request, handleNewMessage);
                const unsubscribeResponse = chatService.on(AutopilotChatEvent.Response, handleNewMessage);
                const unsubscribeSendChunk = chatService.on(AutopilotChatEvent.SendChunk, handleChunk);
                const unsubscribeNewChat = chatService.on(AutopilotChatEvent.NewChat, async ()=>{
                    LocalHistoryService.ACTIVE_CONVERSATION_ID = null;
                    StorageService.Instance.remove(CHAT_ACTIVE_CONVERSATION_ID_KEY);
                });
                const unsubscribeDeleteConversation = chatService.on(AutopilotChatEvent.DeleteConversation, async (id)=>{
                    await LocalHistoryService.deleteConversation(id);
                    if (LocalHistoryService.ACTIVE_CONVERSATION_ID === id) {
                        LocalHistoryService.ACTIVE_CONVERSATION_ID = null;
                        StorageService.Instance.remove(CHAT_ACTIVE_CONVERSATION_ID_KEY);
                    }
                    chatService.setHistory(await LocalHistoryService.getAllConversations());
                });
                cleanup();
                LocalHistoryService.UNSUBSCRIBE_CALLBACKS.set('setHistory', unsubscribeSetHistory);
                LocalHistoryService.UNSUBSCRIBE_CALLBACKS.set('openConversation', unsubscribeOpenConversation);
                LocalHistoryService.UNSUBSCRIBE_CALLBACKS.set('deleteConversation', unsubscribeDeleteConversation);
                LocalHistoryService.UNSUBSCRIBE_CALLBACKS.set('request', unsubscribeRequest);
                LocalHistoryService.UNSUBSCRIBE_CALLBACKS.set('response', unsubscribeResponse);
                LocalHistoryService.UNSUBSCRIBE_CALLBACKS.set('sendChunk', unsubscribeSendChunk);
                LocalHistoryService.UNSUBSCRIBE_CALLBACKS.set('newChat', unsubscribeNewChat);
            } else {
                cleanup();
                chatService.setHistory([]);
            }
        };
        if (chatService.getConfig().useLocalHistory) handleLocalHistoryChange(true);
        internalService.on(AutopilotChatInternalEvent.UseLocalHistory, handleLocalHistoryChange);
    }
}
export { LocalHistoryService };
