import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { App } from "@/App";
import { AuthProvider } from "@/contexts/AuthContext";
import { LanguageProvider } from "@/contexts/LanguageContext";
import { ThemeProvider, applyTheme } from "@/contexts/ThemeContext";
import { BrandingProvider } from "@/contexts/BrandingContext";
import { ApiError } from "@/lib/api";
import { ErrorFallback } from "@/components/ErrorFallback";
// R1: self-hosted fonts only (CSP blocks Google Fonts). Import only the
// weights/subsets the design uses so the font payload stays inside budget -
// an EN page loads latin Plex Sans + latin Cormorant Garamond; an AR page
// loads arabic Plex Sans Arabic + arabic Amiri (unicode-range means the
// browser only fetches the subset the page actually renders).
import "@fontsource/ibm-plex-sans/latin-400.css";
import "@fontsource/ibm-plex-sans/latin-500.css";
import "@fontsource/ibm-plex-sans/latin-600.css";
import "@fontsource/ibm-plex-sans-arabic/arabic-400.css";
import "@fontsource/ibm-plex-sans-arabic/arabic-500.css";
import "@fontsource/ibm-plex-sans-arabic/arabic-600.css";
import "@fontsource/cormorant-garamond/latin-500.css";
import "@fontsource/cormorant-garamond/latin-600.css";
import "@fontsource/amiri/arabic-400.css";
import "@fontsource/amiri/arabic-700.css";
import "@/styles.css";

// R1/D2: apply the persisted theme (light/dark/system) to <html> - and the
// matching <meta name="theme-color"> - before the first paint. CSP forbids
// inline <script> in index.html, so this runs here, synchronously, before
// createRoot: no flash of the wrong theme or status-bar colour.
try {
  const stored = window.localStorage.getItem("azl-theme");
  applyTheme(stored === "light" || stored === "dark" ? stored : "system");
} catch {
  // localStorage unavailable (private mode, blocked storage) - fall back to system.
  applyTheme("system");
}

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 60_000,
      gcTime: 6 * 60 * 60_000,
      refetchOnWindowFocus: false,
      refetchOnReconnect: true,
      retry: (failureCount, error) =>
        error instanceof ApiError
          ? ["NETWORK_ERROR", "INVALID_RESPONSE", "INTERNAL_ERROR"].includes(error.code) && failureCount < 2
          : failureCount < 1,
    },
    mutations: { retry: false },
  },
});

const tree = (
  <React.StrictMode>
    <BrowserRouter>
      <QueryClientProvider client={queryClient}>
        <ThemeProvider>
          <LanguageProvider>
            <BrandingProvider>
              <AuthProvider queryClient={queryClient}>
                <App />
              </AuthProvider>
            </BrandingProvider>
          </LanguageProvider>
        </ThemeProvider>
      </QueryClientProvider>
    </BrowserRouter>
  </React.StrictMode>
);

// T1.9 (monitoring): render immediately so a configured DSN never delays
// first paint (the @sentry/react chunk is ~160 kB gzipped - worth fetching
// for error reporting, but not worth blocking boot on over a slow
// connection). When VITE_SENTRY_DSN is unset, initSentry() resolves null
// without ever importing @sentry/react, so dev/tests/a staging build
// without a Sentry project pay nothing - no request, no bundle growth. Once
// Sentry is ready, re-render the same tree wrapped in its <ErrorBoundary>;
// React reconciles this as a no-op DOM change since the element is
// otherwise identical.
const root = ReactDOM.createRoot(document.getElementById("root")!);
root.render(tree);

async function attachSentryErrorBoundary() {
  const { initSentry } = await import("@/lib/sentry");
  const Sentry = await initSentry();
  if (Sentry) root.render(<Sentry.ErrorBoundary fallback={<ErrorFallback />}>{tree}</Sentry.ErrorBoundary>);
}

if (import.meta.env.VITE_SENTRY_DSN?.trim()) void attachSentryErrorBoundary();
