'use strict';
const STAMP = '1782335739';
const CACHE = 'forged-' + STAMP;
const NO_CACHE_PREFIXES = [];
const PRECACHE = ['/', '/offline'];

self.addEventListener('install', e => {
  e.waitUntil(
    caches.open(CACHE).then(c => c.addAll(PRECACHE)).then(() => self.skipWaiting())
  );
});

self.addEventListener('activate', e => {
  e.waitUntil(
    caches.keys()
      .then(ks => Promise.all(ks.filter(k => k !== CACHE).map(k => caches.delete(k))))
      .then(() => self.clients.claim())
  );
});

function cachePut(req, res) {
  if (res && res.ok) {
    const copy = res.clone();
    caches.open(CACHE).then(c => c.put(req, copy));
  }
  return res;
}

self.addEventListener('fetch', e => {
  const req = e.request;
  if (req.method !== 'GET') return;
  const url = new URL(req.url);
  if (url.origin !== self.location.origin) return;
  if (url.pathname === '/sw' || url.pathname === '/sw.js' || url.pathname === '/manifest.webmanifest') return;

  // Video: full passthrough — never intercept. SW-mediated Range requests
  // break seeking, and a hero MP4 must never land in cache storage.
  if (url.pathname.startsWith('/static/video/') || req.headers.has('range')) return;

  // Dynamic-publish sections (blog): network only, never cached.
  // Offline gets an honest /offline page, never a silently-stale post.
  if (NO_CACHE_PREFIXES.some(p => url.pathname.startsWith(p))) {
    e.respondWith(fetch(req).catch(() => caches.match('/offline')));
    return;
  }

  // Static assets: cache-first inside the stamped cache (unhashed
  // filenames — staleness bounded to one deploy by the activate purge).
  // Note: /static/video/ already returned above — videos are never cached.
  if (url.pathname.startsWith('/static/') || url.pathname.startsWith('/uploads/')) {
    e.respondWith(
      caches.match(req).then(hit => hit || fetch(req).then(res => cachePut(req, res)))
    );
    return;
  }

  // HTML navigation: network-first, cache fallback, then /offline.
  const accept = req.headers.get('accept') || '';
  if (req.mode === 'navigate' || accept.includes('text/html')) {
    e.respondWith(
      fetch(req)
        .then(res => cachePut(req, res))
        .catch(() => caches.match(req).then(hit => hit || caches.match('/offline')))
    );
  }
});
