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

// Code mostly comes from: https://dev.to/100lvlmaster/create-a-pwa-with-sveltekit-svelte-a36
// With some modifications done by someone in the comments

const worker = (self as unknown) as ServiceWorkerGlobalScope;
const STATIC_CACHE_NAME = `cache${version}`
const APP_CACHE_NAME = `offline${version}`;

// Hardcoded bunch of routes to always preemptively cache
const routes = ["/", "/about"];

// Hardcoded list of other assets to always preemptively cache
//const custom_assets = [
//  //"https://fonts.googleapis.com/css2?family=Montserrat:wght@200&family=Roboto+Flex:opsz,wght@8..144,300;8..144,400;8..144,500&family=Roboto+Slab&display=swap"
//  "https://quenten.nl/favicon.png" //Just there as a placeholder
//];

// Adds the domain to the file path, making it a full name
const addDomain = (assets: string[]) =>
  assets.map((f) => self.location.origin + f);

// build is an array of all files generated by the bundler
// files is an array of all files in the static dir
const ourAssets = addDomain([
  ...files,
  ...build,
  ...routes
]);

const to_cache = [
  ...ourAssets,
  //  ...custom_assets
]
const staticAssets = new Set(to_cache);

worker.addEventListener("install", (event) => {
  event.waitUntil(
    caches
      .open(STATIC_CACHE_NAME)
      .then((cache) => {
        to_cache.forEach((item) => {
          return cache.add(item)
        })
        return
      })
      .then(() => {
        worker.skipWaiting();
      })
  );
});

worker.addEventListener("activate", (event) => {
  event.waitUntil(
    caches.keys()
      .then(async (keys) => {
        // Delete old caches
        for (const key of keys) {
          if (key !== STATIC_CACHE_NAME && key !== APP_CACHE_NAME) 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(APP_CACHE_NAME);

  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;
  if (new URL(event.request.url).hostname === "api.quenten.nl") return;

  //console.log("fetch event intercepted")

  // Range requests are unsupported for some reason
  if (event.request.headers.has("range")) {
    // Check if in the cache, and return if it is there, 
    // otherwise let the request go through and start a new request 
    // in the background without the range header
    console.log("Request has a Range header (HTTP 206). Checking if it's in cache")
    event.respondWith(
      (async () => {
        const url = new URL(event.request.url);
        const isStaticAsset = staticAssets.has(url.href);


        const cachedAsset = isStaticAsset && (await caches.match(event.request, {ignoreVary: true}));

        return cachedAsset || (await fetch(event.request,))
      })()
    );

    // Also put the thing in cache for next time!
    const newRequest = new Request(event.request.url)
    fetchAndCache(newRequest);
    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 = staticAssets.has(url.href);
  const isDev = url.host === self.location.host;
  const skipBecauseUncached = event.request.cache === 'only-if-cached' && !isStaticAsset;

  if (isHttp && !skipBecauseUncached) {
    event.respondWith(
      (async () => {
        // always serve static files and bundler-generated assets from cache.
        // if your application has other URLs with data that will never change,
        // set this variable to true for them, and they will only be fetched once.
        const cachedAsset = isStaticAsset && (await caches.match(event.request, {ignoreVary: true}));

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