import { config } from './config.js';
import { state } from './state.js';
import { showNotification, emitirEventoActualizacion, mostrarSpinner, ocultarSpinner, _ } from './utils.js';

export function initDB() {
    return new Promise((resolve, reject) => {
        if (!window.indexedDB) {
            showNotification(_("essentialFeaturesNotSupported"), "warning");
            return reject("IndexedDB not supported");
        }
        const request = indexedDB.open(config.dbName, config.dbVersion);

        request.onupgradeneeded = e => {
            state.db = e.target.result;
            const transaction = e.target.transaction;
            const storesToCreate = ['movies', 'series', 'artists', 'photos', 'tokens', 'conexiones_locales', 'settings', 'jellyfin_settings', 'jellyfin_movies', 'jellyfin_series'];

            storesToCreate.forEach(storeName => {
                if (!state.db.objectStoreNames.contains(storeName)) {
                    let storeOptions;
                    if (['settings', 'jellyfin_settings'].includes(storeName)) {
                        storeOptions = { keyPath: 'id' };
                    } else if (['jellyfin_movies', 'jellyfin_series'].includes(storeName)) {
                        storeOptions = { keyPath: 'libraryId' };
                    }
                    else {
                        storeOptions = { keyPath: 'id', autoIncrement: true };
                    }
                    const store = state.db.createObjectStore(storeName, storeOptions);
                    
                    if (storeName === 'conexiones_locales') {
                        store.createIndex('tokenPrincipalIndex', 'tokenPrincipal', { unique: false });
                        store.createIndex('tokenSecundarioIndex', 'token', { unique: false });
                    }
                } else if (storeName === 'conexiones_locales' && transaction) {
                    try {
                        const connectionsStore = transaction.objectStore('conexiones_locales');
                        if (!connectionsStore.indexNames.contains('tokenPrincipalIndex')) {
                            connectionsStore.createIndex('tokenPrincipalIndex', 'tokenPrincipal', { unique: false });
                        }
                        if (!connectionsStore.indexNames.contains('tokenSecundarioIndex')) {
                            connectionsStore.createIndex('tokenSecundarioIndex', 'token', { unique: false });
                        }
                    } catch (indexError) {
                        if (e.target.transaction) e.target.transaction.abort();
                        reject(`Failed to upgrade indexes for ${storeName}`);
                        return;
                    }
                }
            });
        };

        request.onsuccess = e => {
            state.db = e.target.result;
            state.db.onversionchange = () => {
                state.db.close();
                alert(_("dbUpdateNeeded"));
                window.location.reload();
            };
            state.db.onerror = event => {
                console.error(`Database error: ${event.target.errorCode}`);
                reject(event.target.error);
            };
            resolve();
        };

        request.onerror = e => {
            showNotification(_("dbAccessError"), "error");
            reject(e.target.error);
        };

        request.onblocked = () => {
            alert(_("dbBlocked"));
        };
    });
}

export function getFromDB(storeName) {
    return new Promise((resolve, reject) => {
        if (!state.db || !state.db.objectStoreNames.contains(storeName)) {
            return resolve([]);
        }
        const transaction = state.db.transaction([storeName], 'readonly');
        const store = transaction.objectStore(storeName);
        const request = store.getAll();
        request.onsuccess = e => resolve(e.target.result || []);
        request.onerror = e => reject(e.target.error);
    });
}

export function clearStore(storeName) {
    return new Promise((resolve, reject) => {
        if (!state.db || !state.db.objectStoreNames.contains(storeName)) {
            return resolve();
        }
        const transaction = state.db.transaction([storeName], 'readwrite');
        const store = transaction.objectStore(storeName);
        const request = store.clear();
        request.onsuccess = () => resolve();
        request.onerror = event => reject(event.target.error);
    });
}

export function addItemsToStore(storeName, items) {
    return new Promise((resolve, reject) => {
        if (!state.db || !state.db.objectStoreNames.contains(storeName)) {
            return reject(`Store ${storeName} not available`);
        }
        if (!Array.isArray(items) || items.length === 0) {
            return resolve(0);
        }
        const transaction = state.db.transaction([storeName], 'readwrite');
        const store = transaction.objectStore(storeName);
        let successCount = 0;

        items.forEach(item => {
            if (item !== undefined && item !== null) {
                const request = store.put(item);
                request.onsuccess = () => successCount++;
                request.onerror = (e) => console.warn(`Error adding/updating item in ${storeName}:`, e.target.error, item);
            }
        });

        transaction.oncomplete = () => resolve(successCount);
        transaction.onerror = event => reject(event.target.error);
    });
}

