'use client';

import { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react';

import { LANG_COOKIE, DEFAULT_LANG, isRtlLang } from './languageConstants';

const LS_KEY = 'rra_lang';

export { LANG_COOKIE, DEFAULT_LANG, isRtlLang };

function writeLangCookie(code: string) {
  if (typeof document === 'undefined') return;
  // 1 year, root path, lax — readable on the server for SSR.
  const maxAge = 60 * 60 * 24 * 365;
  document.cookie = `${LANG_COOKIE}=${encodeURIComponent(code)}; path=/; max-age=${maxAge}; SameSite=Lax`;
}

export interface Language {
  code: string;
  name: string;
  native_name: string;
  flag_emoji: string;
  is_rtl: boolean;
  is_active: boolean;
  is_default: boolean;
  display_order: number;
}

interface LanguageContextValue {
  currentLang: string;
  isRTL: boolean;
  dir: 'ltr' | 'rtl';
  translations: Record<string, string>;
  loading: boolean;
  setLang: (code: string) => void;
  t: (key: string, fallback?: string, vars?: Record<string, string | number>) => string;
  activeLanguages: Language[];
  syncUserLanguage: (preferredLang: string) => void;
  bustCache: (langCode: string) => void;
}

const LanguageContext = createContext<LanguageContextValue>({
  currentLang: DEFAULT_LANG,
  isRTL: false,
  dir: 'ltr',
  translations: {},
  loading: false,
  setLang: () => {},
  t: (key, fallback) => fallback ?? key,
  activeLanguages: [],
  syncUserLanguage: () => {},
  bustCache: () => {},
});

export function useLanguage() {
  return useContext(LanguageContext);
}

export function useTranslation() {
  const { t, currentLang, isRTL, dir } = useContext(LanguageContext);
  return { t, currentLang, isRTL, dir };
}

export function LanguageProvider({
  children,
  initialLang,
}: {
  children: React.ReactNode;
  initialLang?: string;
}) {
  // The initial language must come from a source available on both server
  // and first client render (a cookie injected by the server) so the SSR
  // markup matches what React produces on hydration. We deliberately do
  // NOT read localStorage to seed initial state — that would diverge from
  // the SSR pass and trigger a hydration mismatch.
  const [currentLang, setCurrentLang] = useState<string>(initialLang || DEFAULT_LANG);
  const [translations, setTranslations] = useState<Record<string, string>>({});
  const [activeLanguages, setActiveLanguages] = useState<Language[]>([]);
  const [loading, setLoading] = useState(false);
  const cacheRef = useRef<Record<string, Record<string, string>>>({});

  useEffect(() => {
    // Migrate any legacy localStorage value into the cookie so subsequent
    // requests render the right language on the server too.
    if (typeof window !== 'undefined') {
      const saved = localStorage.getItem(LS_KEY);
      if (saved && saved !== currentLang) {
        writeLangCookie(saved);
        setCurrentLang(saved);
      } else if (currentLang) {
        writeLangCookie(currentLang);
      }
    }
    fetchActiveLanguages();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    fetchTranslations(currentLang);
  }, [currentLang]);

  useEffect(() => {
    if (typeof document === 'undefined') return;
    const meta = activeLanguages.find(l => l.code === currentLang);
    const rtl = meta ? meta.is_rtl : isRtlLang(currentLang);
    document.documentElement.lang = currentLang;
    document.documentElement.dir = rtl ? 'rtl' : 'ltr';
    if (rtl) {
      document.body.classList.add('rtl-mode');
    } else {
      document.body.classList.remove('rtl-mode');
    }
  }, [currentLang, activeLanguages]);

  async function fetchActiveLanguages() {
    try {
      const res = await fetch('/api/public/languages');
      if (res.ok) {
        const data = await res.json() as { languages: Language[] };
        setActiveLanguages(data.languages || []);
      }
    } catch {
      setActiveLanguages([]);
    }
  }

  async function fetchTranslations(lang: string) {
    if (cacheRef.current[lang]) {
      setTranslations(cacheRef.current[lang]);
      return;
    }
    setLoading(true);
    try {
      const res = await fetch(`/api/public/translations?lang=${encodeURIComponent(lang)}`);
      if (res.ok) {
        const data = await res.json() as Record<string, string>;
        cacheRef.current[lang] = data || {};
        setTranslations(data || {});
      }
    } catch {
      setTranslations({});
    } finally {
      setLoading(false);
    }
  }

  const syncUserLanguage = useCallback((preferredLang: string) => {
    if (!preferredLang) return;
    setCurrentLang(prev => {
      if (prev === preferredLang) return prev;
      if (typeof window !== 'undefined') {
        localStorage.setItem(LS_KEY, preferredLang);
        writeLangCookie(preferredLang);
      }
      return preferredLang;
    });
  }, []);

  const setLang = useCallback((code: string) => {
    setCurrentLang(code);
    if (typeof window !== 'undefined') {
      localStorage.setItem(LS_KEY, code);
      writeLangCookie(code);
    }
    fetch('/api/auth/me/language', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ lang: code }),
    }).catch(() => {});
  }, []);

  const bustCache = useCallback((langCode: string) => {
    delete cacheRef.current[langCode];
    setCurrentLang(prev => {
      if (prev === langCode) {
        void fetchTranslations(langCode);
      }
      return prev;
    });
  }, []);

  const t = useCallback((key: string, fallback?: string, vars?: Record<string, string | number>): string => {
    let result = translations[key] ?? fallback ?? key;
    if (vars) {
      Object.entries(vars).forEach(([k, v]) => {
        result = result.replace(new RegExp(`\\{\\{${k}\\}\\}`, 'g'), String(v));
      });
    }
    return result;
  }, [translations]);

  const currentLangMeta = activeLanguages.find(l => l.code === currentLang);
  const isRTL = currentLangMeta ? currentLangMeta.is_rtl : isRtlLang(currentLang);

  return (
    <LanguageContext.Provider value={{
      currentLang,
      isRTL,
      dir: isRTL ? 'rtl' : 'ltr',
      translations,
      loading,
      setLang,
      t,
      activeLanguages,
      syncUserLanguage,
      bustCache,
    }}>
      {children}
    </LanguageContext.Provider>
  );
}
