import { readdirSync, writeFileSync } from 'node:fs'
import { relative, resolve } from 'node:path'

const distDirectory = resolve('dist')

function listFiles(directory) {
  return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
    const path = resolve(directory, entry.name)
    return entry.isDirectory() ? listFiles(path) : [path]
  })
}

const assets = listFiles(distDirectory)
  .map((path) => `/${relative(distDirectory, path).replaceAll('\\', '/')}`)
  .filter((path) => path !== '/service-worker.js')
  .sort()
const cacheName = `chronicle-${Date.now()}`
const source = `const CACHE_NAME = ${JSON.stringify(cacheName)}
const APP_ASSETS = ${JSON.stringify(assets, null, 2)}

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then((cache) => cache.addAll(APP_ASSETS))
      .then(() => 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)),
      ))
      .then(() => self.clients.claim()),
  )
})

self.addEventListener('fetch', (event) => {
  const requestUrl = new URL(event.request.url)
  if (
    event.request.method !== 'GET'
    || requestUrl.origin !== self.location.origin
    || requestUrl.pathname.startsWith('/api/')
  ) {
    return
  }

  event.respondWith(
    caches.match(event.request).then((cached) => {
      if (cached) return cached
      return fetch(event.request).catch(() => (
        event.request.mode === 'navigate'
          ? caches.match('/index.html')
          : Response.error()
      ))
    }),
  )
})
`

writeFileSync(resolve(distDirectory, 'service-worker.js'), source)
console.log(`Offline app shell generated with ${assets.length} files.`)
