// Smart Sync IndexedDB + Server API Implementation for High Performance
const API_BASE = 'api.php';
const DB_NAME = 'EasyErpSmartDB';
const DB_VERSION = 1;

let dbInstance = null;

// The stores defined in api.php
const ALL_STORES = [
    'users', 'warehouses', 'items', 'projects', 'transactions',
    'notifications', 'contacts', 'units', 'accounts',
    'journal_entries', 'activity_logs', 'subcontracts',
    'subcontract_abstracts', 'client_abstracts', 'settings',
    'client_contracts', 'client_abstracts_new', 'sub_contracts', 'sub_abstracts',
    'employees', 'advances', 'payrolls', 'custody_requests', 'settlements',
    'mixers', 'pumps', 'equipments', 'concrete_invoices', 'invoice_mixer_trips', 'pos_archive'
];

function getHeaders() {
    const headers = { 'Content-Type': 'application/json' };
    try {
        const savedUser = sessionStorage.getItem('currentUser');
        if (savedUser) {
            const user = JSON.parse(savedUser);
            headers['X-Username'] = encodeURIComponent(user.username || '');
            headers['X-User-Id'] = user.id || 0;
        }
    } catch(e) {}
    return headers;
}

function initDB() {
    return new Promise((resolve, reject) => {
        if (dbInstance) return resolve(dbInstance);
        const request = indexedDB.open(DB_NAME, DB_VERSION);
        request.onupgradeneeded = (event) => {
            const db = event.target.result;
            ALL_STORES.forEach(store => {
                if (!db.objectStoreNames.contains(store)) {
                    db.createObjectStore(store, { keyPath: 'id' });
                }
            });
        };
        request.onsuccess = (event) => {
            dbInstance = event.target.result;
            resolve(dbInstance);
        };
        request.onerror = (event) => reject(event.target.error);
    });
}

function getLocalData(storeName) {
    return new Promise((resolve, reject) => {
        const tx = dbInstance.transaction(storeName, 'readonly');
        const store = tx.objectStore(storeName);
        const request = store.getAll();
        request.onsuccess = () => resolve(request.result || []);
        request.onerror = () => reject(request.error);
    });
}

function saveLocalData(storeName, items) {
    return new Promise((resolve, reject) => {
        const tx = dbInstance.transaction(storeName, 'readwrite');
        const store = tx.objectStore(storeName);
        // Clear old data
        store.clear();
        items.forEach(item => store.put(item));
        tx.oncomplete = () => resolve();
        tx.onerror = () => reject(tx.error);
    });
}

function putLocalItem(storeName, item) {
    if (item && item.id !== undefined && !isNaN(item.id) && item.id !== '') { item.id = Number(item.id); }
    return new Promise((resolve, reject) => {
        const tx = dbInstance.transaction(storeName, 'readwrite');
        const store = tx.objectStore(storeName);
        store.put(item);
        tx.oncomplete = () => resolve();
        tx.onerror = () => reject(tx.error);
    });
}

function removeLocalItem(storeName, id) {
    return new Promise((resolve, reject) => {
        const tx = dbInstance.transaction(storeName, 'readwrite');
        const store = tx.objectStore(storeName);
        store.delete(Number(id)); // Try as number
        store.delete(String(id)); // Try as string
        tx.oncomplete = () => resolve();
        tx.onerror = () => reject(tx.error);
    });
}

let syncPromise = null;

async function syncWithServer() {
    if (syncPromise) return syncPromise;
    
    syncPromise = (async () => {
        try {
            await initDB();
            let localVersions = JSON.parse(localStorage.getItem('erp_db_versions') || '{}');
            
            // 1. Fetch versions fast
            const vRes = await fetch(API_BASE + '?store=versions&_t=' + Date.now(), { headers: { 'Cache-Control': 'no-cache' } });
            if (!vRes.ok) throw new Error("Failed to fetch versions");
            const serverVersions = await vRes.json();
            
            // 2. Identify outdated stores
            const outdatedStores = [];
            for (const store of ALL_STORES) {
                const sVer = serverVersions[store] || 1;
                const lVer = localVersions[store] || 0;
                if (sVer > lVer) {
                    outdatedStores.push(store);
                }
            }
            
            // 3. Fetch ONLY outdated data
            if (outdatedStores.length > 0) {
                // Fetch in chunks if too many (API might have limits)
                const chunkedStores = [];
                for(let i=0; i<outdatedStores.length; i+=10) {
                    chunkedStores.push(outdatedStores.slice(i, i+10).join(','));
                }
                
                for(const chunk of chunkedStores) {
                    const dataRes = await fetch(API_BASE + '?store=multi&stores=' + chunk + '&_t=' + Date.now(), { headers: getHeaders() });
                    const newData = await dataRes.json();
                    
                    for (const storeName in newData) {
                        await saveLocalData(storeName, newData[storeName]);
                        localVersions[storeName] = serverVersions[storeName] || (Date.now()/1000);
                    }
                }
                localStorage.setItem('erp_db_versions', JSON.stringify(localVersions));
            }
            return true;
        } catch (e) {
            console.error("Sync Error:", e);
            return false;
        } finally {
            syncPromise = null;
        }
    })();
    return syncPromise;
}

