/**
 * Service Worker — Plataforma Ganadera PWA (cPanel)
 * Auto-detecta el subdirectorio base
 */

// Detectar base path del scope del SW
const SW_BASE = self.registration ? new URL(self.registration.scope).pathname.replace(/\/$/, '') : '';
const CACHE_NAME = 'ganadera-v6.0.0';
const STATIC_CACHE = 'ganadera-static-v6.0.0';
const DYNAMIC_CACHE = 'ganadera-dynamic-v6.0.0';

// Assets estáticos para cachear inmediatamente
const STATIC_ASSETS = [
    SW_BASE + '/',
    SW_BASE + '/login',
    SW_BASE + '/offline.html',
    SW_BASE + '/assets/css/app.css',
    SW_BASE + '/assets/js/icons.js',
    SW_BASE + '/assets/js/app.js',
    SW_BASE + '/assets/js/api.js',
    SW_BASE + '/assets/img/favicon.png',
    SW_BASE + '/assets/img/logo-sidebar.png',
    SW_BASE + '/assets/img/logo-login.png',
    SW_BASE + '/manifest.json',
];

// ─── INSTALL ────────────────────────────────────────────────
self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open(STATIC_CACHE).then((cache) => {
            console.log('[SW] Caching static assets');
            return cache.addAll(STATIC_ASSETS);
        })
    );
    // Force activate immediately — don't wait for user action
    self.skipWaiting();
});

// ─── MESSAGE HANDLER (skip waiting on demand) ───────────────
self.addEventListener('message', (event) => {
    if (event.data && event.data.type === 'SKIP_WAITING') {
        self.skipWaiting();
    }
});

// ─── ACTIVATE ───────────────────────────────────────────────
self.addEventListener('activate', (event) => {
    event.waitUntil(
        caches.keys().then((keys) => {
            return Promise.all(
                keys
                    .filter((key) => key !== STATIC_CACHE && key !== DYNAMIC_CACHE && key !== CACHE_NAME)
                    .map((key) => {
                        console.log('[SW] Deleting old cache:', key);
                        return caches.delete(key);
                    })
            );
        })
    );
    self.clients.claim();
});

// ─── FETCH ──────────────────────────────────────────────────
self.addEventListener('fetch', (event) => {
    const { request } = event;

    // Ignorar esquemas no-HTTP (chrome-extension, etc.)
    if (!request.url.startsWith('http')) return;

    const url = new URL(request.url);

    // En localhost/desarrollo: siempre network-only, nunca offline fallback
    if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {
        if (request.mode === 'navigate') {
            event.respondWith(
                fetch(request).catch(() => caches.match(request))
            );
        }
        return;
    }

    // No cachear peticiones API (excepto GET de catálogos)
    if (url.pathname.startsWith('/api/')) {
        // Para GET de catálogos, usar Network First
        if (request.method === 'GET' && isCacheableApi(url.pathname)) {
            event.respondWith(networkFirst(request));
        }
        return; // Dejar pasar sin interceptar otras API calls
    }

    // Para uploads/fotos: Network only, no interceptar — dejar al browser manejar
    if (url.pathname.startsWith('/uploads/')) {
        return; // No interceptar, fetch natural del browser
    }

    // Para assets estáticos: Network First (para garantizar frescura)
    if (isStaticAsset(url.pathname)) {
        event.respondWith(networkFirst(request));
        return;
    }

    // Para navegación: Network First con fallback
    if (request.mode === 'navigate') {
        event.respondWith(networkFirst(request));
        return;
    }

    // Default: Network First
    event.respondWith(networkFirst(request));
});

// ─── PUSH NOTIFICATIONS ────────────────────────────────────
self.addEventListener('push', (event) => {
    let data = { title: 'Plataforma Ganadera', body: 'Nueva notificación' };

    if (event.data) {
        try {
            data = event.data.json();
        } catch (e) {
            data.body = event.data.text();
        }
    }

    const options = {
        body: data.body || data.message,
        icon: '/assets/img/icons/icon-192x192.png',
        badge: '/assets/img/icons/icon-72x72.png',
        vibrate: [200, 100, 200],
        data: {
            url: data.url || data.action_url || '/',
        },
        actions: data.actions || [],
        tag: data.tag || 'ganadera-notification',
        renotify: true,
    };

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

self.addEventListener('notificationclick', (event) => {
    event.notification.close();
    const url = event.notification.data?.url || '/';

    event.waitUntil(
        clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
            for (const client of clientList) {
                if (client.url.includes(url) && 'focus' in client) {
                    return client.focus();
                }
            }
            return clients.openWindow(url);
        })
    );
});

