/**
 * Offline Handler
 * SSCI Office Platform - Smart offline support with IndexedDB sync queue
 */

class OfflineHandler {
    constructor() {
        this.isOnline = navigator.onLine;
        this.syncQueue = [];
        this.lastSyncTime = localStorage.getItem('lastSyncTime');
        this.dbName = 'ssciDB';
        this.dbVersion = 1;
        this.db = null;
        this.init();
    }

    /**
     * Initialize offline handler and IndexedDB
     */
    async init() {
        await this.initIndexedDB();
        this.detectNetworkStatus();
        this.setupServiceWorkerListener();
        this.setupSyncManager();
        this.loadSyncQueue();
    }

    /**
     * Initialize IndexedDB for offline storage
     */
    initIndexedDB() {
        return new Promise((resolve) => {
            if (!('indexedDB' in window)) {
                console.warn('IndexedDB not supported');
                resolve();
                return;
            }

            const request = indexedDB.open(this.dbName, this.dbVersion);

            request.onerror = () => {
                console.error('IndexedDB error:', request.error);
                resolve();
            };

            request.onsuccess = (event) => {
                this.db = event.target.result;
                console.log('IndexedDB initialized');
                resolve();
            };

            request.onupgradeneeded = (event) => {
                const db = event.target.result;
                
                // Create sync queue store
                if (!db.objectStoreNames.contains('syncQueue')) {
                    db.createObjectStore('syncQueue', { autoIncrement: true });
                }
                
                // Create drafts store
                if (!db.objectStoreNames.contains('drafts')) {
                    db.createObjectStore('drafts', { keyPath: 'id', autoIncrement: true });
                }
                
                // Create offline form data store
                if (!db.objectStoreNames.contains('formData')) {
                    db.createObjectStore('formData', { keyPath: 'formId' });
                }
                
                console.log('IndexedDB stores created');
            };
        });
    }

    /**
     * Setup service worker message listener
     */
    setupServiceWorkerListener() {
        if (!('serviceWorker' in navigator)) return;

        navigator.serviceWorker.ready.then(registration => {
            navigator.serviceWorker.controller?.addEventListener('message', (event) => {
                if (event.data.type === 'SYNC_COMPLETE') {
                    this.onSyncComplete(event.data);
                } else if (event.data.type === 'OFFLINE_MODE') {
                    this.handleOfflineMode(event.data);
                }
            });
        });
    }

    /**
     * Detect network status
     */
    detectNetworkStatus() {
        window.addEventListener('online', () => {
            this.isOnline = true;
            this.onOnline();
        });

        window.addEventListener('offline', () => {
            this.isOnline = false;
            this.onOffline();
        });

        // Periodic connectivity check
        setInterval(() => {
            this.checkConnectivity();
        }, 10000); // Check every 10 seconds
    }

    /**
     * Check actual connectivity with a small fetch
     */
    async checkConnectivity() {
        try {
            const response = await fetch('/manifest.json', { method: 'HEAD' });
            if (response.ok && !this.isOnline) {
                this.isOnline = true;
                this.onOnline();
            }
        } catch (error) {
            if (this.isOnline) {
                this.isOnline = false;
                this.onOffline();
            }
        }
    }

    /**
     * Handle online event
     */
    async onOnline() {
        console.log('Online detected');
        
        const banner = document.getElementById('offlineBanner');
        if (banner) {
            banner.classList.add('hidden');
        }

        // Show sync in progress message
        this.showSyncNotification('Syncing changes...', 'info');

        // Trigger sync
        await this.syncQueue();
        
        // Register background sync if available
        if ('serviceWorker' in navigator && 'SyncManager' in window) {
            try {
                const registration = await navigator.serviceWorker.ready;
                await registration.sync.register('sync-queue');
                console.log('Background sync registered');
            } catch (error) {
                console.error('Background sync registration failed:', error);
            }
        }
    }

