// Smart Sync IndexedDB + Server API Implementation for High Performance
const API_BASE = 'api.php';
const DB_NAME = 'EasyErpSmartDB';
const DB_VERSION = 3; // Bumped version to force creating whatsapp_orders

let dbInstance = null;

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', 'whatsapp_orders'
];

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();
            if (!localStorage.getItem('force_sync_v13_accounts')) {
    localStorage.setItem('erp_db_versions', '{}');
    localStorage.setItem('force_sync_v13_accounts', 'true');
}
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));
                window.dispatchEvent(new CustomEvent('db_updated', { detail: { stores: outdatedStores } }));
            }
            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': '\u0627\u0644\u0623\u0635\u0646\u0627\u0641', 'projects': '\u0627\u0644\u0645\u0634\u0627\u0631\u064A\u0639', 'warehouses': '\u0627\u0644\u0645\u062E\u0627\u0632\u0646',
        'users': '\u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645\u064A\u0646', 'contacts': '\u062C\u0647\u0627\u062A \u0627\u0644\u0627\u062A\u0635\u0627\u0644', 'units': '\u0627\u0644\u0648\u062D\u062F\u0627\u062A',
        'transactions': '\u0627\u0644\u0645\u0633\u062A\u0646\u062F\u0627\u062A \u0648\u0627\u0644\u0641\u0648\u0627\u062A\u064A\u0631', 'journal_entries': '\u0627\u0644\u0642\u064A\u0648\u062F \u0627\u0644\u064A\u0648\u0645\u064A\u0629',
        'client_abstracts': '\u0627\u0644\u0645\u0633\u062A\u062E\u0644\u0635\u0627\u062A', 'accounts': '\u0634\u062C\u0631\u0629 \u0627\u0644\u062D\u0633\u0627\u0628\u0627\u062A',
        'notifications': '\u0627\u0644\u0625\u0634\u0639\u0627\u0631\u0627\u062A', 'settings': '\u0627\u0644\u0625\u0639\u062F\u0627\u062F\u0627\u062A \u0627\u0644\u0639\u0627\u0645\u0629'
    };
    
    const actionMap = { 'add': '\u0625\u0636\u0627\u0641\u0629', 'update': '\u062A\u0639\u062F\u064A\u0644', 'remove': '\u062D\u0630\u0641' };
    const modName = storeMap[storeName] || storeName;
    const actName = actionMap[action] || action;
    const details = `\u062A\u0645 ${actName} \u0633\u062C\u0644 \u0641\u064A ${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;
    if (result._last_updated) data._last_updated = result._last_updated;
    if (result.driver_token) data.driver_token = result.driver_token;
    
    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) {
        if (res.status === 409) {
            const msg = "\u062A\u0646\u0628\u064A\u0647 \u062E\u0637\u064A\u0631 \u26A0\uFE0F\n\u0642\u0627\u0645 \u0632\u0645\u064A\u0644 \u0644\u0643 \u0628\u062A\u0639\u062F\u064A\u0644 \u0647\u0630\u0647 \u0627\u0644\u0641\u0627\u062A\u0648\u0631\u0629 \u0623\u062B\u0646\u0627\u0621 \u0642\u0631\u0627\u0621\u062A\u0643 \u0644\u0647\u0627!\n\n\u062D\u0641\u0627\u0638\u0627\u064B \u0639\u0644\u0649 \u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0634\u0631\u0643\u0629\u060C \u062A\u0645 \u0625\u064A\u0642\u0627\u0641 \u0639\u0645\u0644\u064A\u0629 \u0627\u0644\u062D\u0641\u0638 \u0627\u0644\u062E\u0627\u0635\u0629 \u0628\u0643.\n\u064A\u0631\u062C\u0649 \u062A\u062D\u062F\u064A\u062B \u0627\u0644\u0635\u0641\u062D\u0629 \u0644\u0631\u0624\u064A\u0629 \u0627\u0644\u062A\u0639\u062F\u064A\u0644\u0627\u062A \u0627\u0644\u062C\u062F\u064A\u062F\u0629 \u0642\u0628\u0644 \u0627\u0644\u062D\u0641\u0638.";
            if (typeof Swal !== 'undefined') {
                Swal.fire({ icon: 'error', title: '\u062E\u0637\u0623 \u0641\u064A \u0627\u0644\u062D\u0641\u0638!', text: msg, confirmButtonText: '\u062D\u0633\u0646\u0627\u064B' });
            } else {
                alert(msg);
            }
            throw new Error("SYNC_CONFLICT");
        }
        const err = await res.json();
        throw new Error(err.error || "Update failed");
    }
    
    const result = await res.json();
    if (result._last_updated) data._last_updated = result._last_updated;
    if (result.driver_token) data.driver_token = result.driver_token;
    
    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;
}

async function login(username, password) {
    try {
        await initDB();
        let users = await getLocalData('users').catch(() => []);
        let user = users.find(u => u.username === username && u.password === password);
        
        if (user) {
            syncWithServer().catch(e => console.warn("Background sync failed", e));
            return user;
        } else {
            await syncWithServer().catch(e => { console.warn("Sync failed", e); });
            users = await getLocalData('users').catch(() => []);
            user = users.find(u => u.username === username && u.password === password);
            return user || null;
        }
    } catch (e) {
        console.error("Login failed due to DB error", e);
        return null;
    }
}

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


// Background polling every 15 seconds
setInterval(async () => {
    if (!dbInstance) return; // Not initialized or logged in yet
    if (syncPromise) return; // Sync already in progress
    try {
        await syncWithServer();
    } catch(e) {}
}, 15000);

// ==========================================
// Firebase & Notifications Logic
// ==========================================

window.sendApproverNotifications = async function(newApproversStr, oldApproversStr, message, linkStr = null) {
    if (!newApproversStr) return;
    const newArr = newApproversStr.split(',').map(s=>s.trim()).filter(Boolean);
    const oldArr = (oldApproversStr || '').split(',').map(s=>s.trim()).filter(Boolean);
    
    for (const u of newArr) {
        if (!oldArr.includes(u)) {
            const notifObj = {
                user: u,
                message: message,
                date: new Date().toISOString(),
                read: false
            };
            if (linkStr) notifObj.link = linkStr;
            await window.DB.add('notifications', notifObj);
            
            try {
                fetch('api.php?store=send_push', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({ user: u, title: 'EasyERP', body: message, link: linkStr })
                });
            } catch(e) {}
        }
    }
};

function loadScript(src) {
    return new Promise(r => {
        const s = document.createElement('script');
        s.src = src;
        s.onload = r;
        document.head.appendChild(s);
    });
}

window.requestNotificationPermissionManual = async function() {
    try {
        if (!('Notification' in window)) {
            alert('الإشعارات غير مدعومة في هذا المتصفح. إذا كنت تستخدم آيفون، يجب إضافة التطبيق إلى "الشاشة الرئيسية" (Add to Home Screen) من إعدادات المشاركة، ثم فتح التطبيق من الشاشة لتتمكن من تفعيل الإشعارات.');
            return;
        }
        const permission = await Notification.requestPermission();
        if (permission === 'granted') {
            if (window.initFirebasePush) {
                await window.initFirebasePush(true);
                alert('تم تفعيل الإشعارات بنجاح!');
            }
        } else {
            alert('تم رفض الإشعارات! يرجى تفعيلها من إعدادات المتصفح.');
        }
    } catch(e) {
        alert('حدث خطأ أثناء تفعيل الإشعارات: ' + e.message);
    }
};

window.initFirebasePush = async function(forceUpdateToken = false) {
    let messaging;
    try {
        if (!window.firebase_initialized) {
            await loadScript('https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js');
            await loadScript('https://www.gstatic.com/firebasejs/8.10.1/firebase-messaging.js');
            
            if (!firebase.apps.length) {
              firebase.initializeApp({
                apiKey: "AIzaSyB_wcxBXiOr2rkrBdL0VHw2KRREpq50rMI",
                authDomain: "easyerp-6d03d.firebaseapp.com",
                projectId: "easyerp-6d03d",
                storageBucket: "easyerp-6d03d.firebasestorage.app",
                messagingSenderId: "616839436850",
                appId: "1:616839436850:web:9296bd07e10c1eb352fa2b"
              });
            }
            window.firebase_initialized = true;
        } else if (!forceUpdateToken) {
            return; // Already loaded and no force requested
        }
        
        messaging = firebase.messaging();
        
        // التسجيل اليدوي لـ Service Worker ليناسب المجلدات الفرعية
        if ('serviceWorker' in navigator) {
            let registration = await navigator.serviceWorker.register('./firebase-messaging-sw.js');
            registration = await navigator.serviceWorker.ready; // Wait until active
            
            const token = await messaging.getToken({ 
                vapidKey: "BKLYJdxvkjoZce7FTfzi6mCp9DDclLfZbBp-8R0iFAXBc4z07mg9Blt6VAu7Gnb8WUlH_NWdf-V-NidsTFP1gmw",
                serviceWorkerRegistration: registration
            });
            
            if (token) {
                const currentUser = JSON.parse(sessionStorage.getItem('currentUser') || '{}');
                if (currentUser.username) {
                    fetch('api.php?store=user_tokens', {
                        method: 'POST',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify({ username: currentUser.username, token: token })
                    });
                }
            }
        }
        
        messaging.onMessage((payload) => {
            console.log('Foreground message received: ', payload);
            // We rely on local IndexedDB polling for foreground, so no need for toast, but we can sync immediately:
            if(window.syncWithServer) window.syncWithServer();
            if(window.loadData) window.loadData();
        });
    } catch (e) {
        console.warn("Firebase Push error:", e);
    }
};

// Auto-init after login or page load
window.addEventListener('DOMContentLoaded', () => {
    setTimeout(() => {
        const currentUser = JSON.parse(sessionStorage.getItem('currentUser') || '{}');
        if (currentUser.username) {
            window.initFirebasePush();
        }
    }, 2000);
});
