// TeeCup service worker (ADR-028) -- håndskrevet, ingen next-pwa/workbox-
// avhengighet. To ansvar, begge begrenset med vilje:
//
// 1) Cache side-NAVIGASJON (nettverk først, cache som fallback, offline.html
//    som siste utvei) -- en tidligere besøkt side kan åpnes på nytt uten
//    nett.
// 2) Cache GET-kall under /orgs/* (nettverk først, cache som fallback) --
//    slik at data for en allerede åpnet side (f.eks. et scorekort) fortsatt
//    er LESBAR offline. Bevisst IKKE stale-while-revalidate: scorekortet
//    leses på nytt rett etter hver innsending, og må da alltid prøve ekte
//    fersk data først -- en umiddelbart utdatert cache ville vist feil
//    matchstatus/hull-tall rett etter en vellykket innsending.
//
// Selve SKRIVINGEN (hole-scores/hole-results) fanges ALDRI her -- det
// håndteres i lib/offline-queue.ts, med en egen IndexedDB-kø i klientkoden,
// hvor UI-et kan gi umiddelbar, presis tilbakemelding ("lagret lokalt,
// venter på synk"). /auth/* og /public/* caches bevisst ikke -- caching er
// begrenset til akkurat det scoreregistrerings-flyten trenger.
//
// Kjent, akseptert begrensning: Cache Storage er nøklet på URL, ikke på
// innlogget bruker/sesjon -- deler flere kontoer samme enhet/nettleser,
// kan en offline-fallback vise data cachet av en TIDLIGERE innlogget
// bruker på samme enhet. Ikke løst i v1 (samme tillitsnivå som resten av
// appen, se team_authz.py sin trusselmodell-begrunnelse), ingen
// cache-tømming ved utlogging bygget ennå.

// v2 (2026-08-02): "nettverk først" var i praksis "nettleser-cache først" --
// et rått fetch(req) her respekterer fortsatt HTTP Cache-Control på selve
// requesten, så en side lastet før en ny utrulling kunne forbli synlig
// lenge etter deploy uten at brukeren merket noe (ingen feilmelding, bare
// stille utdatert innhold). explicit cache:"reload" tvinger et ekte
// nettverksoppslag hver gang, samme prinsipp begge steder under.
const RUNTIME_CACHE = "teecup-runtime-v2"
const OFFLINE_URL = "/offline.html"

self.addEventListener("install", (event) => {
  event.waitUntil(
    caches
      .open(RUNTIME_CACHE)
      .then((cache) => cache.add(OFFLINE_URL))
      .then(() => self.skipWaiting()),
  )
})

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

self.addEventListener("fetch", (event) => {
  const req = event.request
  if (req.method !== "GET") return // skriving går aldri via SW-en

  if (req.mode === "navigate") {
    event.respondWith(
      fetch(req, { cache: "reload" })
        .then((res) => {
          const copy = res.clone()
          caches.open(RUNTIME_CACHE).then((cache) => cache.put(req, copy))
          return res
        })
        .catch(async () => (await caches.match(req)) || (await caches.match(OFFLINE_URL))),
    )
    return
  }

  const url = new URL(req.url)
  if (url.origin === self.location.origin && url.pathname.startsWith("/orgs/")) {
    event.respondWith(
      fetch(req, { cache: "reload" })
        .then((res) => {
          if (res.ok) caches.open(RUNTIME_CACHE).then((cache) => cache.put(req, res.clone()))
          return res
        })
        .catch(() => caches.match(req)),
    )
  }
})

// Push-varsler til telefonens OS (Web Push/VAPID, 2026-07-28). Payloaden er
// alltid JSON {title, body, link_path} (se app/push.py) -- viser en native
// systemvarsling selv når ingen fane er åpen. notificationclick fokuserer en
// allerede åpen fane på samme origin hvis én finnes, ellers åpner en ny.
self.addEventListener("push", (event) => {
  let data = { title: "TeeCup", body: "Du har et nytt varsel.", link_path: "/my-notifications" }
  try {
    if (event.data) data = { ...data, ...event.data.json() }
  } catch {
    // Behold standardteksten hvis payloaden mot formodning ikke er JSON.
  }
  event.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: "/icons/icon-192.png",
      badge: "/icons/icon-192.png",
      data: { link_path: data.link_path },
    }),
  )
})

self.addEventListener("notificationclick", (event) => {
  event.notification.close()
  const linkPath = event.notification.data?.link_path || "/my-notifications"
  event.waitUntil(
    self.clients.matchAll({ type: "window", includeUncontrolled: true }).then((clients) => {
      for (const client of clients) {
        if (client.url.includes(self.location.origin) && "focus" in client) {
          client.navigate(linkPath)
          return client.focus()
        }
      }
      return self.clients.openWindow(linkPath)
    }),
  )
})
