/**
 * Service Worker
 * SSCI Office Platform - PWA Support
 * Implements smart caching with offline-first strategy
 */

const CACHE_VERSION = 'v2';
const CACHE_NAME = `ssci-office-${CACHE_VERSION}`;
const STATIC_CACHE = `ssci-static-${CACHE_VERSION}`;
const DYNAMIC_CACHE = `ssci-dynamic-${CACHE_VERSION}`;
const API_CACHE = `ssci-api-${CACHE_VERSION}`;

const ASSETS_TO_CACHE = [
    '/',
    '/index.php?page=landing',
    '/offline.html',
    '/css/main.css',
    '/js/app.js',
    '/js/notifications.js',
    '/js/pwa.js',
    '/js/offline.js',
    '/js/draft-manager.js',
    '/images/logo.png',
];

/**
 * Install event
 */
self.addEventListener('install', (event) => {
    console.log('Service Worker installing...', CACHE_NAME);
    
    event.waitUntil(
        Promise.all([
            // Cache static assets
            caches.open(STATIC_CACHE).then((cache) => {
                console.log('Caching static assets');
                return cache.addAll(ASSETS_TO_CACHE);
            }),
            // Ensure service worker takes control immediately
            self.skipWaiting()
        ])
    );
});

/**
 * Activate event
 */
self.addEventListener('activate', (event) => {
    console.log('Service Worker activating...');
    
    event.waitUntil(
        caches.keys().then((cacheNames) => {
            return Promise.all(
                cacheNames
                    .filter((cacheName) => {
                        // Delete old cache versions
                        return !cacheName.includes(CACHE_VERSION);
                    })
                    .map((cacheName) => {
                        console.log('Deleting old cache:', cacheName);
                        return caches.delete(cacheName);
                    })
            );
        }).then(() => {
            console.log('Service Worker claiming clients');
            return self.clients.claim();
        })
    );
});

/**
 * Fetch event
 */
self.addEventListener('fetch', (event) => {
    const { request } = event;
    const url = new URL(request.url);

    // Skip cross-origin requests and chrome extensions
    if (url.origin !== location.origin || request.method !== 'GET') {
        return;
    }

    // Network first for API calls with cache fallback
    if (url.pathname.includes('/api/') || url.pathname.includes('?page=api')) {
        event.respondWith(networkFirstWithCache(request));
        return;
    }

    // HTML pages - network first with offline fallback
    if (request.headers.get('accept').includes('text/html')) {
        event.respondWith(networkFirstWithOffline(request));
        return;
    }

    // Static assets - cache first with network fallback
    event.respondWith(cacheFirstWithNetwork(request));
});

/**
 * Network first strategy with cache fallback
 */
function networkFirstWithCache(request) {
    return fetch(request)
        .then((response) => {
            // Only cache successful responses
            if (!response || response.status !== 200 || response.type === 'error') {
                return response;
            }

            const responseToCache = response.clone();
            caches.open(API_CACHE).then((cache) => {
                cache.put(request, responseToCache);
            });

            return response;
        })
        .catch(() => {
            // Return cached API response or offline message
            return caches.match(request)
                .then((cachedResponse) => {
                    if (cachedResponse) {
                        return cachedResponse;
                    }
                    return new Response(JSON.stringify({
                        success: false,
                        message: 'Offline - cached data not available. Changes will sync when online.',
                        offline: true
                    }), {
                        status: 503,
                        statusText: 'Service Unavailable',
                        headers: new Headers({
                            'Content-Type': 'application/json'
                        })
                    });
                });
        });
}

/**
 * Network first strategy for HTML with offline fallback
 */
function networkFirstWithOffline(request) {
    return fetch(request)
        .then((response) => {
            if (!response || response.status !== 200) {
                return response;
            }

            const responseToCache = response.clone();
            caches.open(DYNAMIC_CACHE).then((cache) => {
                cache.put(request, responseToCache);
            });

            return response;
        })
        .catch(() => {
            return caches.match(request)
                .then((cachedResponse) => {
                    return cachedResponse || caches.match('/offline.html');
                });
        });
}

/**
 * Cache first strategy with network fallback
 */
function cacheFirstWithNetwork(request) {
    return caches.match(request)
        .then((response) => {
            // Return cached response if available
            if (response) {
                // Update cache in background (stale-while-revalidate)
                fetch(request).then((freshResponse) => {
                    if (freshResponse && freshResponse.status === 200) {
                        caches.open(STATIC_CACHE).then((cache) => {
                            cache.put(request, freshResponse.clone());
                        });
                    }
                }).catch(() => {
                    // Network failed, but cache is already returned
                });
                return response;
            }

            // No cache, fetch from network
            return fetch(request)
                .then((response) => {
                    if (!response || response.status !== 200) {
                        return response;
                    }

                    const responseToCache = response.clone();
                    caches.open(STATIC_CACHE).then((cache) => {
                        cache.put(request, responseToCache);
                    });

                    return response;
                })
                .catch(() => {
                    // Offline fallback
                    return new Response('Offline - resource not available', {
                        status: 503,
                        statusText: 'Service Unavailable'
                    });
                });
        });
}

/**
 * Background sync
 */
self.addEventListener('sync', (event) => {
    if (event.tag === 'sync-queue') {
        event.waitUntil(processSyncQueue());
    } else if (event.tag === 'sync-draft') {
        event.waitUntil(syncDraftSave());
    }
});

