/* eslint-disable no-var */
import { build, files, version } from '$service-worker';

const worker = (self as unknown) as ServiceWorkerGlobalScope;

const FILES = `cache${version}`;

// build is an array of all files generated by the bundler
// files is an array of all files in the static dir
const to_cache = build.concat(files);
const staticAssets = new Set(to_cache);

worker.addEventListener("install", (event) => {
  event.waitUntil(
    caches
      .open(FILES)
      .then((cache) => cache.addAll(to_cache))
      .then(() => {
        worker.skipWaiting();
      })
  );
});

worker.addEventListener("activate", (event) => {
  event.waitUntil(
    caches.keys()
      .then(async (keys) => {
        // Delete old caches
        for (const key of keys) {
          if (key !== FILES) await caches.delete(key);
        }
        console.log("old caches deleted")
        worker.clients.claim();
      })
      .then(() => console.log("Activated"))
  )
})

// Fetch the asset from the network and store it in the cache
// Falls back to the cache if the user is offline
async function fetchAndCache(request: Request) {
  const cache = await caches.open(`offline${version}`);

  try {
    const response = await fetch(request);
    cache.put(request, response.clone());
    return response;
  } catch (err) { // if the user is offline, the request will fail
    const response = await cache.match(request);
    if (response) return response;

    // if not in cache, throw error anyway
    throw err;
  }
}

worker.addEventListener("fetch", (event) => {
  if (event.request.method !== "GET") return;
  
  console.log("fetch event intercepted")

  // Firefox has not yet fixed this, so it needs to be excluded from this caching behavior
  // https://web.dev/sw-range-requests/
  // https://wpt.fyi/results/fetch/range/sw.https.window.html?label=master&label=experimental&aligned
  if (navigator.userAgent.includes("Firefox/") && event.request.headers.has("range")) return;

  const url = new URL(event.request.url);

  // Don't try to cache protocols other than http/https
  const isHttp = url.protocol.startsWith("http");
  const isStaticAsset = url.host === self.location.host && staticAssets.has(url.pathname);
  const skipBecauseUncached = event.request.cache === 'only-if-cached' && !isStaticAsset;

  if (isHttp && !skipBecauseUncached) {
    event.respondWith(
      (async () => {
        const cachedAsset = isStaticAsset && (await caches.match(event.request));

        return cachedAsset || fetchAndCache(event.request);
      })()
    )
  }
})