"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useState,
  type ReactNode,
} from "react";

export type Theme = "light" | "dark" | "system";
export type ResolvedTheme = "light" | "dark";

type Ctx = {
  theme: Theme;
  resolved: ResolvedTheme;
  setTheme: (t: Theme) => void;
};

const ThemeContext = createContext<Ctx | null>(null);

const STORAGE_KEY = "mf-theme";

function readStored(): Theme {
  if (typeof window === "undefined") return "system";
  try {
    const raw = window.localStorage.getItem(STORAGE_KEY);
    if (raw === "light" || raw === "dark" || raw === "system") return raw;
  } catch {
    /* localStorage indisponible (ex: Safari privé) */
  }
  return "system";
}

function getSystemPref(): ResolvedTheme {
  if (typeof window === "undefined") return "light";
  return window.matchMedia("(prefers-color-scheme: dark)").matches
    ? "dark"
    : "light";
}

function applyClass(resolved: ResolvedTheme) {
  if (typeof document === "undefined") return;
  document.documentElement.classList.toggle("dark", resolved === "dark");
}

export function useTheme() {
  const ctx = useContext(ThemeContext);
  if (!ctx) throw new Error("useTheme must be inside <ThemeProvider>");
  return ctx;
}

export function ThemeProvider({ children }: { children: ReactNode }) {
  // Lazy initializer : lit localStorage à la première render client. SSR =
  // 'system' par défaut. Le script inline dans <body> a déjà posé la classe
  // .dark si nécessaire avant l'hydration, donc pas de FOUC.
  const [theme, setThemeState] = useState<Theme>(readStored);

  // Calcul du resolved selon le theme courant.
  const computeResolved = useCallback((t: Theme): ResolvedTheme => {
    if (t === "system") return getSystemPref();
    return t;
  }, []);

  const [resolved, setResolved] = useState<ResolvedTheme>(() =>
    computeResolved(readStored()),
  );

  // Réagit aux changements de prefers-color-scheme quand on est en mode
  // 'system'. Side effect uniquement (apply class), pas de setState — donc
  // pas de violation react-hooks/set-state-in-effect.
  useEffect(() => {
    if (theme !== "system") {
      applyClass(theme);
      return;
    }
    const mq = window.matchMedia("(prefers-color-scheme: dark)");
    const update = () => {
      const next: ResolvedTheme = mq.matches ? "dark" : "light";
      applyClass(next);
      setResolved(next);
    };
    update();
    mq.addEventListener("change", update);
    return () => mq.removeEventListener("change", update);
  }, [theme]);

  const setTheme = useCallback(
    (t: Theme) => {
      try {
        window.localStorage.setItem(STORAGE_KEY, t);
      } catch {
        /* ignore */
      }
      setThemeState(t);
      const next = computeResolved(t);
      applyClass(next);
      setResolved(next);
    },
    [computeResolved],
  );

  return (
    <ThemeContext.Provider value={{ theme, resolved, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Script inline injecté dans <body> au tout début, AVANT React, pour
// éviter un flash blanc au chargement quand le user a choisi dark. Lit
// localStorage et applique la classe directement.
export const NO_FOUC_SCRIPT = `(function(){try{var t=localStorage.getItem("mf-theme")||"system";var d=t==="dark"||(t==="system"&&matchMedia("(prefers-color-scheme: dark)").matches);if(d)document.documentElement.classList.add("dark")}catch(e){}})();`;
