// ═══════════════════════════════════════════════════════════════════════════
// Canteen Asset Tracker — Service Worker
// Caches app shell + CDN deps. Network-first for API, cache fallback for static.
// ═══════════════════════════════════════════════════════════════════════════

const CACHE_NAME = 'canteen-v3';

// App shell — core resources needed to boot the PWA
const APP_SHELL = [
  '/',
  '/index.html',
];

// CDN resources we want cached for offline resilience
const CDN_URLS = [
  'https://cdn.jsdelivr.net/npm/@zxing/library@0.20.0/umd/index.min.js',
  'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css',
  'https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.css',
  'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',
  'https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.js',
  'https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js',
];

// ── Install: pre-cache app shell + CDN resources ──────────────────────────

self.addEventListener('install', (event) => {
  console.log('[SW] Install — caching app shell + CDN assets');
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.addAll([...APP_SHELL, ...CDN_URLS]).catch((err) => {
        console.warn('[SW] Some resources failed to cache (non-fatal):', err.message);
      });
    })
  );
  // Activate immediately — don't wait for old SW to release
  self.skipWaiting();
});

// ── Activate: purge old caches ────────────────────────────────────────────

self.addEventListener('activate', (event) => {
  console.log('[SW] Activate — purging old caches');
  event.waitUntil(
    caches.keys().then((keys) => {
      return Promise.all(
        keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k))
      );
    })
  );
  // Take control of all clients immediately
  self.clients.claim();
});

// ── Fetch: network-first for everything, cache fallback ───────────────────

self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url);

  // Navigation requests: network-first, fallback to cached index.html
  if (event.request.mode === 'navigate') {
    event.respondWith(
      fetch(event.request)
        .then((response) => {
          // Cache the latest version
          const clone = response.clone();
          caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
          return response;
        })
        .catch(() => {
          return caches.match(event.request).then((cached) => cached || caches.match('/'));
        })
    );
    return;
  }

  // API GET calls: network-first, cache fallback (offline reads)
  // API POST/PUT/DELETE: pass through — main thread handles offline queuing
  if (url.pathname.startsWith('/api/')) {
    if (event.request.method === 'GET') {
      event.respondWith(
        fetch(event.request)
          .then((response) => {
            if (response.ok) {
              const clone = response.clone();
              caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
            }
            return response;
          })
          .catch(() => caches.match(event.request))
      );
    }
    // Non-GET API calls: pass through — main thread queues offline writes
    return;
  }

  // Static assets (local + CDN): network-first, cache fallback
  event.respondWith(
    fetch(event.request)
      .then((response) => {
        if (response.ok) {
          const clone = response.clone();
          caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
        }
        return response;
      })
      .catch(() => {
        return caches.match(event.request);
      })
  );
});

// ── Message handler: allow main thread to trigger queue sync ──────────────

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SYNC_QUEUE') {
    // Forward sync request to all controlled clients
    self.clients.matchAll().then((clients) => {
      clients.forEach((client) => {
        client.postMessage({ type: 'PROCESS_OFFLINE_QUEUE' });
      });
    });
  }
});