    /**
     * Handle offline event
     */
    onOffline() {
        console.log('Offline detected');
        
        const banner = document.getElementById('offlineBanner');
        if (banner) {
            banner.classList.remove('hidden');
            this.updateLastSyncTime();
        }

        // Show offline notification
        this.showSyncNotification('You are offline. Changes will sync when online.', 'warning');
    }

    /**
     * Setup sync manager with background sync API
     */
    setupSyncManager() {
        if ('serviceWorker' in navigator && 'SyncManager' in window) {
            navigator.serviceWorker.ready.then(registration => {
                // Register periodic background sync if available
                if ('periodicSync' in registration) {
                    registration.periodicSync.register('sync-queue', {
                        minInterval: 24 * 60 * 60 * 1000 // Daily
                    }).catch(() => {
                        console.log('Periodic sync not supported or denied');
                    });
                }
            });
        }
    }

    /**
     * Add request to sync queue
     */
    async addToSyncQueue(request) {
        const queueItem = {
            url: request.url,
            method: request.method || 'POST',
            body: request.body,
            headers: request.headers || {},
            timestamp: new Date().toISOString(),
            retryCount: 0
        };

        this.syncQueue.push(queueItem);

        // Save to IndexedDB
        if (this.db) {
            this.saveToIndexedDB('syncQueue', queueItem);
        }

        // Also save to localStorage as backup
        this.saveSyncQueue();

        console.log('Request added to sync queue:', queueItem.url);
    }

    /**
     * Save to IndexedDB
     */
    async saveToIndexedDB(storeName, data) {
        return new Promise((resolve) => {
            if (!this.db) {
                resolve();
                return;
            }

            try {
                const transaction = this.db.transaction(storeName, 'readwrite');
                const store = transaction.objectStore(storeName);
                const request = store.add(data);

                request.onsuccess = () => resolve();
                request.onerror = () => resolve();
            } catch (error) {
                console.error('IndexedDB save error:', error);
                resolve();
            }
        });
    }

    /**
     * Save sync queue to local storage (backup)
     */
    saveSyncQueue() {
        localStorage.setItem('syncQueue', JSON.stringify(this.syncQueue));
    }

    /**
     * Load sync queue from storage
     */
    async loadSyncQueue() {
        // Try IndexedDB first
        if (this.db) {
            const items = await this.getIndexedDBItems('syncQueue');
            if (items && items.length > 0) {
                this.syncQueue = items;
                console.log('Loaded', items.length, 'items from IndexedDB');
                return;
            }
        }

        // Fallback to localStorage
        const queue = localStorage.getItem('syncQueue');
        this.syncQueue = queue ? JSON.parse(queue) : [];
        console.log('Loaded', this.syncQueue.length, 'items from localStorage');
    }

    /**
     * Get items from IndexedDB
     */
    async getIndexedDBItems(storeName) {
        return new Promise((resolve) => {
            if (!this.db) {
                resolve(null);
                return;
            }

            try {
                const transaction = this.db.transaction(storeName, 'readonly');
                const store = transaction.objectStore(storeName);
                const request = store.getAll();

                request.onsuccess = () => {
                    resolve(request.result);
                };
                request.onerror = () => {
                    resolve(null);
                };
            } catch (error) {
                console.error('IndexedDB read error:', error);
                resolve(null);
            }
        });
    }

