// Service Worker for Control Center UI
// Version: 1.0.0

const CACHE_NAME = 'control-center-ui-v1.0.0';
const STATIC_CACHE = `${CACHE_NAME}-static`;
const DYNAMIC_CACHE = `${CACHE_NAME}-dynamic`;

// Static assets to cache on install
const STATIC_ASSETS = [
    '/',
    '/index.html',
    '/manifest.json',
    '/style/input.css',
    '/assets/icon-192.png',
    '/assets/icon-512.png'
];

// API endpoints that should be cached with network-first strategy
const API_ENDPOINTS = [
    '/api/health',
    '/api/dashboard',
    '/api/servers',
    '/api/clusters'
];

// Assets that should never be cached
const NO_CACHE_PATTERNS = [
    '/api/auth/',
    '/api/logout',
    '/api/websocket'
];

// Install event - cache static assets
self.addEventListener('install', (event) => {
    console.log('[SW] Installing service worker...');

    event.waitUntil(
        caches.open(STATIC_CACHE)
            .then((cache) => {
                console.log('[SW] Caching static assets');
                return cache.addAll(STATIC_ASSETS);
            })
            .then(() => {
                console.log('[SW] Installation complete');
                return self.skipWaiting(); // Force activation
            })
            .catch((error) => {
                console.error('[SW] Installation failed:', error);
            })
    );
});

// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
    console.log('[SW] Activating service worker...');

    event.waitUntil(
        caches.keys()
            .then((cacheNames) => {
                return Promise.all(
                    cacheNames
                        .filter(cacheName =>
                            cacheName.startsWith('control-center-ui-') &&
                            cacheName !== STATIC_CACHE &&
                            cacheName !== DYNAMIC_CACHE
                        )
                        .map(cacheName => {
                            console.log('[SW] Deleting old cache:', cacheName);
                            return caches.delete(cacheName);
                        })
                );
            })
            .then(() => {
                console.log('[SW] Activation complete');
                return self.clients.claim(); // Take control of all clients
            })
    );
});

// Fetch event - handle network requests
self.addEventListener('fetch', (event) => {
    const request = event.request;
    const url = new URL(request.url);

    // Skip non-GET requests and chrome-extension requests
    if (request.method !== 'GET' || url.protocol === 'chrome-extension:') {
        return;
    }

    // Skip requests that should never be cached
    if (NO_CACHE_PATTERNS.some(pattern => url.pathname.includes(pattern))) {
        return;
    }

    // Handle different types of requests
    if (isStaticAsset(url)) {
        event.respondWith(handleStaticAsset(request));
    } else if (isAPIRequest(url)) {
        event.respondWith(handleAPIRequest(request));
    } else {
        event.respondWith(handleNavigation(request));
    }
});

// Check if request is for a static asset
function isStaticAsset(url) {
    const staticExtensions = ['.js', '.css', '.png', '.jpg', '.jpeg', '.svg', '.ico', '.woff', '.woff2'];
    return staticExtensions.some(ext => url.pathname.endsWith(ext)) ||
           url.pathname.includes('/assets/');
}

// Check if request is for API
function isAPIRequest(url) {
    return url.pathname.startsWith('/api/');
}

// Handle static assets with cache-first strategy
async function handleStaticAsset(request) {
    try {
        const cachedResponse = await caches.match(request);
        if (cachedResponse) {
            console.log('[SW] Serving static asset from cache:', request.url);
            return cachedResponse;
        }

        // Fetch from network and cache
        const networkResponse = await fetch(request);
        if (networkResponse.ok) {
            const cache = await caches.open(STATIC_CACHE);
            cache.put(request, networkResponse.clone());
            console.log('[SW] Cached static asset:', request.url);
        }

        return networkResponse;
    } catch (error) {
        console.error('[SW] Failed to handle static asset:', error);

        // Return a cached fallback if available
        const cachedResponse = await caches.match(request);
        if (cachedResponse) {
            return cachedResponse;
        }

        // Return a generic error response for images
        if (request.url.includes('.png') || request.url.includes('.jpg') || request.url.includes('.svg')) {
            return new Response('', { status: 404, statusText: 'Image not found' });
        }

        throw error;
    }
}

