import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import en from './locales/en';

export const SUPPORTED_LANGUAGES = [
  { code: 'en', label: 'English', flag: '\uD83C\uDDEC\uD83C\uDDE7' },
  { code: 'fr', label: 'Fran\u00E7ais', flag: '\uD83C\uDDEB\uD83C\uDDF7' },
  { code: 'de', label: 'Deutsch', flag: '\uD83C\uDDE9\uD83C\uDDEA' },
  { code: 'zh', label: '\u4E2D\u6587', flag: '\uD83C\uDDE8\uD83C\uDDF3' },
  { code: 'hi', label: '\u0939\u093F\u0928\u094D\u0926\u0940', flag: '\uD83C\uDDEE\uD83C\uDDF3' },
  { code: 'hu', label: 'Magyar', flag: '\uD83C\uDDED\uD83C\uDDFA' },
] as const;

export type LanguageCode = (typeof SUPPORTED_LANGUAGES)[number]['code'];

const supportedCodes: Set<string> = new Set(SUPPORTED_LANGUAGES.map((l) => l.code));

function toSupportedLanguage(value: string): LanguageCode | null {
  const lower = value.toLowerCase();
  if (supportedCodes.has(lower)) return lower as LanguageCode;

  const prefix = lower.split('-')[0];
  if (supportedCodes.has(prefix)) return prefix as LanguageCode;

  return null;
}

function getStoredLanguage(): LanguageCode | null {
  try {
    const stored = localStorage.getItem('language');
    return stored ? toSupportedLanguage(stored) : null;
  } catch {
    return null;
  }
}

function getUrlLanguage(): LanguageCode | null {
  try {
    if (typeof window === 'undefined') return null;
    const value = new URLSearchParams(window.location.search).get('lang');
    return value ? toSupportedLanguage(value) : null;
  } catch {
    return null;
  }
}

function getBrowserLanguages(): readonly string[] {
  if (typeof navigator === 'undefined') return [];
  return navigator.languages?.length ? navigator.languages : [navigator.language];
}

function detectLanguage(): LanguageCode {
  // 1. Explicit URL language, used by generated screenshot/OG image URLs.
  const urlLanguage = getUrlLanguage();
  if (urlLanguage) return urlLanguage;

  // 2. Explicit user choice (persisted from the language dropdown)
  const stored = getStoredLanguage();
  if (stored) return stored;

  // 3. Browser preference (navigator.languages falls back to navigator.language)
  for (const tag of getBrowserLanguages()) {
    const language = toSupportedLanguage(tag);
    if (language) return language;
  }

  return 'en';
}

export const INITIAL_LANGUAGE = detectLanguage();

type TranslationResource = Record<string, unknown>;

const localeLoaders: Record<
  Exclude<LanguageCode, 'en'>,
  () => Promise<{ default: TranslationResource }>
> = {
  fr: () => import('./locales/fr'),
  de: () => import('./locales/de'),
  hu: () => import('./locales/hu'),
  zh: () => import('./locales/zh'),
  hi: () => import('./locales/hi'),
};

async function getLanguageResource(
  code: Exclude<LanguageCode, 'en'>
): Promise<TranslationResource> {
  const module = await localeLoaders[code]();
  return module.default;
}

function setDocumentLanguage(code: LanguageCode) {
  if (typeof document !== 'undefined') {
    document.documentElement.lang = code;
  }
}

export async function loadLanguage(code: LanguageCode): Promise<void> {
  if (code === 'en' || i18n.hasResourceBundle(code, 'translation')) return;
  const resource = await getLanguageResource(code);
  i18n.addResourceBundle(code, 'translation', resource, true, true);
}

export async function changeLanguage(code: LanguageCode): Promise<void> {
  await loadLanguage(code);
  await i18n.changeLanguage(code);
  setDocumentLanguage(code);
}

export const i18nReady = (async () => {
  const resources: Record<string, { translation: TranslationResource }> = {
    en: { translation: en },
  };
  let language = INITIAL_LANGUAGE;

  if (language !== 'en') {
    try {
      resources[language] = { translation: await getLanguageResource(language) };
    } catch (error) {
      console.error(`Failed to load ${language} translations`, error);
      language = 'en';
    }
  }

  await i18n.use(initReactI18next).init({
    resources,
    lng: language,
    fallbackLng: 'en',
    interpolation: {
      escapeValue: false, // React already escapes
    },
  });

  setDocumentLanguage(language);
})();

/**
 * Translate a key that is computed at runtime (not a literal).
 * Bypasses the strict type checking on t() for dynamic key construction.
 */
export function tDynamic(key: string): string {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  return (i18n.t as any)(key);
}

export default i18n;