// ─── BACKGROUND SYNC ───────────────────────────────────────
self.addEventListener('sync', (event) => {
    if (event.tag === 'sync-pending-data') {
        event.waitUntil(syncPendingData());
    }
});

// ─── ESTRATEGIAS DE CACHÉ ──────────────────────────────────

async function cacheFirst(request) {
    const cached = await caches.match(request);
    if (cached) return cached;

    try {
        const response = await fetch(request);
        if (response.ok) {
            const cache = await caches.open(STATIC_CACHE);
            cache.put(request, response.clone());
        }
        return response;
    } catch (e) {
        return new Response('', { status: 408, statusText: 'Offline' });
    }
}

async function networkFirst(request) {
    try {
        const response = await fetch(request, { cache: 'no-cache' });
        // Cache successful responses only
        if (response.ok) {
            const cache = await caches.open(DYNAMIC_CACHE);
            cache.put(request, response.clone());
        }
        return response;
    } catch (e) {
        // Network failed — try cache
        const cached = await caches.match(request);
        if (cached) return cached;

        // Navigation → offline fallback
        if (request.mode === 'navigate') {
            const offlinePage = await caches.match(SW_BASE + '/offline.html');
            if (offlinePage) return offlinePage;
            // Return a user-friendly offline page
            return new Response(
                '<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Sin conexión</title><style>body{font-family:Inter,sans-serif;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#f1f5f9;color:#334155;text-align:center}div{padding:2rem}.icon{font-size:3rem;margin-bottom:1rem}h2{margin:0 0 .5rem}p{color:#64748b;margin:0 0 1.5rem}a{background:#047857;color:#fff;padding:10px 24px;border-radius:8px;text-decoration:none;font-weight:600}</style></head><body><div><div class="icon">📡</div><h2>Sin conexión</h2><p>Verifica tu conexión a internet e intenta de nuevo.</p><a href="javascript:location.reload()">Reintentar</a></div></body></html>',
                { status: 503, headers: { 'Content-Type': 'text/html; charset=utf-8' } }
            );
        }

        // For non-navigation resources: let browser handle gracefully
        return new Response('', {
            status: 408,
            statusText: 'Offline - recurso no disponible',
        });
    }
}

// ─── HELPERS ────────────────────────────────────────────────

function isStaticAsset(pathname) {
    return /\.(css|js|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$/i.test(pathname);
}

function isCacheableApi(pathname) {
    const cacheablePatterns = [
        '/api/species',
        '/api/breeds',
        '/api/vaccines',
        '/api/settings/catalogs',
    ];
    return cacheablePatterns.some((p) => pathname.startsWith(p));
}

async function syncPendingData() {
    // Sincronizar datos pendientes almacenados en IndexedDB
    // cuando se recupere la conexión
    try {
        const db = await openIndexedDB();
        const pending = await getPendingRequests(db);

        for (const item of pending) {
            try {
                await fetch(item.url, {
                    method: item.method,
                    headers: item.headers,
                    body: item.body,
                });
                await removePendingRequest(db, item.id);
            } catch (e) {
                console.log('[SW] Sync failed for:', item.url);
            }
        }
    } catch (e) {
        console.log('[SW] Sync error:', e);
    }
}

function openIndexedDB() {
    return new Promise((resolve, reject) => {
        const request = indexedDB.open('ganadera-offline', 1);
        request.onupgradeneeded = (e) => {
            const db = e.target.result;
            if (!db.objectStoreNames.contains('pending')) {
                db.createObjectStore('pending', { keyPath: 'id', autoIncrement: true });
            }
        };
        request.onsuccess = (e) => resolve(e.target.result);
        request.onerror = (e) => reject(e.target.error);
    });
}

function getPendingRequests(db) {
    return new Promise((resolve, reject) => {
        const tx = db.transaction('pending', 'readonly');
        const store = tx.objectStore('pending');
        const request = store.getAll();
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
    });
}

function removePendingRequest(db, id) {
    return new Promise((resolve, reject) => {
        const tx = db.transaction('pending', 'readwrite');
        const store = tx.objectStore('pending');
        const request = store.delete(id);
        request.onsuccess = () => resolve();
        request.onerror = () => reject(request.error);
    });
}
