"use client";

import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import type { Locale } from "@/types";
import { DEFAULT_LOCALE, LOCALES } from "@/constants/site";
import { getDictionary, resolveKey, type Dictionary } from "@/i18n";
import { settingsApi } from "@/api/settings.api";
import { qk } from "@/lib/queryKeys";

export interface LanguageOption {
  code: string;
  name: string;
  dir: "ltr" | "rtl";
  flag?: string;
}

interface I18nContextValue {
  locale: Locale;
  dir: "ltr" | "rtl";
  t: (key: string) => string;
  setLocale: (locale: string) => void;
  dict: Dictionary;
  languages: LanguageOption[];
  apiTranslations: Record<string, string>;
}

const I18nContext = createContext<I18nContextValue | undefined>(undefined);

const STORAGE_KEY = "xremit_locale";

const STATIC_LANGUAGES: LanguageOption[] = LOCALES.map((l) => ({
  code: l.code,
  name: l.label,
  dir: l.dir,
  flag: l.flag,
}));

export function I18nProvider({ children }: { children: React.ReactNode }) {
  const [locale, setLocaleState] = useState<Locale>(DEFAULT_LOCALE);

  const { data: langData } = useQuery({
    queryKey: qk.settings.language,
    queryFn: settingsApi.language,
    staleTime: 5 * 60_000,
  });

  const apiLanguages = useMemo(
    () => langData?.languages ?? [],
    [langData],
  );

  const languages = useMemo<LanguageOption[]>(() => {
    if (apiLanguages.length > 0) {
      return apiLanguages.map((l) => ({
        code: l.code,
        name: l.name,
        dir: l.dir,
        flag: LOCALES.find((loc) => loc.code === l.code)?.flag,
      }));
    }
    return STATIC_LANGUAGES;
  }, [apiLanguages]);

  // Hydrate from localStorage on mount
  useEffect(() => {
    try {
      const stored = localStorage.getItem(STORAGE_KEY) as Locale | null;
      if (stored) setLocaleState(stored as Locale);
    } catch {
      /* ignore */
    }
  }, []);

  const dir = useMemo<"ltr" | "rtl">(() => {
    const apiLang = apiLanguages.find((l) => l.code === locale);
    if (apiLang) return apiLang.dir;
    return LOCALES.find((l) => l.code === locale)?.dir ?? "ltr";
  }, [locale, apiLanguages]);

  useEffect(() => {
    if (typeof document !== "undefined") {
      document.documentElement.lang = locale;
      document.documentElement.dir = dir;
    }
  }, [locale, dir]);

  const setLocale = useCallback((next: string) => {
    setLocaleState(next);
    try {
      localStorage.setItem(STORAGE_KEY, next);
    } catch {
      /* ignore */
    }
  }, []);

  const dict = useMemo(() => getDictionary(locale), [locale]);

  const apiTranslations = useMemo<Record<string, string>>(
    () => apiLanguages.find((l) => l.code === locale)?.translate_key_values ?? {},
    [apiLanguages, locale],
  );

  const t = useCallback(
    (key: string) => apiTranslations[key] ?? resolveKey(dict, key),
    [apiTranslations, dict],
  );

  const value = useMemo<I18nContextValue>(
    () => ({ locale, dir, t, setLocale, dict, languages, apiTranslations }),
    [locale, dir, t, setLocale, dict, languages, apiTranslations],
  );

  return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>;
}

export function useTranslation() {
  const ctx = useContext(I18nContext);
  if (!ctx) throw new Error("useTranslation must be used within I18nProvider");
  return ctx;
}
