import {
  createContext,
  useContext,
  useEffect,
  useMemo,
  type ReactNode,
} from "react";

import { useSettingsStore, type Lang } from "@/lib/settings";
import { ar } from "@/lib/translations/ar";
import { en } from "@/lib/translations/en";
import { fr } from "@/lib/translations/fr";

export type Vars = Record<string, string | number>;

/**
 * Lightweight i18n. No external dependency: three languages, dot-path keys,
 * `{var}` interpolation, and a `one`/`other`/`zero` plural convention that
 * covers the few counts this app shows (minutes, seats).
 */
const DICTS: Record<Lang, Record<string, unknown>> = { en, ar, fr };

const interpolate = (text: string, vars?: Vars): string =>
  vars
    ? text.replace(/\{(\w+)\}/g, (_, key: string) => String(vars[key] ?? ""))
    : text;

const readPath = (dict: Record<string, unknown>, path: string): unknown =>
  path.split(".").reduce<unknown>(
    (acc, segment) =>
      acc && typeof acc === "object"
        ? (acc as Record<string, unknown>)[segment]
        : undefined,
    dict,
  );

const translate = (
  lang: Lang,
  key: string,
  vars?: Vars,
  count?: number,
): string => {
  const dict = DICTS[lang] ?? en;

  if (count !== undefined) {
    const pluralSuffix =
      count === 0 ? "zero" : count === 1 ? "one" : "other";
    const pluralValue = readPath(dict, `${key}.${pluralSuffix}`);

    if (typeof pluralValue === "string") {
      return interpolate(pluralValue, { n: count, ...vars });
    }
  }

  const value = readPath(dict, key);

  if (typeof value === "string") return interpolate(value, vars);

  // Fall back to English, then to the key itself, so a missing translation
  // never renders an empty string.
  if (lang !== "en") {
    const fallback = readPath(en, key);
    if (typeof fallback === "string") return interpolate(fallback, vars);
  }

  return key;
};

/**
 * Module-level translator for non-React helpers (`lib/utils.ts`,
 * `lib/pricing.ts`) that can't call `useT`. The I18nProvider sets this on
 * mount and whenever the language changes; until then it defaults to English.
 */
let activeLang: Lang = "en";

export const setTranslator = (lang: Lang) => {
  activeLang = lang;
};

export const tr = (key: string, vars?: Vars, count?: number): string =>
  translate(activeLang, key, vars, count);

type I18nContextValue = {
  lang: Lang;
  isRTL: boolean;
  t: (key: string, vars?: Vars, count?: number) => string;
};

const I18nContext = createContext<I18nContextValue | null>(null);

export const I18nProvider = ({ children }: { children: ReactNode }) => {
  const lang = useSettingsStore((state) => state.lang);

  useEffect(() => {
    setTranslator(lang);
  }, [lang]);

  const value = useMemo<I18nContextValue>(
    () => ({
      lang,
      isRTL: lang === "ar",
      t: (key, vars, count) => translate(lang, key, vars, count),
    }),
    [lang],
  );

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

export const useT = (): I18nContextValue["t"] => {
  const context = useContext(I18nContext);

  if (!context) {
    throw new Error("useT must be used within I18nProvider.");
  }

  return context.t;
};

export const useI18n = (): I18nContextValue => {
  const context = useContext(I18nContext);

  if (!context) {
    throw new Error("useI18n must be used within I18nProvider.");
  }

  return context;
};