const CACHE_NAME = 'l484-pwa-v12'
const APP_SHELL = [
  '/',
  '/manifest.webmanifest',
]

self.addEventListener('install', (event) => {
  event.waitUntil(caches.open(CACHE_NAME).then((cache) => cache.addAll(APP_SHELL)))
  self.skipWaiting()
})

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

self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url)
  if (!['http:', 'https:'].includes(url.protocol)) return
  if (url.pathname.startsWith('/api/')) return

  if (event.request.mode === 'navigate') {
    event.respondWith(
      fetch(event.request)
        .then((response) => {
          const clone = response.clone()
          caches.open(CACHE_NAME).then((cache) => cache.put('/', clone))
          return response
        })
        .catch(() => caches.match('/') || caches.match(event.request)),
    )
    return
  }

  event.respondWith(
    caches.match(event.request).then((cached) =>
      cached || fetch(event.request).then((response) => {
        if (event.request.method === 'GET' && response.ok && response.type === 'basic') {
          const clone = response.clone()
          caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone))
        }
        return response
      }),
    ),
  )
})

self.addEventListener('pushsubscriptionchange', (event) => {
  event.waitUntil((async () => {
    const response = await fetch('/api/notifications/vapid-public-key', { cache: 'no-store' })
    const { publicKey } = response.ok ? await response.json() : {}
    if (!publicKey) return
    const padding = '='.repeat((4 - publicKey.length % 4) % 4)
    const base64 = (publicKey + padding).replace(/-/g, '+').replace(/_/g, '/')
    const rawData = atob(base64)
    const applicationServerKey = new Uint8Array([...rawData].map((char) => char.charCodeAt(0)))
    const subscription = await self.registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey })
    await fetch('/api/notifications/subscribe', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ subscription }),
    })
  })())
})

self.addEventListener('push', (event) => {
  let data = {}
  try {
    data = event.data ? event.data.json() : {}
  } catch {
    data = { title: 'L484', message: event.data?.text() || 'New L484 update.' }
  }
  const title = data.title || 'L484'
  const options = {
    body: data.message || data.body || 'New L484 update.',
    icon: data.icon || '/images/small-logo.svg',
    badge: '/images/small-logo.svg',
    tag: data.tag || 'l484-update',
    data: { url: data.data?.url || '/' },
  }
  event.waitUntil(self.registration.showNotification(title, options))
})

self.addEventListener('notificationclick', (event) => {
  event.notification.close()
  const urlToOpen = event.notification.data?.url || '/'
  event.waitUntil(
    clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
      const existing = clientList.find((client) => new URL(client.url).pathname === urlToOpen && 'focus' in client)
      if (existing) return existing.focus()
      if (clients.openWindow) return clients.openWindow(urlToOpen)
      return null
    }),
  )
})
