import React, { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react';
import { Language, TranslationKeys, loadLanguage, fetchAvailableLanguageCodes, I18nCodeInfo } from '../../locales';
import { getUserDataCache } from '../../utils/userCache';


export type { Language };

type TranslateParams = Record<string, string | number | boolean | null | undefined>;

interface LanguageContextType {
    currentLanguage: Language;
    setLanguage: (language: Language) => void;
    t: (key: string, params?: TranslateParams) => string;
    isLoading: boolean;
    reloadLanguage: () => Promise<void>;
    availableLanguages: I18nCodeInfo[];
    refreshAvailableLanguages: () => Promise<void>;
}

const LanguageContext = createContext<LanguageContextType | undefined>(undefined);

interface LanguageProviderProps {
    children: ReactNode;
}

export const LanguageProvider: React.FC<LanguageProviderProps> = ({ children }) => {
    const [currentLanguage, setCurrentLanguage] = useState<Language>('de');
    const [translations, setTranslations] = useState<TranslationKeys>({});
    const [isLoading, setIsLoading] = useState(true);
    const [availableLanguages, setAvailableLanguages] = useState<I18nCodeInfo[]>([]);

    const loadAndSetLanguage = async (language: Language) => {
        setIsLoading(true);
        try {
            const targetKeys = await loadLanguage(language);
            setTranslations(targetKeys);
            setCurrentLanguage(language);
        } catch (error) {
            console.error('Failed to load language:', error);
        } finally {
            setIsLoading(false);
        }
    };

    useEffect(() => {
        const initializeLanguage = async () => {
            let initialLanguage: Language = 'de';
            
            const userData = getUserDataCache();
            if (userData?.language && String(userData.language).trim()) {
                initialLanguage = String(userData.language).trim() as Language;
                await loadAndSetLanguage(initialLanguage);
                return;
            }
            
            const browserLang = navigator.language.split('-')[0] as Language;
            try {
                const codes = await fetchAvailableLanguageCodes();
                const codeSet = new Set(codes.map((c) => c.code));
                if (codeSet.has(browserLang) && browserLang !== 'xx') {
                    initialLanguage = browserLang;
                }
            } catch {
                // keep default
            }
            
            await loadAndSetLanguage(initialLanguage);
        };

        initializeLanguage();
        
        const handleUserUpdate = async () => {
            const userData = getUserDataCache();
            if (userData?.language && String(userData.language).trim()) {
                const userLanguage = String(userData.language).trim() as Language;
                if (userLanguage !== currentLanguage) {
                    loadAndSetLanguage(userLanguage);
                }
            }
            try {
                const list = await fetchAvailableLanguageCodes();
                setAvailableLanguages(list.filter((l) => l.code !== 'xx'));
            } catch {
                // silent
            }
        };

        window.addEventListener('userInfoUpdated', handleUserUpdate);
        
        return () => {
            window.removeEventListener('userInfoUpdated', handleUserUpdate);
        };
    }, []);

    const setLanguage = async (language: Language) => {
        await loadAndSetLanguage(language);
    };

    const reloadLanguage = async () => {
        await loadAndSetLanguage(currentLanguage);
    };

    const refreshAvailableLanguages = useCallback(async () => {
        try {
            const list = await fetchAvailableLanguageCodes();
            setAvailableLanguages(list.filter((l) => l.code !== 'xx'));
        } catch (e) {
            console.error('Failed to load language codes:', e);
        }
    }, []);

    useEffect(() => {
        refreshAvailableLanguages();
    }, [refreshAvailableLanguages]);

    const _applyParams = (template: string, params?: TranslateParams): string => {
        if (!params) return template;
        let out = template;
        for (const [paramKey, rawVal] of Object.entries(params)) {
            if (rawVal === undefined || rawVal === null) continue;
            out = out.split(`{${paramKey}}`).join(String(rawVal));
        }
        return out;
    };

    const t = (key: string, params?: TranslateParams): string => {
        const resolved = translations[key] ?? `[${key}]`;
        return _applyParams(resolved, params);
    };

    const contextValue: LanguageContextType = {
        currentLanguage,
        setLanguage,
        t,
        isLoading,
        reloadLanguage,
        availableLanguages,
        refreshAvailableLanguages,
    };

    return (
        <LanguageContext.Provider value={contextValue}>
            {children}
        </LanguageContext.Provider>
    );
};

export const useLanguage = (): LanguageContextType => {
    const context = useContext(LanguageContext);
    if (!context) {
        throw new Error('useLanguage must be used within a LanguageProvider');
    }
    return context;
};
