import React from 'react';
import { DEFAULT_LOCALE, SUPPORTED_LOCALES, type LocaleCode, isLocaleCode } from './messages';

export interface LocaleContextValue {
  locale: LocaleCode;
  setLocale: (next: LocaleCode) => void;
  resetLocale: () => void;
  hydrated: boolean;
  defaultLocale: LocaleCode;
  storageKey: string;
  availableLocales: typeof SUPPORTED_LOCALES;
}

const LocaleContext = React.createContext<LocaleContextValue | undefined>(undefined);

function sanitizeLocale(value: string | null | undefined, fallback: LocaleCode = DEFAULT_LOCALE): LocaleCode {
  if (value && isLocaleCode(value)) {
    return value;
  }
  return fallback;
}

export interface LocaleProviderProps {
  children: React.ReactNode;
  defaultLocale?: LocaleCode;
  storageKey?: string;
}

export function LocaleProvider({
  children,
  defaultLocale = DEFAULT_LOCALE,
  storageKey = 'guestLocale_global',
}: LocaleProviderProps) {
  const resolvedDefault = sanitizeLocale(defaultLocale, DEFAULT_LOCALE);
  const [locale, setLocaleState] = React.useState<LocaleCode>(resolvedDefault);
  const [userLocale, setUserLocale] = React.useState<LocaleCode | null>(null);
  const [hydrated, setHydrated] = React.useState(false);

  React.useEffect(() => {
    setHydrated(false);

    if (typeof window === 'undefined') {
      setLocaleState(resolvedDefault);
      setUserLocale(null);
      setHydrated(true);
      return;
    }

    let stored: string | null = null;
    try {
      stored = window.localStorage.getItem(storageKey);
    } catch (error) {
      console.warn('Failed to read stored locale', error);
    }

    const nextLocale = sanitizeLocale(stored, resolvedDefault);
    setLocaleState(nextLocale);
    setUserLocale(isLocaleCode(stored) ? stored : null);
    setHydrated(true);
  }, [storageKey, resolvedDefault]);

  React.useEffect(() => {
    if (!hydrated || userLocale !== null) {
      return;
    }
    setLocaleState(resolvedDefault);
  }, [hydrated, userLocale, resolvedDefault]);

  const setLocale = React.useCallback(
    (next: LocaleCode) => {
      const safeLocale = sanitizeLocale(next, resolvedDefault);
      setLocaleState(safeLocale);
      setUserLocale(safeLocale);

      if (typeof window !== 'undefined') {
        try {
          window.localStorage.setItem(storageKey, safeLocale);
        } catch (error) {
          console.warn('Failed to persist locale', error);
        }
      }
    },
    [storageKey, resolvedDefault],
  );

  const resetLocale = React.useCallback(() => {
    setUserLocale(null);
    setLocaleState(resolvedDefault);
    if (typeof window !== 'undefined') {
      try {
        window.localStorage.removeItem(storageKey);
      } catch (error) {
        console.warn('Failed to clear stored locale', error);
      }
    }
  }, [resolvedDefault, storageKey]);

  const value = React.useMemo<LocaleContextValue>(
    () => ({
      locale,
      setLocale,
      resetLocale,
      hydrated,
      defaultLocale: resolvedDefault,
      storageKey,
      availableLocales: SUPPORTED_LOCALES,
    }),
    [locale, setLocale, resetLocale, hydrated, resolvedDefault, storageKey],
  );

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

export function useLocale(): LocaleContextValue {
  const ctx = React.useContext(LocaleContext);
  if (!ctx) {
    throw new Error('useLocale must be used within a LocaleProvider');
  }
  return ctx;
}

export function useOptionalLocale(): LocaleContextValue | undefined {
  return React.useContext(LocaleContext);
}