/**
 * Process sync queue from IndexedDB or localStorage
 */
async function processSyncQueue() {
    try {
        const requests = await getQueuedRequests();
        
        if (!requests || requests.length === 0) {
            return;
        }

        const failedRequests = [];

        for (const req of requests) {
            try {
                const response = await fetch(req.url, {
                    method: req.method || 'POST',
                    body: req.body,
                    headers: req.headers || { 'Content-Type': 'application/json' }
                });

                if (!response.ok) {
                    failedRequests.push(req);
                    console.warn('Sync failed for:', req.url);
                }
            } catch (error) {
                console.error('Sync request error:', error);
                failedRequests.push(req);
            }
        }

        // Update queue with failed requests
        await saveQueuedRequests(failedRequests);

        // Notify clients of sync completion
        const clients = await self.clients.matchAll();
        clients.forEach(client => {
            client.postMessage({
                type: 'SYNC_COMPLETE',
                success: failedRequests.length === 0,
                failedCount: failedRequests.length
            });
        });
    } catch (error) {
        console.error('Sync queue error:', error);
    }
}

/**
 * Sync draft auto-saves
 */
async function syncDraftSave() {
    try {
        const drafts = await getDraftQueue();
        if (!drafts || drafts.length === 0) {
            return;
        }

        for (const draft of drafts) {
            try {
                await fetch('/api/sync', {
                    method: 'POST',
                    body: JSON.stringify(draft),
                    headers: { 'Content-Type': 'application/json' }
                });
            } catch (error) {
                console.error('Draft sync error:', error);
            }
        }
    } catch (error) {
        console.error('Draft queue error:', error);
    }
}

/**
 * Get queued requests from IndexedDB
 */
async function getQueuedRequests() {
    return new Promise((resolve) => {
        const request = indexedDB.open('ssciDB', 1);
        
        request.onsuccess = function(event) {
            const db = event.target.result;
            if (!db.objectStoreNames.contains('syncQueue')) {
                resolve([]);
                return;
            }
            
            const transaction = db.transaction('syncQueue', 'readonly');
            const store = transaction.objectStore('syncQueue');
            const getAllRequest = store.getAll();
            
            getAllRequest.onsuccess = function() {
                resolve(getAllRequest.result || []);
            };
            getAllRequest.onerror = function() {
                resolve([]);
            };
        };
        request.onerror = function() {
            resolve([]);
        };
    });
}

/**
 * Save queued requests to IndexedDB
 */
async function saveQueuedRequests(requests) {
    return new Promise((resolve) => {
        const openRequest = indexedDB.open('ssciDB', 1);
        
        openRequest.onsuccess = function(event) {
            const db = event.target.result;
            if (!db.objectStoreNames.contains('syncQueue')) {
                resolve();
                return;
            }
            
            const transaction = db.transaction('syncQueue', 'readwrite');
            const store = transaction.objectStore('syncQueue');
            
            store.clear();
            requests.forEach(req => {
                store.add(req);
            });
            
            transaction.oncomplete = function() {
                resolve();
            };
            transaction.onerror = function() {
                resolve();
            };
        };
        openRequest.onerror = function() {
            resolve();
        };
    });
}

/**
 * Get draft queue from IndexedDB
 */
async function getDraftQueue() {
    return new Promise((resolve) => {
        const request = indexedDB.open('ssciDB', 1);
        
        request.onsuccess = function(event) {
            const db = event.target.result;
            if (!db.objectStoreNames.contains('drafts')) {
                resolve([]);
                return;
            }
            
            const transaction = db.transaction('drafts', 'readonly');
            const store = transaction.objectStore('drafts');
            const getAllRequest = store.getAll();
            
            getAllRequest.onsuccess = function() {
                resolve(getAllRequest.result || []);
            };
            getAllRequest.onerror = function() {
                resolve([]);
            };
        };
        request.onerror = function() {
            resolve([]);
        };
    });
}

/**
 * Push notification event
 */
self.addEventListener('push', (event) => {
    if (event.data) {
        const data = event.data.json();
        const options = {
            body: data.message,
            icon: '/images/logo.png',
            badge: '/images/badge.png',
            vibrate: [200, 100, 200],
            data: {
                dateOfArrival: Date.now(),
                primaryKey: 1
            },
            actions: [
                {
                    action: 'explore',
                    title: 'Open',
                    icon: '/images/checkmark.png'
                },
                {
                    action: 'close',
                    title: 'Close',
                    icon: '/images/xmark.png'
                }
            ]
        };

        event.waitUntil(
            self.registration.showNotification(data.title, options)
        );
    }
});

/**
 * Notification click event
 */
self.addEventListener('notificationclick', (event) => {
    event.notification.close();

    if (event.action === 'close') {
        return;
    }

    event.waitUntil(
        clients.matchAll({ type: 'window' })
            .then((clientList) => {
                // Check if the app is already open
                for (let i = 0; i < clientList.length; i++) {
                    const client = clientList[i];
                    if (client.url === '/' && 'focus' in client) {
                        return client.focus();
                    }
                }
                // If not open, open a new window
                if (clients.openWindow) {
                    return clients.openWindow('/');
                }
            })
    );
});

console.log('Service Worker loaded');
