import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

/**
 * Stale-build eviction.
 *
 * Some returning visitors still have an old service worker or HTTP cache from
 * earlier deploys, which serves them a stale `index.html` and stale JS chunks.
 * We aggressively unregister all SWs and clear all Cache Storage on every load.
 * If we actually FOUND something to evict, we force a one-time hard reload so
 * the next paint is guaranteed fresh. The `aj_evicted` flag prevents loops.
 */
async function evictStaleBuild() {
  let foundStale = false;

  if ("serviceWorker" in navigator) {
    try {
      const regs = await navigator.serviceWorker.getRegistrations();
      // Whitelist the article-meta SW (route-aware citation_* injection).
      const stale = regs.filter((r) => {
        const url = r.active?.scriptURL || r.waiting?.scriptURL || r.installing?.scriptURL || "";
        return !/sw-article-meta\.js(\?|$)/i.test(url);
      });
      if (stale.length > 0) foundStale = true;
      await Promise.all(stale.map((r) => r.unregister()));
    } catch {}
  }

  if ("caches" in window) {
    try {
      const keys = await caches.keys();
      // Preserve the article-meta SW shell cache.
      const stale = keys.filter((k) => !k.startsWith("air-article-shell-"));
      if (stale.length > 0) foundStale = true;
      await Promise.all(stale.map((k) => caches.delete(k)));
    } catch {}
  }

  if (foundStale && !sessionStorage.getItem("aj_evicted")) {
    sessionStorage.setItem("aj_evicted", "1");
    window.location.reload();
    return true;
  }
  return false;
}

// Timeout: if evictStaleBuild() hangs (e.g. stuck service worker or cache API),
// render the app anyway after 3s so the user doesn't see a blank screen.
Promise.race([
  evictStaleBuild(),
  new Promise<false>((resolve) => setTimeout(() => resolve(false), 3000)),
]).then((reloading) => {
  if (reloading) return;

  const isChunkErr = (msg: string) => {
    const m = msg.toLowerCase();
    return (
      m.includes("dynamically imported module") ||
      m.includes("failed to fetch dynamically imported") ||
      m.includes("importing a module script failed") ||
      m.includes("chunkloaderror") ||
      m.includes("loading chunk") ||
      m.includes("loading css chunk")
    );
  };
  const handleChunkErr = (msg: string) => {
    if (!isChunkErr(msg)) return;
    if (sessionStorage.getItem("aj_chunk_reload")) return;
    sessionStorage.setItem("aj_chunk_reload", "1");
    window.location.reload();
  };
  window.addEventListener("error", (e) => handleChunkErr(`${e.message || ""} ${(e.error && e.error.message) || ""}`));
  window.addEventListener("unhandledrejection", (e) => {
    const r: any = e.reason;
    handleChunkErr(`${(r && (r.message || r.toString())) || ""}`);
  });
  window.addEventListener("load", () => {
    setTimeout(() => sessionStorage.removeItem("aj_chunk_reload"), 5000);
  });

  createRoot(document.getElementById("root")!).render(<App />);
}).catch(() => {
  createRoot(document.getElementById("root")!).render(<App />);
});
