/// <reference lib="webworker" />
// Music PWA service worker（injectManifest 模式）。
// 只 precache app shell（HTML/JS/CSS/icon），媒体（audio + chord PNG）走前端 IDB
// 显式缓存（lib/cache.js），不让 SW 自动 cache 大文件避免 quota 失控。

const MANIFEST = self.__WB_MANIFEST || []

function hashStr(s) {
  let h = 5381
  for (let i = 0; i < s.length; i++) h = ((h << 5) + h + s.charCodeAt(i)) >>> 0
  return h.toString(36)
}
const VERSION = hashStr(MANIFEST.map((e) => `${e.url}@${e.revision || ''}`).join('|'))
const CACHE = `music-shell-${VERSION}`

const INDEX = new URL('index.html', self.location.href).href
const URLS = Array.from(new Set([INDEX, ...MANIFEST.map((e) => new URL(e.url, self.location.href).href)]))

self.addEventListener('install', (event) => {
  event.waitUntil(
    (async () => {
      const cache = await caches.open(CACHE)
      // 并发 addAll，HTTP/2 多路复用，一次过；失败回退串行
      try {
        await cache.addAll(URLS)
      } catch {
        for (const u of URLS) {
          try {
            const r = await fetch(u, { cache: 'reload' })
            if (r.ok) await cache.put(u, r)
          } catch {}
        }
      }
      await self.skipWaiting()
    })(),
  )
})

self.addEventListener('activate', (event) => {
  event.waitUntil(
    (async () => {
      const keys = await caches.keys()
      await Promise.all(
        keys.filter((k) => k.startsWith('music-shell-') && k !== CACHE).map((k) => caches.delete(k)),
      )
      await self.clients.claim()
    })(),
  )
})

self.addEventListener('fetch', (event) => {
  const req = event.request
  if (req.method !== 'GET') return
  const url = new URL(req.url)
  // 只接管同源 GET，跳过 /api/*（前端 cache.js 自己管）
  if (url.origin !== self.location.origin) return
  if (url.pathname.startsWith('/api/')) return

  event.respondWith(
    (async () => {
      const cache = await caches.open(CACHE)
      // 导航请求总是回 index.html，让 SPA 路由跑（离线也能进任何 route）
      if (req.mode === 'navigate') {
        const cached = await cache.match(INDEX)
        if (cached) return cached
      }
      const cached = await cache.match(req)
      if (cached) return cached
      try {
        const fresh = await fetch(req)
        if (fresh.ok) cache.put(req, fresh.clone()).catch(() => {})
        return fresh
      } catch (e) {
        // 离线 + 没缓存
        return new Response('offline', { status: 503 })
      }
    })(),
  )
})
