/* eslint-disable no-restricted-globals */
/**
 * AsignaPro — Service Worker
 *
 * - Navegación: NetworkFirst con fallback a /offline.
 * - Assets públicos/build/media: StaleWhileRevalidate.
 * - Formularios, Livewire, auth y APIs: siempre red.
 */

const APP_VERSION = 'asignapro-pwa-v4-20260509';
const RUNTIME_CACHE = 'asignapro-runtime-v4-20260509';

const PRECACHE_URLS = [
    '/offline',
    '/manifest.json',
    '/manifest.webmanifest',
    '/favicon.png',
    '/apple-touch-icon.png',
    '/assets/brand/loading-logo.png',
    '/icons/icon-192x192.png',
    '/icons/icon-192x192-maskable.png',
    '/icons/icon-512x512.png',
    '/icons/icon-512x512-maskable.png',
];

self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open(APP_VERSION).then((cache) =>
            cache.addAll(PRECACHE_URLS).catch(() => undefined)
        )
    );
    self.skipWaiting();
});

self.addEventListener('activate', (event) => {
    event.waitUntil(
        caches.keys().then((keys) =>
            Promise.all(
                keys
                    .filter((key) => ![APP_VERSION, RUNTIME_CACHE].includes(key))
                    .map((key) => caches.delete(key))
            )
        )
    );
    self.clients.claim();
});

self.addEventListener('fetch', (event) => {
    const request = event.request;
    if (request.method !== 'GET') return;

    const url = new URL(request.url);
    if (url.origin !== self.location.origin) return;

    const neverCachePrefixes = [
        '/livewire/',
        '/logout',
        '/sanctum/',
        '/api/',
    ];

    if (neverCachePrefixes.some((path) => url.pathname.startsWith(path))) {
        return;
    }

    const acceptsHtml = (request.headers.get('accept') || '').includes('text/html');

    if (request.mode === 'navigate' || acceptsHtml) {
        event.respondWith(
            fetch(request)
                .then((response) => {
                    if (response.ok) {
                        const copy = response.clone();
                        caches.open(RUNTIME_CACHE).then((cache) => cache.put(request, copy)).catch(() => undefined);
                    }

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

    const isStaticAsset =
        url.pathname.startsWith('/build/') ||
        url.pathname.startsWith('/icons/') ||
        url.pathname.startsWith('/assets/') ||
        url.pathname.startsWith('/media/') ||
        url.pathname.startsWith('/storage/') ||
        /\.(png|jpe?g|webp|svg|gif|ico|woff2?|ttf|css|js)$/.test(url.pathname);

    if (isStaticAsset) {
        event.respondWith(
            caches.match(request).then((cached) => {
                const network = fetch(request)
                    .then((response) => {
                        if (response.ok) {
                            const copy = response.clone();
                            caches.open(RUNTIME_CACHE).then((cache) => cache.put(request, copy)).catch(() => undefined);
                        }

                        return response;
                    })
                    .catch(() => cached);

                return cached || network;
            })
        );
    }
});

self.addEventListener('push', (event) => {
    const fallback = {
        title: 'AsignaPro',
        body: 'Tienes una nueva actualización en tu agenda.',
        data: { url: '/empresa/dashboard' },
    };

    let payload = fallback;

    if (event.data) {
        try {
            payload = { ...fallback, ...event.data.json() };
        } catch (_) {
            payload = { ...fallback, body: event.data.text() };
        }
    }

    const options = {
        body: payload.body || payload.message || fallback.body,
        icon: payload.icon || '/icons/icon-192x192.png',
        badge: payload.badge || '/icons/icon-192x192.png',
        image: payload.image,
        tag: payload.tag || 'asignapro-notification',
        renotify: Boolean(payload.renotify),
        requireInteraction: Boolean(payload.requireInteraction),
        data: payload.data || { url: payload.url || '/empresa/dashboard' },
        actions: payload.actions || [],
    };

    event.waitUntil(
        self.registration.showNotification(payload.title || fallback.title, options)
    );
});

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

    const targetUrl = event.notification.data?.url || '/empresa/dashboard';
    const url = new URL(targetUrl, self.location.origin).href;

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

            if (clients.openWindow) {
                return clients.openWindow(url);
            }

            return undefined;
        })
    );
});