// Handle API requests with network-first strategy
async function handleAPIRequest(request) {
    try {
        // Always try network first for API requests
        const networkResponse = await fetch(request);

        if (networkResponse.ok && API_ENDPOINTS.some(endpoint => request.url.includes(endpoint))) {
            // Cache successful responses for specific endpoints
            const cache = await caches.open(DYNAMIC_CACHE);
            cache.put(request, networkResponse.clone());
            console.log('[SW] Cached API response:', request.url);
        }

        return networkResponse;
    } catch (error) {
        console.error('[SW] Network request failed, trying cache:', error);

        // Fallback to cache if network fails
        const cachedResponse = await caches.match(request);
        if (cachedResponse) {
            console.log('[SW] Serving API response from cache:', request.url);
            return cachedResponse;
        }

        // Return a generic offline response
        return new Response(
            JSON.stringify({
                error: 'Offline',
                message: 'This request is not available offline'
            }),
            {
                status: 503,
                statusText: 'Service Unavailable',
                headers: { 'Content-Type': 'application/json' }
            }
        );
    }
}

// Handle navigation requests (SPA routing)
async function handleNavigation(request) {
    try {
        // Try network first
        const networkResponse = await fetch(request);
        return networkResponse;
    } catch (error) {
        console.log('[SW] Network failed for navigation, serving index.html from cache');

        // For navigation requests, serve index.html from cache (SPA routing)
        const cachedResponse = await caches.match('/index.html');
        if (cachedResponse) {
            return cachedResponse;
        }

        // Fallback offline page
        return new Response(`
            <!DOCTYPE html>
            <html>
            <head>
                <title>Control Center - Offline</title>
                <style>
                    body {
                        font-family: system-ui, sans-serif;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        min-height: 100vh;
                        margin: 0;
                        background: #f3f4f6;
                    }
                    .offline {
                        text-align: center;
                        padding: 2rem;
                        background: white;
                        border-radius: 0.5rem;
                        box-shadow: 0 4px 6px rgba(0,0,0,0.1);
                    }
                </style>
            </head>
            <body>
                <div class="offline">
                    <h1>You're Offline</h1>
                    <p>Please check your internet connection and try again.</p>
                    <button onclick="window.location.reload()">Retry</button>
                </div>
            </body>
            </html>
        `, {
            status: 200,
            statusText: 'OK',
            headers: { 'Content-Type': 'text/html' }
        });
    }
}

// Handle messages from the main thread
self.addEventListener('message', (event) => {
    const { type, payload } = event.data;

    switch (type) {
        case 'SKIP_WAITING':
            self.skipWaiting();
            break;

        case 'CLEAR_CACHE':
            clearAllCaches();
            break;

        case 'GET_CACHE_STATUS':
            getCacheStatus().then(status => {
                event.ports[0].postMessage(status);
            });
            break;

        default:
            console.log('[SW] Unknown message type:', type);
    }
});

// Clear all caches
async function clearAllCaches() {
    try {
        const cacheNames = await caches.keys();
        await Promise.all(
            cacheNames.map(cacheName => caches.delete(cacheName))
        );
        console.log('[SW] All caches cleared');
    } catch (error) {
        console.error('[SW] Failed to clear caches:', error);
    }
}

// Get cache status
async function getCacheStatus() {
    try {
        const cacheNames = await caches.keys();
        const status = {};

        for (const cacheName of cacheNames) {
            const cache = await caches.open(cacheName);
            const keys = await cache.keys();
            status[cacheName] = keys.length;
        }

        return status;
    } catch (error) {
        console.error('[SW] Failed to get cache status:', error);
        return {};
    }
}

// Handle background sync (if supported)
self.addEventListener('sync', (event) => {
    if (event.tag === 'background-sync') {
        console.log('[SW] Background sync triggered');
        event.waitUntil(performBackgroundSync());
    }
});

// Perform background sync
async function performBackgroundSync() {
    try {
        // Sync any pending data when back online
        const clients = await self.clients.matchAll();
        clients.forEach(client => {
            client.postMessage({ type: 'BACKGROUND_SYNC' });
        });
    } catch (error) {
        console.error('[SW] Background sync failed:', error);
    }
}

// Handle push notifications (if needed in the future)
self.addEventListener('push', (event) => {
    if (event.data) {
        const data = event.data.json();
        const options = {
            body: data.body,
            icon: '/assets/icon-192.png',
            badge: '/assets/icon-72.png',
            tag: 'control-center-notification',
            requireInteraction: true,
            actions: data.actions || []
        };

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

// Handle notification clicks
self.addEventListener('notificationclick', (event) => {
    event.notification.close();

    event.waitUntil(
        clients.openWindow('/')
    );
});

console.log('[SW] Service worker script loaded successfully');
