// UK Data Services - Service Worker for PWA Functionality
// Version 1.0 - Advanced caching and offline support

const CACHE_NAME = 'ukds-pwa-v1.1.0';
const STATIC_CACHE = 'ukds-static-v1.1.0';
const DYNAMIC_CACHE = 'ukds-dynamic-v1.1.0';
const IMAGE_CACHE = 'ukds-images-v1.1.0';

// Files to cache immediately (critical resources)
const STATIC_ASSETS = [
    '/',
    '/index.php',
    '/assets/css/main.min.css',
    '/assets/js/main.min.js',
    '/assets/images/ukds-main-logo.webp',
    '/assets/images/ukds-main-logo.png',
    '/assets/images/logo-white.svg',
    '/assets/images/favicon.svg',
    '/manifest.json',
    '/offline.html'
];

// Network-first resources (always try network first)
const NETWORK_FIRST = [
    '/quote.php',
    '/contact-handler.php',
    '/quote-handler.php'
];

// Cache-first resources (images, fonts, static assets)
const CACHE_FIRST = [
    '/assets/images/',
    '/assets/fonts/',
    'https://fonts.googleapis.com/',
    'https://fonts.gstatic.com/'
];

// Install event - cache critical resources
self.addEventListener('install', (event) => {
    console.log('[SW] Installing service worker...');
    
    event.waitUntil(
        Promise.all([
            // Cache static assets
            caches.open(STATIC_CACHE).then((cache) => {
                console.log('[SW] Caching static assets');
                return cache.addAll(STATIC_ASSETS);
            }),
            
            // Skip waiting to activate immediately
            self.skipWaiting()
        ])
    );
});

// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
    console.log('[SW] Activating service worker...');
    
    event.waitUntil(
        Promise.all([
            // Clean up old caches
            caches.keys().then((cacheNames) => {
                return Promise.all(
                    cacheNames.map((cacheName) => {
                        if (!isCurrentCache(cacheName)) {
                            console.log('[SW] Deleting old cache:', cacheName);
                            return caches.delete(cacheName);
                        }
                    })
                );
            }),
            
            // Take control of all clients
            self.clients.claim()
        ])
    );
});

// Fetch event - handle all network requests
self.addEventListener('fetch', (event) => {
    const { request } = event;
    const url = new URL(request.url);
    
    // Skip non-GET requests
    if (request.method !== 'GET') {
        return;
    }
    
    // Skip external analytics and third-party requests
    if (url.origin !== location.origin && !isCacheableExternal(url.href)) {
        return;
    }
    
    event.respondWith(handleRequest(request));
});

// Handle different types of requests with appropriate strategies
async function handleRequest(request) {
    const url = new URL(request.url);
    
    try {
        // Network-first strategy for forms and dynamic content
        if (isNetworkFirst(request.url)) {
            return await networkFirst(request);
        }
        
        // Cache-first strategy for images and static assets
        if (isCacheFirst(request.url)) {
            return await cacheFirst(request);
        }
        
        // Stale-while-revalidate for HTML pages
        if (isHTML(request)) {
            return await staleWhileRevalidate(request);
        }
        
        // Default to network-first
        return await networkFirst(request);
        
    } catch (error) {
        console.log('[SW] Request failed:', error);
        return await handleOffline(request);
    }
}

// Network-first strategy
async function networkFirst(request) {
    try {
        const networkResponse = await fetch(request);
        
        // Cache successful responses
        if (networkResponse.ok) {
            const cache = await caches.open(DYNAMIC_CACHE);
            cache.put(request, networkResponse.clone());
        }
        
        return networkResponse;
    } catch (error) {
        // Fallback to cache
        const cachedResponse = await caches.match(request);
        if (cachedResponse) {
            return cachedResponse;
        }
        throw error;
    }
}

// Cache-first strategy
async function cacheFirst(request) {
    const cachedResponse = await caches.match(request);
    
    if (cachedResponse) {
        return cachedResponse;
    }
    
    try {
        const networkResponse = await fetch(request);
        
        if (networkResponse.ok) {
            const cache = await caches.open(getAppropriateCache(request.url));
            cache.put(request, networkResponse.clone());
        }
        
        return networkResponse;
    } catch (error) {
        throw error;
    }
}

// Stale-while-revalidate strategy
async function staleWhileRevalidate(request) {
    const cachedResponse = await caches.match(request);
    
    // Always try to update in background
    const networkPromise = fetch(request).then(async (networkResponse) => {
        if (networkResponse.ok) {
            const cache = await caches.open(DYNAMIC_CACHE);
            cache.put(request, networkResponse.clone());
        }
        return networkResponse;
    }).catch(() => {
        // Ignore network errors for background updates
    });
    
    // Return cached version immediately if available
    if (cachedResponse) {
        return cachedResponse;
    }
    
    // Wait for network if no cache
    return await networkPromise;
}

// Handle offline scenarios
async function handleOffline(request) {
    const url = new URL(request.url);
    
    // Try to find cached version
    const cachedResponse = await caches.match(request);
    if (cachedResponse) {
        return cachedResponse;
    }
    
    // Return offline page for HTML requests
    if (isHTML(request)) {
        const offlinePage = await caches.match('/offline.html');
        if (offlinePage) {
            return offlinePage;
        }
    }
    
    // Return generic offline response
    return new Response(
        JSON.stringify({
            error: 'Offline',
            message: 'This content is not available offline'
        }),
        {
            status: 503,
            statusText: 'Service Unavailable',
            headers: {
                'Content-Type': 'application/json'
            }
        }
    );
}