export async function clearContentData() {
    showNotification(_("deletingContentData"), "info");
    mostrarSpinner();
    const storesToDelete = ['movies', 'series', 'artists', 'photos', 'conexiones_locales', 'jellyfin_movies', 'jellyfin_series'];
    try {
        if (!state.db) throw new Error(_("dbNotAvailable"));
        const storesPresent = storesToDelete.filter(name => state.db.objectStoreNames.contains(name));
        if (storesPresent.length === 0) {
            showNotification(_("noContentDataToDelete"), "info");
            return;
        }

        const transaction = state.db.transaction(storesPresent, 'readwrite');
        const promises = storesPresent.map(storeName => {
            return new Promise((resolve, reject) => {
                const request = transaction.objectStore(storeName).clear();
                request.onsuccess = resolve;
                request.onerror = e => reject(e.target.error);
            });
        });
        await Promise.all(promises);
        showNotification(_("contentDataDeleted"), "success");
        emitirEventoActualizacion();
    } catch (error) {
        showNotification(_("errorDeletingData", error.message), "error");
    } finally {
        ocultarSpinner();
    }
}

export async function loadTokensToEditor() {
    if (!state.aceEditor) {
        showNotification(_("aceEditorNotAvailable"), "error");
        return;
    }
    try {
        const tokensData = await getFromDB('tokens');
        const tokenList = tokensData.map(item => item.token);
        const structure = { tokens: tokenList.length > 0 ? tokenList : ["Pega_Tu_X-Plex-Token_Aqui"] };
        state.aceEditor.setValue(JSON.stringify(structure, null, 4), -1);
        state.aceEditor.focus();
    } catch (error) {
        showNotification(_("errorLoadingTokens"), "error");
        state.aceEditor.setValue(`{\n  "error": "${_("errorLoadingTokensMessage", error.message)}"\n}`, -1);
    }
}

export async function saveTokensFromEditor() {
    if (!state.aceEditor) {
        showNotification(_("aceEditorNotAvailableToSave"), "error");
        return;
    }
    const jsonContent = state.aceEditor.getValue();
    try {
        const parsed = JSON.parse(jsonContent);
        if (!parsed || !Array.isArray(parsed.tokens)) {
            throw new Error(_("invalidJsonFormat"));
        }
        const tokens = [...new Set(parsed.tokens.filter(t => typeof t === 'string' && t.trim()))];
        await clearStore('tokens');
        if (tokens.length > 0) {
            await addItemsToStore('tokens', tokens.map(t => ({ token: t })));
        }
        showNotification(_("tokensSaved"), "success");
        emitirEventoActualizacion();
    } catch (error) {
        showNotification(_("errorSavingTokens", error.message), "error");
    }
}

export async function exportDatabase() {
    mostrarSpinner();
    try {
        if (!state.db) throw new Error(_("dbNotAvailable"));
        const dbData = {};
        const storeNames = Array.from(state.db.objectStoreNames);
        for (const storeName of storeNames) {
            dbData[storeName] = await getFromDB(storeName);
        }
        const jsonString = JSON.stringify(dbData, null, 4);
        const blob = new Blob([jsonString], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        const timestamp = new Date().toISOString().slice(0, 19).replace(/[-:]/g, '');
        a.download = `CinePlex_Backup_${timestamp}.json`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
        showNotification(_("dbExported"), "success");
    } catch (error) {
        showNotification(_("errorExportingDb", error.message), "error");
    } finally {
        ocultarSpinner();
    }
}

export async function importDatabase(file) {
    if (!file) return;
    mostrarSpinner();
    state.isImporting = true;
    const reader = new FileReader();
    reader.onload = async (e) => {
        try {
            if (!state.db) throw new Error(_("dbNotAvailable"));
            const dbData = JSON.parse(e.target.result);
            if (typeof dbData !== 'object' || dbData === null) throw new Error(_("invalidJsonFile"));

            const storesToImport = Object.keys(dbData).filter(name => state.db.objectStoreNames.contains(name));
            if (storesToImport.length === 0) throw new Error(_("noDataToImport"));

            const transaction = state.db.transaction(storesToImport, 'readwrite');
            for (const storeName of storesToImport) {
                await new Promise((res, rej) => {
                    const req = transaction.objectStore(storeName).clear();
                    req.onsuccess = res;
                    req.onerror = rej;
                });
                if (Array.isArray(dbData[storeName])) {
                    for (const item of dbData[storeName]) {
                        if (item) transaction.objectStore(storeName).put(item);
                    }
                }
            }
            await new Promise((res, rej) => {
                transaction.oncomplete = res;
                transaction.onerror = e => rej(e.target.error);
            });
            showNotification(_("dbImported"), "success");
            emitirEventoActualizacion();
        } catch (error) {
            showNotification(_("errorImportingDb", error.message), "error");
        } finally {
            ocultarSpinner();
            state.isImporting = false;
        }
    };
    reader.readAsText(file);
}

export async function getServers() {
    const connections = await getFromDB('conexiones_locales');
    return connections.map(conn => ({
        id: conn.id,
        name: conn.nombre,
        accessToken: conn.token,
        publicUrl: conn.protocolo + '://' + conn.ip + ':' + conn.puerto,
        localUrl: conn.protocolo + '://' + conn.ip + ':' + conn.puerto,
    }));
}