/**
 * GoldAutoTrade Service Worker — offline caching for PWA.
 *
 * Strategy:
 *   - Cache-first for versioned static assets (JS/CSS/icons — URL has hash)
 *   - Network-first for / (HTML entry point) and API
 *   - Enables the app to load offline and show cached data when backend unreachable.
 *
 * RELEASE NOTE: bump BUILD_VERSION when fetch policy changes materially.
 */
const BUILD_VERSION = "v3";
const CACHE_STATIC = `gat-static-${BUILD_VERSION}`;
const CACHE_API = `gat-api-${BUILD_VERSION}`;
self.addEventListener("install", () => {
  self.skipWaiting();
});

// ── Activate: clean all caches from older versions ───────────────
self.addEventListener("activate", (event) => {
  event.waitUntil(
    caches.keys().then((keys) => {
      return Promise.all(
        keys
          .filter((k) => k !== CACHE_STATIC && k !== CACHE_API)
          .map((k) => caches.delete(k))
      );
    })
  );
  self.clients.claim();
});

// ── Fetch: network-first for / and API, cache-first for hashed assets ─
self.addEventListener("fetch", (event) => {
  const url = new URL(event.request.url);

  // Skip non-GET requests
  if (event.request.method !== "GET") return;

  // API requests: network-first, fallback to cache
  if (url.pathname.startsWith("/api/")) {
    event.respondWith(networkFirst(event.request, CACHE_API));
    return;
  }

  // HTML entry point: network-only.
  // Never cache index.html here, otherwise an old shell may keep pointing
  // to removed asset hashes after a new release.
  if (url.pathname === "/" || url.pathname.endsWith(".html")) {
    event.respondWith(networkOnly(event.request));
    return;
  }

  // Vite dev resources should never be cached by SW.
  if (url.pathname.startsWith("/@vite/") || url.pathname.startsWith("/src/")) {
    return;
  }

  // Versioned static assets (hashed filenames): cache-first
  if (
    url.pathname.startsWith("/assets/") ||
    url.pathname.startsWith("/icons/") ||
    url.pathname.endsWith(".js") ||
    url.pathname.endsWith(".css") ||
    url.pathname.endsWith(".svg") ||
    url.pathname.endsWith(".png")
  ) {
    event.respondWith(cacheFirst(event.request, CACHE_STATIC));
    return;
  }

  // Everything else: network-first
  event.respondWith(networkFirst(event.request, CACHE_STATIC));
});

// ── Strategies ────────────────────────────────────────────────────
async function cacheFirst(request, cacheName) {
  const cached = await caches.match(request);
  if (cached) return cached;
  try {
    const response = await fetch(request);
    if (shouldCacheStatic(request, response)) {
      const cache = await caches.open(cacheName);
      cache.put(request, response.clone());
    }
    return response;
  } catch (e) {
    return new Response("Offline", { status: 503 });
  }
}

async function networkFirst(request, cacheName) {
  try {
    const response = await fetch(request);
    if (shouldCacheResponse(request, response)) {
      const cache = await caches.open(cacheName);
      cache.put(request, response.clone());
    }
    return response;
  } catch (e) {
    const cached = await caches.match(request);
    return cached || new Response('{"error":"offline"}', {
      status: 503,
      headers: { "Content-Type": "application/json" },
    });
  }
}

async function networkOnly(request) {
  return fetch(request);
}

function shouldCacheResponse(request, response) {
  return Boolean(response && response.ok && request.method === "GET");
}

function shouldCacheStatic(request, response) {
  if (!shouldCacheResponse(request, response)) return false;
  const url = new URL(request.url);
  if (url.origin !== self.location.origin) return false;
  if (url.pathname === "/" || url.pathname.endsWith(".html")) return false;
  return true;
}

// ── Push notifications ────────────────────────────────────────────
self.addEventListener("push", (event) => {
  if (!event.data) return;
  const data = event.data.json();
  const options = {
    body: data.message || "",
    icon: "/icons/icon-192.png",
    badge: "/icons/icon-192.png",
    vibrate: [200, 100, 200],
    data: { url: data.url || "/" },
    tag: data.tag || "gat-notification",
  };
  event.waitUntil(
    self.registration.showNotification(
      data.title || "GoldAutoTrade Alert",
      options
    )
  );
});

self.addEventListener("notificationclick", (event) => {
  event.notification.close();
  const url = event.notification.data?.url || "/";
  event.waitUntil(
    self.clients.matchAll({ type: "window" }).then((clients) => {
      for (const client of clients) {
        if (client.url.includes(url) && "focus" in client) {
          return client.focus();
        }
      }
      if (self.clients.openWindow) {
        return self.clients.openWindow(url);
      }
    })
  );
});