// Utility functions
function isCurrentCache(cacheName) {
    return [CACHE_NAME, STATIC_CACHE, DYNAMIC_CACHE, IMAGE_CACHE].includes(cacheName);
}

function isNetworkFirst(url) {
    return NETWORK_FIRST.some(pattern => url.includes(pattern));
}

function isCacheFirst(url) {
    return CACHE_FIRST.some(pattern => url.includes(pattern));
}

function isHTML(request) {
    return request.headers.get('accept')?.includes('text/html');
}

function isCacheableExternal(url) {
    return url.includes('fonts.googleapis.com') || 
           url.includes('fonts.gstatic.com') ||
           url.includes('cdnjs.cloudflare.com');
}

function getAppropriateCache(url) {
    if (url.includes('/assets/images/')) {
        return IMAGE_CACHE;
    }
    if (url.includes('/assets/')) {
        return STATIC_CACHE;
    }
    return DYNAMIC_CACHE;
}

// Background sync for form submissions
self.addEventListener('sync', (event) => {
    if (event.tag === 'quote-submission') {
        event.waitUntil(syncQuoteSubmissions());
    }
    if (event.tag === 'contact-submission') {
        event.waitUntil(syncContactSubmissions());
    }
});

// Handle quote submissions when back online
async function syncQuoteSubmissions() {
    try {
        const submissions = await getStoredSubmissions('quote');
        
        for (const submission of submissions) {
            try {
                const response = await fetch('/quote-handler.php', {
                    method: 'POST',
                    body: submission.data
                });
                
                if (response.ok) {
                    await removeStoredSubmission('quote', submission.id);
                    console.log('[SW] Quote submission synced:', submission.id);
                }
            } catch (error) {
                console.log('[SW] Failed to sync quote submission:', error);
            }
        }
    } catch (error) {
        console.log('[SW] Sync failed:', error);
    }
}

// Handle contact submissions when back online
async function syncContactSubmissions() {
    try {
        const submissions = await getStoredSubmissions('contact');
        
        for (const submission of submissions) {
            try {
                const response = await fetch('/contact-handler.php', {
                    method: 'POST',
                    body: submission.data
                });
                
                if (response.ok) {
                    await removeStoredSubmission('contact', submission.id);
                    console.log('[SW] Contact submission synced:', submission.id);
                }
            } catch (error) {
                console.log('[SW] Failed to sync contact submission:', error);
            }
        }
    } catch (error) {
        console.log('[SW] Sync failed:', error);
    }
}

// IndexedDB helpers for storing offline form submissions
async function getStoredSubmissions(type) {
    // Simplified version - in production use IndexedDB
    return [];
}

async function removeStoredSubmission(type, id) {
    // Simplified version - in production use IndexedDB
    return true;
}

// Push notification handling
self.addEventListener('push', (event) => {
    console.log('[SW] Push received');
    
    const options = {
        body: event.data ? event.data.text() : 'New notification from UK Data Services',
        icon: '/assets/images/favicon-192x192.png',
        badge: '/assets/images/badge-72x72.png',
        vibrate: [200, 100, 200],
        tag: 'ukds-notification',
        actions: [
            {
                action: 'view',
                title: 'View',
                icon: '/assets/images/icon-view.png'
            },
            {
                action: 'dismiss',
                title: 'Dismiss',
                icon: '/assets/images/icon-dismiss.png'
            }
        ]
    };
    
    event.waitUntil(
        self.registration.showNotification('UK Data Services', options)
    );
});

// Handle notification clicks
self.addEventListener('notificationclick', (event) => {
    console.log('[SW] Notification clicked');
    
    event.notification.close();
    
    if (event.action === 'view') {
        event.waitUntil(
            clients.openWindow('/')
        );
    }
});

// Periodic background sync (if supported)
self.addEventListener('periodicsync', (event) => {
    if (event.tag === 'update-cache') {
        event.waitUntil(updateCriticalResources());
    }
});

// Update critical resources in background
async function updateCriticalResources() {
    try {
        const cache = await caches.open(STATIC_CACHE);
        
        const updatePromises = [
            '/',
            '/assets/css/main.min.css',
            '/assets/js/main.min.js'
        ].map(url => 
            fetch(url).then(response => {
                if (response.ok) {
                    return cache.put(url, response);
                }
            }).catch(() => {
                // Ignore failed updates
            })
        );
        
        await Promise.all(updatePromises);
        console.log('[SW] Critical resources updated');
    } catch (error) {
        console.log('[SW] Failed to update critical resources:', error);
    }
}

// Message handling from main thread
self.addEventListener('message', (event) => {
    if (event.data && event.data.type === 'SKIP_WAITING') {
        self.skipWaiting();
    }
    
    if (event.data && event.data.type === 'CACHE_URLS') {
        event.waitUntil(
            cacheUrls(event.data.urls)
        );
    }
});

// Cache specific URLs on demand
async function cacheUrls(urls) {
    const cache = await caches.open(DYNAMIC_CACHE);
    
    const cachePromises = urls.map(url => 
        fetch(url).then(response => {
            if (response.ok) {
                return cache.put(url, response);
            }
        }).catch(() => {
            // Ignore failed caching
        })
    );
    
    await Promise.all(cachePromises);
}

// Analytics for service worker performance
function trackSWEvent(eventType, details = {}) {
    // Send analytics data when online
    if (navigator.onLine) {
        fetch('/analytics/sw-events', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                type: eventType,
                timestamp: Date.now(),
                ...details
            })
        }).catch(() => {
            // Ignore analytics failures
        });
    }
}