import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { installRealtimeAuditWrapper } from "./lib/supabaseChannelWrapper";
import { injectPreloadChain } from "./lib/preloadChain";
import { buildLogoPreloadChain } from "./lib/preloadLogoChain";
import { preloadHero, isHomePath } from "./lib/preloadHero";
import { isBaselineMode } from "./lib/baselineMode";
// Vite-resolved hashed URLs for the logo assets. We inject `<link rel=preload>`
// chains (AVIF → WebP → PNG) before React mounts so the browser starts the
// requests in parallel with JS bundle parsing — on slow 3G/4G this shaves
// ~150-300ms off first paint of the brand mark without disturbing the
// anti-FOUC inline scripts in index.html.
//
// We preload BOTH the visible asset for the current viewport AND the matching
// theme variant (light/dark). Doing it here (post anti-FOUC) means the
// `<html class="dark">` flag is already applied, so we can request only the
// one banner the user will actually see — no wasted bytes.
import elyrixIconPng from "@/assets/elyrix-icon-mobile.png";
const elyrixIconAvif = elyrixIconPng;
const elyrixIconWebp = elyrixIconPng;
const elyrixIconAvifSm = elyrixIconPng;
const elyrixIconWebpSm = elyrixIconPng;
import elyrixLogoLightAvifSm from "@/assets/elyrix-logo-sm.avif";
import elyrixLogoLightAvif from "@/assets/elyrix-logo.avif";
import elyrixLogoLightWebpSm from "@/assets/elyrix-logo-sm.webp";
import elyrixLogoLightWebp from "@/assets/elyrix-logo.webp";
import elyrixLogoLightPng from "@/assets/elyrix-logo.png";
import elyrixLogoDarkAvifSm from "@/assets/elyrix-logo-dark-sm.avif";
import elyrixLogoDarkAvif from "@/assets/elyrix-logo-dark.avif";
import elyrixLogoDarkWebpSm from "@/assets/elyrix-logo-dark-sm.webp";
import elyrixLogoDarkWebp from "@/assets/elyrix-logo-dark.webp";
import elyrixLogoDarkPng from "@/assets/elyrix-logo-dark.png";

// Cascading preload logic lives in `./lib/preloadChain` so it can be
// driven by jsdom unit tests (browsers fire the `error` event on failed
// preloads, which the cascade uses to advance to the next candidate).

(() => {
  if (typeof window === "undefined") return;
  // Baseline mode (URL `?baseline=1` / `?nopreload=1`, localStorage flag, or
  // VITE_PERF_BASELINE build flag) skips the preload chain entirely so the
  // LCP harness can compare against an un-optimised baseline. See
  // `src/lib/baselineMode.ts` for the full activation surface — keeping the
  // decision in one module ensures the preload, decoding hint and
  // fetchPriority are all toggled together (partial rollbacks would skew the
  // measurement).
  if (isBaselineMode()) return;
  const chain = buildLogoPreloadChain(
    {
      viewportWidth: window.innerWidth,
      isDark: document.documentElement.classList.contains("dark"),
    },
    {
      iconAvif: elyrixIconAvif,
      iconWebp: elyrixIconWebp,
      iconPng: elyrixIconPng,
      iconAvifSm: elyrixIconAvifSm,
      iconWebpSm: elyrixIconWebpSm,
      lightBannerAvifSm: elyrixLogoLightAvifSm,
      lightBannerAvif: elyrixLogoLightAvif,
      lightBannerWebpSm: elyrixLogoLightWebpSm,
      lightBannerWebp: elyrixLogoLightWebp,
      lightBannerPng: elyrixLogoLightPng,
      darkBannerAvifSm: elyrixLogoDarkAvifSm,
      darkBannerAvif: elyrixLogoDarkAvif,
      darkBannerWebpSm: elyrixLogoDarkWebpSm,
      darkBannerWebp: elyrixLogoDarkWebp,
      darkBannerPng: elyrixLogoDarkPng,
    },
  );
  injectPreloadChain(chain);

  // Hero background — only on the home route (the only one that renders it).
  // Idempotent: SPA navigations into `/` later will trigger `preloadHero()`
  // again from `Index.tsx`, but the module-level guard prevents a duplicate
  // `<link>` injection. On non-home initial loads we skip entirely so other
  // pages don't pay for bytes they won't render.
  if (isHomePath(window.location.pathname)) {
    preloadHero();
  }
})();

installRealtimeAuditWrapper();

// Web Vitals telemetry — captures LCP/CLS/INP/FCP/TTFB and tags each LCP
// candidate with the element kind (logo-navbar-icon, hero-background, …)
// so we can see whether the preload chain successfully made the brand mark
// the LCP element, or whether the hero background still wins.
// The sink only fires when the user has accepted analytics cookies; the
// in-memory buffer (`window.__webVitals`) populates regardless for devtools.
import("./lib/webVitals").then(({ initWebVitals }) => {
  // Build the ingest URL once at boot — Vite inlines the env vars so this is
  // a constant string at runtime (no per-sample work). We point at the
  // public edge function `ingest-web-vitals` which validates, derives
  // device/theme/connection from headers, and inserts via service role
  // (RLS keeps the table read-restricted to admins).
  const ingestUrl = `${import.meta.env.VITE_SUPABASE_URL}/functions/v1/ingest-web-vitals`;
  initWebVitals({
    sink: (sample) => {
      try {
        // sendBeacon is fire-and-forget and survives page-hide without
        // delaying navigation — perfect for telemetry. Failures stay
        // silent: telemetry must never break UX. If sendBeacon is
        // unavailable (very old browser), fall back to a keepalive fetch
        // so we still get the sample on modern devices that disable Beacon
        // for tracking-prevention reasons.
        const body = JSON.stringify(sample);
        const blob = new Blob([body], { type: "application/json" });
        const sent = navigator.sendBeacon?.(ingestUrl, blob);
        if (!sent) {
          void fetch(ingestUrl, {
            method: "POST",
            body,
            headers: { "Content-Type": "application/json" },
            keepalive: true,
          }).catch(() => {});
        }
      } catch {
        /* noop */
      }
    },
  });
});

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

// --- Service Worker guard: only register in production, outside iframes/preview ---
const isInIframe = (() => {
  try { return window.self !== window.top; } catch { return true; }
})();
const isPreviewHost =
  window.location.hostname.includes("id-preview--") ||
  window.location.hostname.includes("lovableproject.com");

if (!isInIframe && !isPreviewHost && "serviceWorker" in navigator) {
  // Defer SW registration well past FCP/LCP. We wait for `load`, then for an
  // idle window (or a 3s timeout fallback) so the registration request never
  // competes with critical-path resources on slow mobile.
  const register = () => {
    navigator.serviceWorker.register("/sw.js").catch(() => {});
  };
  const schedule = () => {
    const w = window as unknown as {
      requestIdleCallback?: (cb: () => void, opts?: { timeout: number }) => void;
    };
    if (typeof w.requestIdleCallback === "function") {
      w.requestIdleCallback(register, { timeout: 3000 });
    } else {
      setTimeout(register, 2000);
    }
  };
  if (document.readyState === "complete") schedule();
  else window.addEventListener("load", schedule, { once: true });
} else {
  // Unregister any stale SW in preview/iframe
  navigator.serviceWorker?.getRegistrations().then((regs) =>
    regs.forEach((r) => r.unregister())
  );
}
