import { STORAGE_KEYS } from '@/common/constants/storageKeys';
import { Language, LanguagePreference, setLanguage as setLangCore } from '@/common/strings';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { getLocales } from 'expo-localization';
import { ReactNode, createContext, useCallback, useContext, useEffect, useState } from 'react';
import { useColorScheme } from 'react-native';

export type Theme = 'light' | 'dark' | 'system';

interface PreferencesContextValue {
  theme: Theme;
  isDarkMode: boolean;
  setTheme: (theme: Theme) => void;
  enabledCastleFeatures: string[];
  toggleCastleFeature: (feature: string) => void;
  hapticFeedback: boolean;
  setHapticFeedback: (enabled: boolean) => void;
  languagePreference: LanguagePreference;
  setLanguage: (lang: LanguagePreference) => void;
}

const PreferencesContext = createContext<PreferencesContextValue | null>(null);

function getDeviceLanguage(): Language {
  const locales = getLocales();
  if (locales && locales.length > 0 && locales[0].languageCode === 'ko') {
    return 'ko';
  }
  return 'en';
}

export function PreferencesProvider({ children }: { children: ReactNode }) {
  const systemScheme = useColorScheme();
  const [theme, setThemeState] = useState<Theme>('system');
  const [enabledCastleFeatures, setEnabledCastleFeatures] = useState<string[]>([]);
  const [hapticFeedback, setHapticFeedbackState] = useState(true);
  const [languagePreference, setLanguagePreferenceState] = useState<LanguagePreference>('system');
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    const langToSet = languagePreference === 'system' ? getDeviceLanguage() : languagePreference;
    setLangCore(langToSet);
  }, [languagePreference]);

  useEffect(() => {
    Promise.all([
      AsyncStorage.getItem(STORAGE_KEYS.THEME),
      AsyncStorage.getItem(STORAGE_KEYS.CASTLE_FEATURES),
      AsyncStorage.getItem(STORAGE_KEYS.HAPTIC),
      AsyncStorage.getItem(STORAGE_KEYS.LANGUAGE),
    ])
      .then(([storedTheme, storedCastleFeatures, storedHaptic, storedLang]) => {
        if (storedTheme === 'light' || storedTheme === 'dark' || storedTheme === 'system') {
          setThemeState(storedTheme);
        }
        if (storedCastleFeatures) {
          try {
            setEnabledCastleFeatures(JSON.parse(storedCastleFeatures));
          } catch {
            void 0;
          }
        }
        setHapticFeedbackState(storedHaptic !== 'false');

        if (storedLang === 'en' || storedLang === 'ko' || storedLang === 'system') {
          setLanguagePreferenceState(storedLang);
        }
      })
      .catch(e => {
        console.error('Failed to load preferences', e);
      })
      .finally(() => setLoaded(true));
  }, []);

  const setTheme = useCallback((newTheme: Theme) => {
    setThemeState(newTheme);
    AsyncStorage.setItem(STORAGE_KEYS.THEME, newTheme);
  }, []);

  const toggleCastleFeature = useCallback((feature: string) => {
    setEnabledCastleFeatures(prev => {
      const next = prev.includes(feature) ? prev.filter(f => f !== feature) : [...prev, feature];
      AsyncStorage.setItem(STORAGE_KEYS.CASTLE_FEATURES, JSON.stringify(next));
      return next;
    });
  }, []);

  const setHapticFeedback = useCallback((enabled: boolean) => {
    setHapticFeedbackState(enabled);
    AsyncStorage.setItem(STORAGE_KEYS.HAPTIC, String(enabled));
  }, []);

  const setLanguage = useCallback((pref: LanguagePreference) => {
    setLanguagePreferenceState(pref);
    AsyncStorage.setItem(STORAGE_KEYS.LANGUAGE, pref);
  }, []);

  const isDarkMode = theme === 'system' ? systemScheme === 'dark' : theme === 'dark';

  if (!loaded) return null;

  return (
    <PreferencesContext.Provider
      value={{
        theme,
        isDarkMode,
        setTheme,
        enabledCastleFeatures,
        toggleCastleFeature,
        hapticFeedback,
        setHapticFeedback,
        languagePreference,
        setLanguage,
      }}
    >
      {children}
    </PreferencesContext.Provider>
  );
}

export function usePreferences() {
  const context = useContext(PreferencesContext);
  if (!context) throw new Error('usePreferences must be used within PreferencesProvider');
  return context;
}