async function getAllStores() {
    await initDB();
    await syncWithServer(); // Extremely fast if nothing changed (10ms)
    
    const allData = {};
    for (const store of ALL_STORES) {
        allData[store] = await getLocalData(store);
    }
    return allData;
}

async function getMultiStores(storeNames) {
    await initDB();
    await syncWithServer();
    
    const data = {};
    for (const store of storeNames) {
        data[store] = await getLocalData(store);
    }
    return data;
}

async function getAll(storeName) {
    await initDB();
    await syncWithServer();
    return await getLocalData(storeName);
}

function updateLocalVersion(storeName) {
    let localVersions = JSON.parse(localStorage.getItem('erp_db_versions') || '{}');
    // Set to a high value so the next sync doesn't overwrite our local change immediately
    // The server will have a slightly smaller timestamp, so we ignore it until someone ELSE changes it.
    localVersions[storeName] = (Date.now() / 1000) + 2; 
    localStorage.setItem('erp_db_versions', JSON.stringify(localVersions));
}

function logToActivity(storeName, action, dataId) {
    if (storeName === 'activity_logs') return;
    const user = JSON.parse(sessionStorage.getItem('currentUser') || '{}');
    if (!user.username) return;
    
    const storeMap = {
        'items': 'الأصناف', 'projects': 'المشاريع', 'warehouses': 'المخازن',
        'users': 'المستخدمين', 'contacts': 'جهات الاتصال', 'units': 'الوحدات',
        'transactions': 'المستندات والفواتير', 'journal_entries': 'القيود اليومية',
        'client_abstracts': 'المستخلصات', 'accounts': 'شجرة الحسابات',
        'notifications': 'الإشعارات', 'settings': 'الإعدادات العامة'
    };
    
    const actionMap = { 'add': 'إضافة', 'update': 'تعديل', 'remove': 'حذف' };
    const modName = storeMap[storeName] || storeName;
    const actName = actionMap[action] || action;
    const details = `تم ${actName} سجل في ${modName} (ID: ${dataId})`;

    const logEntry = {
        id: Date.now() + Math.floor(Math.random() * 10000),
        timestamp: new Date().toLocaleString('en-GB'),
        username: user.username,
        action: actName,
        module: modName,
        record_id: String(dataId),
        details: details
    };

    fetch(API_BASE + '?store=activity_logs', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(logEntry)
    }).then(async res => {
        const r = await res.json();
        logEntry.id = r.id || logEntry.id;
        await putLocalItem('activity_logs', logEntry);
        updateLocalVersion('activity_logs');
        if (window.currentAuditLogs) window.currentAuditLogs.push(logEntry);
        if (typeof window.renderAuditLogs === 'function') window.renderAuditLogs();
    }).catch(e => console.error(e));
}

async function add(storeName, data) {
    const res = await fetch(API_BASE + '?store=' + storeName, {
        method: 'POST',
        headers: getHeaders(),
        body: JSON.stringify(data)
    });
    if (!res.ok) throw new Error("API Error");
    const result = await res.json();
    data.id = result.id;
    
    await putLocalItem(storeName, data);
    updateLocalVersion(storeName);
    logToActivity(storeName, "add", data.id);
    
    return data.id;
}

async function update(storeName, data) {
    if (!data.id) throw new Error("Cannot update without an ID");
    
    const res = await fetch(API_BASE + '?store=' + storeName + '&id=' + data.id, {
        method: 'PUT',
        headers: getHeaders(),
        body: JSON.stringify(data)
    });
    if (!res.ok) throw new Error("API Error");
    const result = await res.json();
    
    await putLocalItem(storeName, data);
    updateLocalVersion(storeName);
    logToActivity(storeName, "update", data.id);
    
    return result;
}

async function remove(storeName, id) {
    const res = await fetch(API_BASE + '?store=' + storeName + '&id=' + id, {
        method: 'DELETE',
        headers: getHeaders()
    });
    if (!res.ok) throw new Error("API Error");
    const result = await res.json();
    
    await removeLocalItem(storeName, id);
    updateLocalVersion(storeName);
    logToActivity(storeName, "remove", id);
    
    return result;
}

function login(username, password) {
    // Force sync before login to ensure we have latest users
    return syncWithServer().then(() => {
        return getLocalData('users').then(users => {
            const user = users.find(u => u.username === username && u.password === password);
            return user || null;
        });
    });
}

window.DB = {
    initDB,
    getAll,
    getAllStores,
    getMultiStores,
    add,
    update,
    remove,
    login
};
