// SIMAK PWA Service Worker
// Version: increment on every significant change to force update
const CACHE_VERSION = 'simak-v2';
const STATIC_CACHE = CACHE_VERSION + '-static';
const RUNTIME_CACHE = CACHE_VERSION + '-runtime';

// Static assets - safe to cache aggressively (Cache First)
const STATIC_ASSETS = [
  '/',
  '/offline.html',
  '/assets/img/icons/icon-72x72.png',
  '/assets/img/icons/icon-96x96.png',
  '/assets/img/icons/icon-128x128.png',
  '/assets/img/icons/icon-144x144.png',
  '/assets/img/icons/icon-152x152.png',
  '/assets/img/icons/icon-192x192.png',
  '/assets/img/icons/icon-384x384.png',
  '/assets/img/icons/icon-512x512.png',
  '/assets/img/logo-sekolah-default.png',
  '/assets/img/logo-kemenag-default.png',
  '/css/wizard_style.css',
  '/manifest.json'
];

// CDN assets - cache with caution
const CDN_ASSETS = [
  'cdn.jsdelivr.net',
  'cdn.datatables.net',
  'fonts.googleapis.com',
  'fonts.gstatic.com',
  'code.jquery.com'
];

// Paths that must NEVER be cached (Network Only)
const UNCACHEABLE_PATHS = [
  '/login',
  '/logout',
  '/activate',
  '/install',
  '/api/',
  '/admin/',
  '/guru/',
  '/siswa/',
  '/tata-usaha/',
  '/kamad/',
  '/manual-schedule/',
  '/schedule-generator/',
  '/updater',
  '/user-management/',
  '/debugbar',
  '/csrf'
];

// Dynamic paths - use Network First with runtime cache fallback
const DYNAMIC_BASE = [
  '/dashboard'
];

// ─── INSTALL ────────────────────────────────────────────────
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(STATIC_CACHE).then(cache => {
      return cache.addAll(STATIC_ASSETS);
    }).then(() => self.skipWaiting())
  );
});

// ─── ACTIVATE ───────────────────────────────────────────────
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(keys => {
      return Promise.all(
        keys.filter(key => key.startsWith('simak-') && key !== STATIC_CACHE && key !== RUNTIME_CACHE)
          .map(key => caches.delete(key))
      );
    }).then(() => self.clients.claim())
  );
});

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

  // Only handle same-origin and CDN requests
  if (url.origin !== self.location.origin && !CDN_ASSETS.some(d => url.hostname.includes(d))) {
    return;
  }

  // ── Network Only: never cache sensitive/dynamic operations ──
  if (request.method !== 'GET') {
    return;
  }

  const path = url.pathname + url.search;

  // Check if path is uncacheable
  if (UNCACHEABLE_PATHS.some(p => path.startsWith(p))) {
    return; // Browser handles normally via network
  }

  // ── Static Assets: Cache First ──
  if (isStaticAsset(path, url)) {
    event.respondWith(cacheFirst(request));
    return;
  }

  // ── CDN Assets: Stale While Revalidate ──
  if (CDN_ASSETS.some(d => url.hostname.includes(d))) {
    event.respondWith(staleWhileRevalidate(request));
    return;
  }

  // ── Dynamic Pages: Network First with offline fallback ──
  if (isDynamicPath(path)) {
    event.respondWith(networkFirst(request));
    return;
  }

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

// ─── STRATEGIES ─────────────────────────────────────────────

function cacheFirst(request) {
  return caches.match(request).then(cached => {
    if (cached) return cached;
    return fetch(request).then(response => {
      if (response && response.status === 200) {
        const clone = response.clone();
        caches.open(STATIC_CACHE).then(cache => cache.put(request, clone));
      }
      return response;
    });
  });
}

function networkFirst(request) {
  return fetch(request).then(response => {
    if (response && response.status === 200) {
      const clone = response.clone();
      caches.open(RUNTIME_CACHE).then(cache => cache.put(request, clone));
    }
    return response;
  }).catch(() => {
    return caches.match(request).then(cached => {
      if (cached) return cached;
      // If navigating to a page, show offline page
      if (request.mode === 'navigate') {
        return caches.match('/offline.html');
      }
      return new Response('', { status: 503, statusText: 'Offline' });
    });
  });
}

function staleWhileRevalidate(request) {
  return caches.open(RUNTIME_CACHE).then(cache => {
    return cache.match(request).then(cached => {
      const fetchPromise = fetch(request).then(response => {
        if (response && response.status === 200) {
          cache.put(request, response.clone());
        }
        return response;
      });
      return cached || fetchPromise;
    });
  });
}

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

function isStaticAsset(path, url) {
  const staticExtensions = [
    '.css', '.js', '.png', '.jpg', '.jpeg', '.gif', '.svg',
    '.ico', '.woff', '.woff2', '.ttf', '.eot', '.webp', '.json',
    '.mp4', '.webm'
  ];
  if (staticExtensions.some(ext => path.toLowerCase().endsWith(ext))) return true;
  if (path === '/manifest.json') return true;
  if (path === '/offline.html') return true;
  return false;
}

function isDynamicPath(path) {
  return DYNAMIC_BASE.some(b => path === b || path === b + '/');
}

// ─── MESSAGE HANDLING ───────────────────────────────────────

self.addEventListener('message', event => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
  if (event.data && event.data.type === 'GET_VERSION') {
    if (event.ports && event.ports[0]) {
      event.ports[0].postMessage({ version: CACHE_VERSION });
    }
  }
});