/// <reference lib="webworker" />

const CACHE_NAME = 'soulsync-shell-v1'
const DB_NAME = 'soulsync-offline'
const AUDIO_STORE = 'audio-blobs'

// App shell files to cache for offline UI access
const SHELL_FILES = [
  '/',
  '/music',
  '/offline',
]

// Install: pre-cache app shell
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) =>
      cache.addAll(SHELL_FILES).catch(() => {
        // Non-critical if some pages fail to cache
      })
    )
  )
  self.skipWaiting()
})

// Activate: clean old caches
self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then((keys) =>
      Promise.all(keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k)))
    )
  )
  self.clients.claim()
})

/**
 * Open IndexedDB from the service worker to serve cached audio
 */
function openDB() {
  return new Promise((resolve, reject) => {
    const req = indexedDB.open(DB_NAME, 1)
    req.onupgradeneeded = () => {
      const db = req.result
      if (!db.objectStoreNames.contains(AUDIO_STORE)) {
        db.createObjectStore(AUDIO_STORE)
      }
      if (!db.objectStoreNames.contains('track-meta')) {
        db.createObjectStore('track-meta')
      }
    }
    req.onsuccess = () => resolve(req.result)
    req.onerror = () => reject(req.error)
  })
}

function getFromDB(trackId) {
  return openDB().then(
    (db) =>
      new Promise((resolve, reject) => {
        const tx = db.transaction(AUDIO_STORE, 'readonly')
        const req = tx.objectStore(AUDIO_STORE).get(trackId)
        req.onsuccess = () => {
          db.close()
          resolve(req.result)
        }
        req.onerror = () => {
          db.close()
          reject(req.error)
        }
      })
  )
}

// Fetch: intercept /api/music/stream/ requests to serve from IndexedDB
self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url)

  // Intercept stream requests
  const streamMatch = url.pathname.match(/^\/api\/music\/stream\/(.+)$/)
  if (streamMatch) {
    const trackId = streamMatch[1]
    event.respondWith(
      getFromDB(trackId).then((blob) => {
        if (blob) {
          return new Response(blob, {
            headers: {
              'Content-Type': blob.type || 'audio/mpeg',
              'Content-Length': String(blob.size),
            },
          })
        }
        // Not cached, fetch from network
        return fetch(event.request)
      }).catch(() => fetch(event.request))
    )
    return
  }

  // For navigation requests: try network first, fall back to cache
  if (event.request.mode === 'navigate') {
    event.respondWith(
      fetch(event.request).catch(() =>
        caches.match(event.request).then((cached) => cached || caches.match('/'))
      )
    )
    return
  }
})
