import React from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter, HashRouter } from "react-router-dom";
import { HelmetProvider } from "react-helmet-async";
import App from "./App.tsx";
import "./index.css";
import { initI18n } from "@/i18n";
import { initSentry } from "./lib/sentry";
import { isIOSNativeApp, isNativeApp } from "./utils/platformUtils";

// Polyfill crypto.randomUUID for older browsers (e.g. HeadlessChrome 91, older WebViews).
// randomUUID is only available on https/secure contexts in modern browsers; fall back to
// a v4 UUID generated from crypto.getRandomValues, or Math.random as a last resort.
(() => {
  try {
    const c: any = (typeof globalThis !== "undefined" ? (globalThis as any).crypto : undefined) ?? {};
    if (typeof c.randomUUID === "function") return;
    const getRandomValues: ((arr: Uint8Array) => Uint8Array) | undefined =
      typeof c.getRandomValues === "function" ? c.getRandomValues.bind(c) : undefined;
    const randomUUID = (): string => {
      const bytes = new Uint8Array(16);
      if (getRandomValues) {
        getRandomValues(bytes);
      } else {
        for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);
      }
      // Per RFC 4122 v4
      bytes[6] = (bytes[6] & 0x0f) | 0x40;
      bytes[8] = (bytes[8] & 0x3f) | 0x80;
      const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
      return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
    };
    if (typeof (globalThis as any).crypto === "undefined") {
      (globalThis as any).crypto = { randomUUID };
    } else {
      try {
        (globalThis as any).crypto.randomUUID = randomUUID;
      } catch {
        Object.defineProperty((globalThis as any).crypto, "randomUUID", { value: randomUUID, configurable: true });
      }
    }
  } catch {
    // ignore
  }
})();

// Initialize Sentry first (before React renders)
initSentry();

const renderApp = () => {
  const useHash = import.meta.env.VITE_USE_HASH_ROUTER === "true";
  const RouterImpl = useHash ? HashRouter : BrowserRouter;

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

/**
 * IMPORTANT:
 * - The web app uses a Service Worker (PWA) for performance/offline.
 * - In a Capacitor native shell, SW caching can cause the app to show an older
 *   version than what is currently deployed on the domain.
 * So: keep SW on web, but disable + unregister it in native apps.
 */
const setupServiceWorker = () => {
  if (!("serviceWorker" in navigator)) return;

  const isPreviewOrDev =
    import.meta.env.DEV ||
    (typeof window !== "undefined" && (
      window.location.hostname.includes("lovableproject.com") ||
      window.location.hostname.includes("lovable.app")
    ));

  const native =
    isPreviewOrDev ||
    isNativeApp() ||
    (typeof navigator !== "undefined" && /Capacitor/i.test(navigator.userAgent)) ||
    (typeof window !== "undefined" && !!(window as any)?.webkit?.messageHandlers?.bridge);

  const unregisterAll = async () => {
    try {
      const regs = await navigator.serviceWorker.getRegistrations();
      await Promise.all(regs.map((r) => r.unregister()));

      // Also clear SW caches if present (best-effort)
      if ("caches" in window) {
        const keys = await caches.keys();
        await Promise.all(keys.map((k) => caches.delete(k)));
      }

      // eslint-disable-next-line no-console
      console.info("[ECHO_BOOT] service worker disabled (native)");
    } catch (error) {
      // eslint-disable-next-line no-console
      console.error("SW disable/unregister failed:", error);
    }
  };

  // Native + preview/dev: do it ASAP (don’t wait for `load`, which might be too late if a SW
  // is already controlling the page).
  if (native) {
    void (async () => {
      await unregisterAll();

      // If an old SW was controlling this tab, force one hard reload once to fully detach.
      if (navigator.serviceWorker.controller) {
        const reloadKey = '__echo_sw_reset_once__';
        if (!sessionStorage.getItem(reloadKey)) {
          sessionStorage.setItem(reloadKey, '1');
          window.location.reload();
        }
      }
    })();
    return;
  }

  // Web: register after load
  window.addEventListener("load", () => {
    let refreshing = false;

    navigator.serviceWorker
      .register("/registerSW.js", { scope: "/" })
      .then(async (registration) => {
        // Best-effort: ask the browser to check for an updated SW immediately.
        try {
          await registration.update();
        } catch {
          // ignore
        }

        const trySkipWaiting = () => {
          // VitePWA's generated SW listens for this message.
          registration.waiting?.postMessage({ type: "SKIP_WAITING" });
        };

        // If an updated SW is already waiting, activate it.
        trySkipWaiting();

        registration.addEventListener("updatefound", () => {
          const installing = registration.installing;
          if (!installing) return;
          installing.addEventListener("statechange", () => {
            if (installing.state === "installed") {
              trySkipWaiting();
            }
          });
        });

        navigator.serviceWorker.addEventListener("controllerchange", () => {
          // Reload once so the new bundle (including translations) is used.
          if (refreshing) return;
          refreshing = true;
          window.location.reload();
        });
      })
      .catch((error) => console.error("SW registration failed:", error));
  });
};

// Initialize i18n and render the app
initI18n()
  .then(() => {
    renderApp();
    setupServiceWorker();
  })
  .catch((error) => {
    console.error("Failed to initialize i18n:", error);

    // Fallback render without i18n if it fails
    renderApp();
    setupServiceWorker();
  });