    /**
     * Process sync queue
     */
    async syncQueue() {
        if (this.syncQueue.length === 0) {
            return;
        }

        console.log('Starting sync of', this.syncQueue.length, 'items');

        const failedRequests = [];
        const succeededCount = this.syncQueue.length;

        for (const request of this.syncQueue) {
            try {
                request.retryCount = (request.retryCount || 0) + 1;

                const response = await fetch(request.url, {
                    method: request.method,
                    body: request.body,
                    headers: {
                        'Content-Type': 'application/json',
                        ...request.headers
                    }
                });

                if (!response.ok) {
                    if (request.retryCount < 3) {
                        failedRequests.push(request);
                    }
                }
            } catch (error) {
                console.error('Sync error for', request.url, ':', error);
                if ((request.retryCount || 0) < 3) {
                    failedRequests.push(request);
                }
            }
        }

        this.syncQueue = failedRequests;
        this.saveSyncQueue();

        // Update IndexedDB
        if (this.db) {
            await this.clearIndexedDB('syncQueue');
            for (const req of failedRequests) {
                await this.saveToIndexedDB('syncQueue', req);
            }
        }

        const syncedCount = succeededCount - failedRequests.length;
        this.updateLastSyncTime();
        
        if (failedRequests.length === 0) {
            this.showSyncNotification(`All ${syncedCount} pending changes have been synced!`, 'success');
        } else {
            this.showSyncNotification(`Synced ${syncedCount} changes. ${failedRequests.length} pending retry.`, 'warning');
        }
    }

    /**
     * Clear IndexedDB store
     */
    async clearIndexedDB(storeName) {
        return new Promise((resolve) => {
            if (!this.db) {
                resolve();
                return;
            }

            try {
                const transaction = this.db.transaction(storeName, 'readwrite');
                const store = transaction.objectStore(storeName);
                const request = store.clear();

                request.onsuccess = () => resolve();
                request.onerror = () => resolve();
            } catch (error) {
                console.error('IndexedDB clear error:', error);
                resolve();
            }
        });
    }

    /**
     * On sync complete from service worker
     */
    onSyncComplete(data) {
        console.log('Sync complete:', data);
        if (data.success) {
            this.showSyncNotification('All changes synced successfully!', 'success');
            this.updateLastSyncTime();
        } else if (data.failedCount > 0) {
            this.showSyncNotification(`Sync complete. ${data.failedCount} items pending.`, 'warning');
        }
    }

    /**
     * Handle offline mode
     */
    handleOfflineMode(data) {
        console.log('Offline mode activated:', data);
        this.onOffline();
    }

    /**
     * Show sync notification
     */
    showSyncNotification(message, type = 'info') {
        if (typeof showToast === 'function') {
            showToast(type, message);
        } else {
            console.log(`[${type.toUpperCase()}]`, message);
        }
    }

    /**
     * Update last sync time
     */
    updateLastSyncTime() {
        const now = new Date();
        this.lastSyncTime = now.toLocaleTimeString();
        localStorage.setItem('lastSyncTime', this.lastSyncTime);

        const lastSyncElement = document.getElementById('lastSyncTime');
        if (lastSyncElement) {
            lastSyncElement.textContent = this.lastSyncTime;
        }
    }

    /**
     * Cache form data
     */
    cacheFormData(formId) {
        const form = document.getElementById(formId);
        if (!form) return;

        const formData = new FormData(form);
        const data = Object.fromEntries(formData);
        localStorage.setItem(`form_${formId}`, JSON.stringify(data));
    }

    /**
     * Restore cached form data
     */
    restoreFormData(formId) {
        const cached = localStorage.getItem(`form_${formId}`);
        if (!cached) return;

        const data = JSON.parse(cached);
        const form = document.getElementById(formId);
        if (!form) return;

        for (const [key, value] of Object.entries(data)) {
            const field = form.elements[key];
            if (field) {
                if (field.type === 'checkbox') {
                    field.checked = value === 'on';
                } else {
                    field.value = value;
                }
            }
        }
    }

    /**
     * Clear cached form data
     */
    clearFormCache(formId) {
        localStorage.removeItem(`form_${formId}`);
    }
}

// Initialize offline handler
const offlineHandler = new OfflineHandler();

// Auto-cache form data on input
document.addEventListener('change', (e) => {
    if (e.target.form) {
        offlineHandler.cacheFormData(e.target.form.id);
    }
});

// Display last sync time on load
window.addEventListener('load', () => {
    const lastSyncElement = document.getElementById('lastSyncTime');
    if (lastSyncElement && offlineHandler.lastSyncTime) {
        lastSyncElement.textContent = offlineHandler.lastSyncTime;
    }
});
