import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from "react";
import {
  applyResolvedTheme,
  loadThemePreference,
  resolveTheme,
  saveThemePreference,
  type ResolvedTheme,
  type ThemePreference,
} from "../lib/theme";

type ThemeContextValue = {
  /** 使用者偏好：light / dark / system */
  preference: ThemePreference;
  /** 實際套用：light / dark */
  resolved: ResolvedTheme;
  setPreference: (theme: ThemePreference) => void;
  /** 在 light ↔ dark 間切換（若目前是 system 則以 resolved 為基準） */
  toggle: () => void;
};

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

export function ThemeProvider({ children }: { children: ReactNode }) {
  const [preference, setPreferenceState] = useState<ThemePreference>(() => loadThemePreference());
  const [resolved, setResolved] = useState<ResolvedTheme>(() =>
    resolveTheme(loadThemePreference()),
  );

  const apply = useCallback((pref: ThemePreference) => {
    const next = resolveTheme(pref);
    setResolved(next);
    applyResolvedTheme(next);
  }, []);

  useEffect(() => {
    apply(preference);
  }, [preference, apply]);

  // system：跟著 OS 切
  useEffect(() => {
    if (preference !== "system") return;
    let mq: MediaQueryList;
    try {
      mq = window.matchMedia("(prefers-color-scheme: dark)");
    } catch {
      return;
    }
    const onChange = () => apply("system");
    mq.addEventListener("change", onChange);
    return () => mq.removeEventListener("change", onChange);
  }, [preference, apply]);

  const setPreference = useCallback((theme: ThemePreference) => {
    setPreferenceState(theme);
    saveThemePreference(theme);
  }, []);

  const toggle = useCallback(() => {
    setPreferenceState((prev) => {
      const base = prev === "system" ? resolveTheme("system") : prev;
      const next: ThemePreference = base === "dark" ? "light" : "dark";
      saveThemePreference(next);
      return next;
    });
  }, []);

  const value = useMemo(
    () => ({ preference, resolved, setPreference, toggle }),
    [preference, resolved, setPreference, toggle],
  );

  return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
}

export function useTheme(): ThemeContextValue {
  const ctx = useContext(ThemeContext);
  if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
  return ctx;
}
