import React from "react";
import { createRoot } from "react-dom/client";
import { HelmetProvider } from "react-helmet-async";
import App from "./App.tsx";
import "./index.css";
import "./styles/auth-pierre.css";

// PWA / Service Worker hygiene
// In Lovable preview/iframe contexts, any registered Service Worker can serve
// stale Vite chunks and break dynamic imports. Always unregister + clear caches
// in those contexts. In production, vite-plugin-pwa handles autoUpdate.
(async () => {
  if (typeof window === "undefined" || !("serviceWorker" in navigator)) return;

  const isInIframe = (() => {
    try {
      return window.self !== window.top;
    } catch {
      return true;
    }
  })();

  const host = window.location.hostname;
  const isPreviewHost =
    host.includes("lovableproject.com") ||
    host.includes("lovable.app") && host.includes("id-preview--") ||
    host.includes("id-preview--");

  if (isInIframe || isPreviewHost) {
    try {
      const regs = await navigator.serviceWorker.getRegistrations();
      const hadRegs = regs.length > 0;
      await Promise.all(regs.map((r) => r.unregister()));
      let clearedCaches = 0;
      if ("caches" in window) {
        const keys = await caches.keys();
        clearedCaches = keys.length;
        await Promise.all(keys.map((k) => caches.delete(k)));
      }
      // Se havia SW ou caches ativos, a página atual provavelmente foi
      // pintada com assets antigos. Recarrega UMA vez por sessão para
      // o preview vir limpo já no primeiro paint.
      if ((hadRegs || clearedCaches > 0) && !sessionStorage.getItem("pwa_preview_cleaned")) {
        sessionStorage.setItem("pwa_preview_cleaned", "1");
        window.location.reload();
        return;
      }
    } catch (e) {
      console.warn("[PWA] Failed to clean SW/caches in preview:", e);
    }
    return;
  }


  // Production one-time cache bust: força usuários presos em versões antigas
  // do SW (design system antigo em cache) a baixar a nova versão.
  // Bump CACHE_BUST_VERSION sempre que precisar invalidar caches globalmente.
  const CACHE_BUST_VERSION = "2026-05-23-pierre-v2";
  try {
    const last = localStorage.getItem("pwa_cache_bust_version");
    if (last !== CACHE_BUST_VERSION) {
      console.info(
        `[PWA] Cache bust: ${last ?? "(none)"} → ${CACHE_BUST_VERSION}. Limpando assets antigos...`
      );

      // 1) Desregistra todos os Service Workers (exceto o de push notifications).
      const regs = await navigator.serviceWorker.getRegistrations();
      await Promise.all(
        regs.map(async (r) => {
          if (r.scope && r.scope.includes("/push/")) return true;
          // Garante que qualquer SW em waiting solte o controle antes de unregister.
          try {
            r.waiting?.postMessage({ type: "SKIP_WAITING" });
          } catch {}
          return r.unregister();
        })
      );

      // 2) Apaga TODOS os Cache Storage (workbox-precache, runtime, etc.).
      if ("caches" in window) {
        const keys = await caches.keys();
        await Promise.all(keys.map((k) => caches.delete(k)));
      }

      // 3) Apaga IndexedDB usados pelo Workbox/PWA (precache manifest, expiration).
      //    Mantém DBs do app (Supabase auth, etc.) — só remove os conhecidos do PWA.
      try {
        const pwaDbPrefixes = [
          "workbox-",
          "workbox-expiration",
          "workbox-precache",
          "workbox-background-sync",
        ];
        const idbAny = indexedDB as unknown as {
          databases?: () => Promise<{ name?: string }[]>;
        };
        if (typeof idbAny.databases === "function") {
          const dbs = await idbAny.databases();
          await Promise.all(
            (dbs || [])
              .map((d) => d?.name)
              .filter((name): name is string =>
                !!name && pwaDbPrefixes.some((p) => name.startsWith(p))
              )
              .map(
                (name) =>
                  new Promise<void>((resolve) => {
                    const req = indexedDB.deleteDatabase(name);
                    req.onsuccess = () => resolve();
                    req.onerror = () => resolve();
                    req.onblocked = () => resolve();
                  })
              )
          );
        }
      } catch (e) {
        console.warn("[PWA] IndexedDB cleanup failed (ok):", e);
      }

      // 4) Remove chaves de versão antigas que possam ter ficado em storage.
      try {
        Object.keys(localStorage)
          .filter(
            (k) =>
              k.startsWith("pwa_") &&
              k !== "pwa_cache_bust_version" &&
              k !== "pwa_cache_bust_reloaded"
          )
          .forEach((k) => localStorage.removeItem(k));
      } catch {}

      // 5) Grava a nova versão e recarrega UMA vez para baixar assets frescos.
      localStorage.setItem("pwa_cache_bust_version", CACHE_BUST_VERSION);
      if (!sessionStorage.getItem("pwa_cache_bust_reloaded")) {
        sessionStorage.setItem("pwa_cache_bust_reloaded", "1");
        window.location.reload();
      }
    } else {
      // Mesma versão: garante que o flag de reload da sessão não trava
      // um reload legítimo numa próxima troca de versão.
      sessionStorage.removeItem("pwa_cache_bust_reloaded");
    }
  } catch (e) {
    console.warn("[PWA] Cache bust failed:", e);
  }
})();

// Stale-chunk recovery: quando o HTML em cache aponta para um bundle JS antigo
// que não existe mais no servidor (após redeploy), o dynamic import falha com
// "Importing a module script failed" / "Failed to fetch dynamically imported module".
// Força UM reload por sessão para baixar o index.html novo (com hashes atuais).
if (typeof window !== "undefined") {
  const isStaleChunkError = (msg: string) =>
    /Importing a module script failed|Failed to fetch dynamically imported module|error loading dynamically imported module/i.test(
      msg
    );

  const recoverOnce = () => {
    if (sessionStorage.getItem("stale_chunk_recovered")) return;
    sessionStorage.setItem("stale_chunk_recovered", "1");
    window.location.reload();
  };

  window.addEventListener("error", (e) => {
    if (e?.message && isStaleChunkError(e.message)) recoverOnce();
  });
  window.addEventListener("unhandledrejection", (e) => {
    const msg = String((e as PromiseRejectionEvent)?.reason?.message ?? (e as PromiseRejectionEvent)?.reason ?? "");
    if (isStaleChunkError(msg)) recoverOnce();
  });
}



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