// Sentry init AVANT tout autre import non-essentiel pour capturer même
// les erreurs de bootstrap (cf. apps/web/src/lib/sentry.ts).
import "./lib/sentry";

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { RouterProvider, createRouter } from "@tanstack/react-router";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import * as Sentry from "@sentry/react";

import { routeTree } from "./routeTree.gen";
import { env } from "./lib/env";
import { api } from "./lib/api";
import { authStore } from "./lib/auth";
import type { AuthSession } from "@rubis/shared";

import "./styles/app.css";

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 30_000,
      gcTime: 5 * 60_000,
      retry: 1,
      refetchOnWindowFocus: false,
    },
    mutations: {
      retry: 0,
    },
  },
});

const router = createRouter({
  routeTree,
  context: { queryClient },
  defaultPreload: "intent",
  defaultPreloadStaleTime: 0,
});

declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}

async function enableMocking(): Promise<void> {
  // import.meta.env.DEV est un booléen statique : Vite tree-shake la branche
  // entière (et le chunk MSW avec) quand on build en mode production.
  if (!import.meta.env.DEV || !env.VITE_USE_MOCKS) return;
  const { worker } = await import("./mocks/browser");
  await worker.start({
    onUnhandledRequest: "bypass",
    serviceWorker: {
      url: "/mockServiceWorker.js",
    },
  });
  // eslint-disable-next-line no-console
  console.info(
    "%c[MSW]%c Mocks API actifs — VITE_USE_MOCKS=true",
    "background:#9F1239;color:white;padding:2px 6px;border-radius:3px;font-weight:600",
    "color:#8A7F76",
  );
}

/**
 * Tente de récupérer la session à partir du refresh token (cf. ADR-017).
 * Si le serveur (ou MSW) confirme une session valide → on rehydrate l'authStore
 * AVANT le 1er render, ce qui évite le flash redirect /login pour les users
 * déjà connectés.
 *
 * En mode dev avec MSW, la "session" persistée est en localStorage (cf.
 * mocks/sessionStore). En prod réel, c'est le cookie httpOnly côté Adonis.
 */
async function bootstrapSession(): Promise<void> {
  try {
    const session = await api.post<AuthSession>(
      "/api/v1/auth/refresh",
      undefined,
      { anonymous: true },
    );
    authStore.setSession(session.accessToken, session.user);
  } catch {
    // Pas de session valide → on reste anonyme. _app guard redirigera vers /login.
  }
}

function FallbackError() {
  return (
    <div className="min-h-screen flex items-center justify-center bg-cream px-6">
      <div className="text-center max-w-md">
        <h1 className="font-display text-3xl mb-3 text-ink">Quelque chose a coincé.</h1>
        <p className="text-ink-2 mb-6">
          On a noté, on regarde. Rechargez la page pour réessayer.
        </p>
        <button
          onClick={() => location.reload()}
          className="bg-rubis hover:bg-rubis-deep text-white px-5 py-2.5 rounded-md font-medium transition-colors"
        >
          Recharger
        </button>
      </div>
    </div>
  );
}

function render(): void {
  const rootEl = document.getElementById("root");
  if (!rootEl) throw new Error("#root introuvable dans index.html");
  createRoot(rootEl).render(
    <StrictMode>
      <Sentry.ErrorBoundary fallback={<FallbackError />}>
        <QueryClientProvider client={queryClient}>
          <RouterProvider router={router} />
        </QueryClientProvider>
      </Sentry.ErrorBoundary>
    </StrictMode>,
  );
}

async function init(): Promise<void> {
  await enableMocking();
  await bootstrapSession();
  render();
}

void init();
