// Tapecast Service Worker — Stufe 1
// Cache-Strategie:
//  - App-Shell (HTML/JS/CSS/Icons): stale-while-revalidate
//  - Beats (/beats/*.mp3): cache-first (loop-perfect, ändern sich nie)
//  - API (/api/*): network-only (immer fresh, Recordings)
//  - Recording-Audio (/api/recordings/:id/audio): network-only mit Range-Support
//
// Wir touchen ABSICHTLICH KEINE recordings — Audio-Files sind groß und werden vom Browser
// per Range-Request geladen, Caching macht hier mehr Stress als Nutzen.

const CACHE_VERSION = 'tapecast-v1';
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
const BEATS_CACHE = `${CACHE_VERSION}-beats`;

const SHELL_ASSETS = [
  './',
  './index.html',
  './manifest.webmanifest',
  './favicon.svg',
  './icons/icon-192.png',
  './icons/icon-512.png',
  './icons/apple-touch-icon.png',
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(SHELL_CACHE).then((cache) =>
      cache.addAll(SHELL_ASSETS).catch((err) => {
        // Manche Assets sind beim ersten Install noch nicht da – nicht fatal.
        console.warn('[SW] shell precache partial:', err);
      })
    )
  );
  self.skipWaiting();
});

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

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

  // Nur GET cachen.
  if (req.method !== 'GET') return;

  // API: NIE cachen (Recordings dynamisch).
  if (url.pathname.startsWith('/api/')) {
    return; // default network
  }

  // Recordings-Audio (auch mit Range-Header): nie cachen.
  if (url.pathname.includes('/api/recordings/') && url.pathname.endsWith('/audio')) {
    return;
  }

  // Beats: cache-first.
  if (url.pathname.startsWith('/beats/') && url.pathname.endsWith('.mp3')) {
    event.respondWith(
      caches.open(BEATS_CACHE).then(async (cache) => {
        const cached = await cache.match(req);
        if (cached) return cached;
        try {
          const fresh = await fetch(req);
          if (fresh.ok && fresh.status === 200) {
            cache.put(req, fresh.clone());
          }
          return fresh;
        } catch (err) {
          return cached || Response.error();
        }
      })
    );
    return;
  }

  // App-Shell & restliche Assets: stale-while-revalidate.
  // Cross-Origin (z.B. Google Fonts) ohnehin durchwinken.
  if (url.origin !== self.location.origin) return;

  event.respondWith(
    caches.open(SHELL_CACHE).then(async (cache) => {
      const cached = await cache.match(req);
      const fetchPromise = fetch(req)
        .then((res) => {
          if (res && res.ok && res.status === 200) {
            cache.put(req, res.clone());
          }
          return res;
        })
        .catch(() => null);

      // Wenn online, dann Cache aktualisieren, aber sofort cached zurückgeben.
      if (cached) {
        fetchPromise; // fire & forget
        return cached;
      }
      const fresh = await fetchPromise;
      if (fresh) return fresh;

      // Letzter Fallback: index.html aus dem Cache (SPA shell).
      const shell = await cache.match('./index.html');
      if (shell) return shell;
      return Response.error();
    })
  );
});
