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

// Run BEFORE React mounts so any tracker that looks for `window.__cookiesDisabled`
// (see index.html GTM bootstrap) sees the flag, and any cookies already set
// on the root domain get wiped from this subdomain's view.
initCookieGate();

// Force-reset client storage for all returning visitors when this version bumps.
// Increment RESET_VERSION whenever you need to push a global cache/cookie wipe.
const RESET_VERSION = "2026-05-01-3";
const RESET_KEY = "tt_reset_version";
const performGlobalReset = async () => {
  try {
    if (localStorage.getItem(RESET_KEY) === RESET_VERSION) return;

    // Preserve auth + refund-builder recovery state so users aren't logged
    // out or stripped of their in-progress claim while caches are reset.
    const preserved: Record<string, string> = {};
    for (let i = 0; i < localStorage.length; i++) {
      const key = localStorage.key(i);
      if (
        key &&
        (key.startsWith("sb-") ||
          key.includes("supabase.auth") ||
          key.startsWith("tt_builder_") ||
          key.startsWith("tt_builder_chat:"))
      ) {
        const v = localStorage.getItem(key);
        if (v !== null) preserved[key] = v;
      }
    }

    localStorage.clear();
    sessionStorage.clear();

    // Restore auth
    for (const [k, v] of Object.entries(preserved)) localStorage.setItem(k, v);
    localStorage.setItem(RESET_KEY, RESET_VERSION);

    // Clear non-auth cookies on current domain
    const host = window.location.hostname;
    const domains = [host, `.${host}`, host.split(".").slice(-2).join(".")];
    document.cookie.split(";").forEach((c) => {
      const name = c.split("=")[0]?.trim();
      if (!name) return;
      if (name.startsWith("sb-") || name.includes("supabase")) return;
      domains.forEach((d) => {
        document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${d}`;
      });
      document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
    });

    // Nuke all Cache Storage entries
    if ("caches" in window) {
      const keys = await caches.keys();
      await Promise.all(keys.map((k) => caches.delete(k)));
    }
  } catch {
    // Reset failed — non-critical
  }
};
void performGlobalReset();

// Recover from stale dynamic-import chunks. After a deploy the previously
// cached entry bundle can reference chunk URLs that no longer exist, which
// surfaces as "Failed to fetch dynamically imported module" (Chrome) or
// "Module name, '...' does not resolve to a valid URL" (Safari). When that
// happens we hard-reload once to pull the new asset graph. A sessionStorage
// guard prevents reload loops if the failure is genuinely something else.
const CHUNK_RELOAD_KEY = "tt_chunk_reload_at";
const isChunkLoadError = (msg: unknown): boolean => {
  const m = String(msg || "").toLowerCase();
  return (
    m.includes("failed to fetch dynamically imported module") ||
    m.includes("does not resolve to a valid url") ||
    m.includes("error loading dynamically imported module") ||
    m.includes("importing a module script failed") ||
    (m.includes("module") && m.includes("not resolve"))
  );
};
const tryRecoverFromStaleChunk = (msg: unknown) => {
  if (!isChunkLoadError(msg)) return;
  try {
    const last = Number(sessionStorage.getItem(CHUNK_RELOAD_KEY) || 0);
    if (Date.now() - last < 30_000) return; // already tried recently
    sessionStorage.setItem(CHUNK_RELOAD_KEY, String(Date.now()));
  } catch {
    // ignore — still attempt reload below
  }
  // Best-effort cache nuke before reload so the new shell can load cleanly.
  void (async () => {
    try {
      if ("caches" in window) {
        const keys = await caches.keys();
        await Promise.all(keys.map((k) => caches.delete(k)));
      }
      if ("serviceWorker" in navigator) {
        const regs = await navigator.serviceWorker.getRegistrations();
        await Promise.all(regs.map((r) => r.unregister()));
      }
    } catch {
      // ignore
    } finally {
      window.location.reload();
    }
  })();
};
window.addEventListener("error", (e) => tryRecoverFromStaleChunk(e?.message));
window.addEventListener("unhandledrejection", (e) =>
  tryRecoverFromStaleChunk((e?.reason && (e.reason.message || String(e.reason))) || ""),
);

createRoot(document.getElementById("root")!).render(<App />);

const TT_CACHE_PREFIX = "tt-cache-";

const setupServiceWorker = async () => {
  if (!("serviceWorker" in navigator)) return;

  if (import.meta.env.DEV) {
    try {
      const registrations = await navigator.serviceWorker.getRegistrations();
      await Promise.all(registrations.map((registration) => registration.unregister()));

      if ("caches" in window) {
        const cacheKeys = await caches.keys();
        await Promise.all(
          cacheKeys
            .filter((key) => key.startsWith(TT_CACHE_PREFIX))
            .map((key) => caches.delete(key)),
        );
      }
    } catch {
      // Cleanup failed — non-critical in development
    }

    return;
  }

  window.addEventListener("load", () => {
    navigator.serviceWorker.register("/sw.js").catch(() => {
      // SW registration failed — non-critical
    });
  });
};

void setupServiceWorker();
