import { StatusBar } from "expo-status-bar";
import { Appearance, useColorScheme } from "react-native";
import {
  createContext,
  useContext,
  useEffect,
  useMemo,
  type ReactNode,
} from "react";

import { useSettingsStore, type ThemeMode } from "@/lib/settings";

type ThemeContextValue = {
  /** "light" | "dark" — the scheme actually in effect (honors our override). */
  colorScheme: "light" | "dark";
  isDark: boolean;
  mode: ThemeMode;
};

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

/**
 * Drives the whole-app theme.
 *
 * NativeWind's `dark:` variants read the React Native `Appearance` module, so
 * calling `Appearance.setColorScheme` with our chosen mode is what makes every
 * `dark:` class apply app-wide — no `darkMode` config key is needed (the
 * default `media` strategy already reads Appearance). The inline-styled spots
 * that can't use Tailwind classes (map style, BottomSheet, tab bar, spinners)
 * consume `useTheme().isDark` instead.
 */
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
  const mode = useSettingsStore((state) => state.mode);

  useEffect(() => {
    // `null` clears the override and falls back to the device scheme.
    Appearance.setColorScheme(mode === "system" ? null : mode);
  }, [mode]);

  const deviceScheme = useColorScheme();
  const resolved = deviceScheme === "dark" ? "dark" : "light";

  const value = useMemo<ThemeContextValue>(
    () => ({ colorScheme: resolved, isDark: resolved === "dark", mode }),
    [resolved, mode],
  );

  return (
    <ThemeContext.Provider value={value}>
      {children}
      <StatusBar style={resolved === "dark" ? "light" : "dark"} />
    </ThemeContext.Provider>
  );
};

export const useTheme = (): ThemeContextValue => {
  const context = useContext(ThemeContext);

  if (!context) {
    throw new Error("useTheme must be used within ThemeProvider.");
  }

  return context;
};