/**
 * Service Worker for Land Secure (Production)
 * For use with landsecureapp.com
 * Enables offline functionality and caching
 */

const CACHE_NAME = 'land-survey-v1';
const DATA_CACHE_NAME = 'land-survey-data-v1';

// Files to cache for offline use (production paths - no subdirectory)
const STATIC_ASSETS = [
    '/',
    '/dashboard',
    '/lands',
    '/add-land',
    '/alerts',
    '/profile',
    '/clients',
    '/assets/vendor/bootstrap/css/bootstrap.min.css',
    '/assets/vendor/jquery/jquery.min.js',
    '/assets/vendor/bootstrap/js/bootstrap.bundle.min.js',
    '/assets/font-awesome/css/all.min.css',
    '/assets/offline.html',
    '/assets/js/offline-storage.js'
];

// API endpoints that should be cached
const API_ROUTES = [
    '/api/lands.php',
    '/api/clients.php',
    '/api/beacon_points.php'
];

// Install event - cache static assets
self.addEventListener('install', event => {
    console.log('[SW] Installing Service Worker');
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache => {
                console.log('[SW] Caching static assets');
                return cache.addAll(STATIC_ASSETS.filter(url => {
                    // Only cache URLs that exist
                    return true;
                })).catch(err => {
                    console.log('[SW] Some assets failed to cache:', err);
                });
            })
            .then(() => self.skipWaiting())
    );
});

// 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.map(cacheName => {
                    if (cacheName !== CACHE_NAME && cacheName !== DATA_CACHE_NAME) {
                        console.log('[SW] Deleting old cache:', cacheName);
                        return caches.delete(cacheName);
                    }
                })
            );
        }).then(() => self.clients.claim())
    );
});

// Fetch event - serve from cache, fallback to network
self.addEventListener('fetch', event => {
    const requestUrl = new URL(event.request.url);

    // Handle API requests differently
    if (isApiRequest(event.request)) {
        event.respondWith(handleApiRequest(event.request));
        return;
    }

    // Handle POST requests (form submissions)
    if (event.request.method === 'POST') {
        event.respondWith(handlePostRequest(event.request));
        return;
    }

    // For other requests, try network first, then cache
    event.respondWith(
        fetch(event.request)
            .then(response => {
                // Cache the response
                if (response.status === 200) {
                    const responseClone = response.clone();
                    caches.open(CACHE_NAME).then(cache => {
                        cache.put(event.request, responseClone);
                    });
                }
                return response;
            })
            .catch(() => {
                // Network failed, try cache
                return caches.match(event.request)
                    .then(cachedResponse => {
                        if (cachedResponse) {
                            return cachedResponse;
                        }
                        // Return offline page for navigation requests
                        if (event.request.mode === 'navigate') {
                            return caches.match('/assets/offline.html');
                        }
                        return new Response('Offline', {
                            status: 503,
                            statusText: 'Service Unavailable'
                        });
                    });
            })
    );
});

// Check if request is to an API endpoint
function isApiRequest(request) {
    const url = new URL(request.url);
    return url.pathname.includes('/api/') ||
           url.pathname.includes('_ajax') ||
           request.headers.get('Accept')?.includes('application/json');
}

// Handle API requests with network-first strategy and IndexedDB fallback
async function handleApiRequest(request) {
    try {
        const response = await fetch(request);

        if (response.status === 200) {
            // Cache API response
            const cache = await caches.open(DATA_CACHE_NAME);
            cache.put(request, response.clone());

            // Notify clients about fresh data
            self.clients.matchAll().then(clients => {
                clients.forEach(client => {
                    client.postMessage({
                        type: 'API_RESPONSE_CACHED',
                        url: request.url
                    });
                });
            });
        }

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

        // Try to get from cache
        const cachedResponse = await caches.match(request);
        if (cachedResponse) {
            return cachedResponse;
        }

        // Return offline JSON response
        return new Response(JSON.stringify({
            offline: true,
            message: 'You are offline. Data will sync when connection is restored.',
            cached: false
        }), {
            status: 200,
            headers: { 'Content-Type': 'application/json' }
        });
    }
}

// Handle POST requests - store offline if network fails
async function handlePostRequest(request) {
    try {
        const response = await fetch(request.clone());
        return response;
    } catch (error) {
        console.log('[SW] POST request failed, queueing for sync');

        // Store the request for later sync
        const requestData = await serializeRequest(request);

        // Send message to client to store in IndexedDB
        self.clients.matchAll().then(clients => {
            clients.forEach(client => {
                client.postMessage({
                    type: 'OFFLINE_POST_REQUEST',
                    data: requestData
                });
            });
        });

        // Return a response indicating offline storage
        return new Response(JSON.stringify({
            offline: true,
            queued: true,
            message: 'Request saved. Will sync when online.'
        }), {
            status: 200,
            headers: { 'Content-Type': 'application/json' }
        });
    }
}

// Serialize a request for storage
async function serializeRequest(request) {
    const headers = {};
    for (const [key, value] of request.headers.entries()) {
        headers[key] = value;
    }

    let body = null;
    if (request.method !== 'GET' && request.method !== 'HEAD') {
        const contentType = request.headers.get('Content-Type') || '';
        if (contentType.includes('application/json')) {
            body = await request.json();
        } else if (contentType.includes('form')) {
            const formData = await request.formData();
            body = {};
            for (const [key, value] of formData.entries()) {
                body[key] = value;
            }
        } else {
            body = await request.text();
        }
    }

    return {
        url: request.url,
        method: request.method,
        headers: headers,
        body: body,
        timestamp: Date.now()
    };
}

// Background Sync
self.addEventListener('sync', event => {
    console.log('[SW] Background sync event:', event.tag);

    if (event.tag === 'sync-data') {
        event.waitUntil(syncOfflineData());
    }
});

// Sync offline data
async function syncOfflineData() {
    // Notify clients to sync their IndexedDB data
    const clients = await self.clients.matchAll();
    clients.forEach(client => {
        client.postMessage({
            type: 'TRIGGER_SYNC'
        });
    });
}

// Push notification handler
self.addEventListener('push', event => {
    const data = event.data?.json() || {};

    const options = {
        body: data.body || 'New notification from Land Secure App',
        icon: '/assets/images/icon-192.png',
        badge: '/assets/images/badge-72.png',
        vibrate: [100, 50, 100],
        data: {
            url: data.url || '/dashboard'
        }
    };

    event.waitUntil(
        self.registration.showNotification(data.title || 'Land Secure', options)
    );
});

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

    event.waitUntil(
        clients.openWindow(event.notification.data.url)
    );
});

// Message handler for client communication
self.addEventListener('message', event => {
    console.log('[SW] Message received:', event.data);

    if (event.data.type === 'SKIP_WAITING') {
        self.skipWaiting();
    }

    if (event.data.type === 'CACHE_URLS') {
        const urls = event.data.urls;
        caches.open(CACHE_NAME).then(cache => {
            cache.addAll(urls);
        });
    }

    if (event.data.type === 'CLEAR_CACHE') {
        caches.delete(CACHE_NAME);
        caches.delete(DATA_CACHE_NAME);
    }
});
