/**
 * ai-cli PWA Service Worker
 * Caches app shell (HTML/CSS/JS/icons) for fast startup.
 * API calls and WebSocket are always network-first.
 */

// v0.4.159: self-updating SW. Bumped to v3. The old v1/v2 service workers kept
// serving a stale index.html/app.js (no Hub tab, broken Light theme) because a
// new SW only "waits" — it never told the page to reload. Now: install →
// skipWaiting (take over immediately), activate → evict old caches + claim +
// postMessage('reload') so every open tab refreshes once onto the new version.
// index.html / app.js are NEVER cached (always network), so a plain refresh
// after upgrade is enough even before the SW turns over.
const CACHE_NAME = 'aicli-v3';

// HTML/JS that must always be fresh — never served from the SW cache, so an
// upgraded server is reflected on the very next load. Other assets (vendored
// CSS/JS, icons) are large + content-stable and fine to cache.
const NEVER_CACHE = new Set(['/', '/index.html', '/app.js']);

// App shell to precache (offline-capable startup). Deliberately EXCLUDES the
// always-fresh HTML/JS in NEVER_CACHE — only large content-stable assets.
const APP_SHELL = [
  '/style.css',
  '/manifest.json',
  '/icon.svg',
  '/icon-192.png',
  '/icon-512.png',
  '/vendor/daisyui-full.min.css',
  '/vendor/tailwind.js',
  '/vendor/marked.min.js',
  '/vendor/highlight.min.js',
  '/vendor/github-dark.min.css',
  '/vendor/github.min.css',
];

self.addEventListener('install', (event) => {
  // Take over immediately rather than waiting for all old tabs to close.
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(APP_SHELL))
      .then(() => self.skipWaiting())
  );
});

self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys()
      .then(keys => Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k))))
      .then(() => self.clients.claim())
      .then(async () => {
        // Tell every open tab a new version is live so it can reload once.
        const clients = await self.clients.matchAll({ type: 'window' });
        for (const c of clients) c.postMessage({ type: 'sw-updated' });
      })
  );
});

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

  // Never intercept API calls or WebSocket upgrades.
  if (url.pathname.startsWith('/api/') || event.request.headers.get('upgrade') === 'websocket') {
    return;
  }

  // Always-fresh HTML/JS: network-only, never touch the cache. Guarantees an
  // upgraded server shows up on the next load even if the SW hasn't turned over.
  if (NEVER_CACHE.has(url.pathname)) {
    event.respondWith(fetch(event.request).catch(() => caches.match(event.request)));
    return;
  }

  // Everything else: network-first with cache fallback (offline support).
  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))
  );
});
