/* global self, caches, URL, Response */

const CACHE_NAME = 'flynn-webchat-v5';
const token = new URL(self.location.href).searchParams.get('token');
const withToken = (path) => {
  if (!token) {
    return path;
  }
  const sep = path.includes('?') ? '&' : '?';
  return `${path}${sep}token=${encodeURIComponent(token)}`;
};
const OFFLINE_ASSETS = ['/', '/index.html', '/style.css', '/app.js', '/manifest.webmanifest'].map(withToken);

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then((cache) => cache.addAll(OFFLINE_ASSETS))
      .catch(() => undefined),
  );
  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) => {
  if (event.request.method !== 'GET') {
    return;
  }

  const requestUrl = new URL(event.request.url);
  const isNavigation = event.request.mode === 'navigate';
  const isStaticAsset = requestUrl.origin === self.location.origin
    && (requestUrl.pathname.startsWith('/lib/')
      || requestUrl.pathname.startsWith('/pages/')
      || requestUrl.pathname === '/app.js'
      || requestUrl.pathname === '/style.css'
      || requestUrl.pathname === '/index.html'
      || requestUrl.pathname === '/manifest.webmanifest');

  event.respondWith((async () => {
    try {
      const networkResponse = await fetch(event.request);
      if (isNavigation || isStaticAsset) {
        const cache = await caches.open(CACHE_NAME);
        await cache.put(event.request, networkResponse.clone());
      }
      return networkResponse;
    } catch {
      const cached = await caches.match(event.request, { ignoreSearch: true });
      if (cached) {
        return cached;
      }

      if (isNavigation) {
        const fallback = await caches.match('/index.html', { ignoreSearch: true });
        if (fallback) {
          return fallback;
        }
      }

      return new Response('Offline', { status: 503 });
    }
  })());
});

self.addEventListener('push', (event) => {
  let payload = {
    title: 'Flynn',
    body: 'You have a new update.',
  };

  try {
    const parsed = event.data?.json();
    if (parsed && typeof parsed === 'object') {
      payload = {
        ...payload,
        ...parsed,
      };
    }
  } catch {
    const text = event.data?.text();
    if (text) {
      payload.body = text;
    }
  }

  event.waitUntil(self.registration.showNotification(payload.title, {
    body: payload.body,
    tag: payload.tag || 'flynn-webchat',
    renotify: false,
    data: payload.data || {},
  }));
});

self.addEventListener('notificationclick', (event) => {
  event.notification.close();

  event.waitUntil((async () => {
    const clients = await self.clients.matchAll({ type: 'window', includeUncontrolled: true });
    if (clients.length > 0) {
      await clients[0].focus();
      return;
    }
    await self.clients.openWindow('/#/chat');
  })());
});
