// Cinco idiomas, inglés por defecto. El texto vive en /lang/<código>.json y no
// dentro de los componentes: añadir un capítulo es tocar cinco entradas, no
// cinco maquetados.
//
// Cómo se decide el idioma, por orden: la ruta (/es/…), lo que el usuario eligió
// la última vez, lo que pide su navegador, y si nada encaja, inglés.

const LANGS = [
  { code: 'en', label: 'EN', name: 'English' },
  { code: 'es', label: 'ES', name: 'Español' },
  { code: 'fr', label: 'FR', name: 'Français' },
  { code: 'it', label: 'IT', name: 'Italiano' },
  { code: 'pt', label: 'PT', name: 'Português' },
];
const LANG_KEY = 'ppl_lang';
const CODES = LANGS.map(l => l.code);

// Constantes que no se traducen. Cambiar la versión aquí la cambia en los cinco
// idiomas; las fechas se guardan en ISO y cada idioma las formatea a su manera.
const V = {
  version:    'v0.3',
  engine:     'Godot 4',
  chapter:    4,
  eaDate:     '2026-07-31',
  publicDate: '2026-08-14',
  patreon:    'https://www.patreon.com/c/WickedTalesInteractive',
  itch:       'https://wicked2509.itch.io/pirate-private-loot',
  studio:     'https://www.wickedtalesinteractive.com',
};

function langFromPath() {
  const seg = window.location.pathname.split('/').filter(Boolean)[0];
  return CODES.includes(seg) ? seg : null;
}

function langFromNavigator() {
  for (const tag of navigator.languages || [navigator.language || '']) {
    const base = String(tag).toLowerCase().split('-')[0];
    if (CODES.includes(base)) return base;
  }
  return null;
}

function detectLang() {
  const fromPath = langFromPath();
  if (fromPath) return fromPath;
  // ?lang= lo usan las páginas que pinta el servidor (/play, /game) para
  // devolver al visitante en el mismo idioma en el que se fue.
  const q = new URLSearchParams(window.location.search).get('lang');
  if (CODES.includes(q)) return q;
  try {
    const saved = localStorage.getItem(LANG_KEY);
    if (CODES.includes(saved)) return saved;
  } catch {}
  return langFromNavigator() || 'en';
}

// Ruta pública de un idioma: el inglés vive en la raíz, el resto bajo su prefijo.
const pathFor = (code) => (code === 'en' ? '/' : `/${code}/`);

// El idioma se guarda TAMBIÉN en una cookie porque /play y /game los pinta el
// servidor y localStorage no llega hasta allí: sin esto, quien entrara a /play
// desde un marcador o desde el launcher se la encontraba en inglés aunque
// tuviera el sitio en español.
function recordarIdioma(code) {
  try { localStorage.setItem(LANG_KEY, code); } catch {}
  document.cookie = `${LANG_KEY}=${code}; path=/; max-age=31536000; SameSite=Lax`;
}

const I18nContext = React.createContext(null);

function I18nProvider({ children }) {
  const [lang, setLangState] = React.useState(detectLang);
  const [dict, setDict] = React.useState(null);
  const [fallback, setFallback] = React.useState(null);

  React.useEffect(() => {
    let vivo = true;
    document.documentElement.lang = lang;
    // Se deja constancia en cada carga, no solo al cambiar de idioma: así el
    // servidor también sabe el idioma de quien nunca ha tocado el selector.
    recordarIdioma(lang);
    fetch(`/lang/${lang}.json`)
      .then(r => r.json())
      .then(d => {
        if (!vivo) return;
        setDict(d);
        // El título y la descripción también son texto traducible.
        if (d.meta?.title) document.title = d.meta.title;
        const desc = document.querySelector('meta[name="description"]');
        if (desc && d.meta?.description) desc.setAttribute('content', d.meta.description);
      })
      .catch(() => { if (vivo) setDict({}); });
    // El inglés se carga aparte como red de seguridad: si a una traducción le
    // falta una clave, sale en inglés en vez de salir la clave cruda.
    if (lang !== 'en') {
      fetch('/lang/en.json').then(r => r.json()).then(d => { if (vivo) setFallback(d); }).catch(() => {});
    }
    return () => { vivo = false; };
  }, [lang]);

  const setLang = React.useCallback((code) => {
    if (!CODES.includes(code) || code === lang) return;
    recordarIdioma(code);
    // Si estamos en una ruta con idioma, cambiamos de ruta para que el enlace
    // se pueda compartir ya traducido. Si no, basta con recomponer.
    const destino = pathFor(code) + window.location.hash;
    if (window.location.pathname !== pathFor(code)) window.location.href = destino;
    else setLangState(code);
  }, [lang]);

  const valor = React.useMemo(() => {
    const buscar = (fuente, ruta) => ruta.split('.').reduce((n, k) => (n == null ? undefined : n[k]), fuente);

    // Devuelve lo que haya en la clave: texto, lista u objeto. Interpola {var}
    // con V y con lo que se le pase.
    const t = (ruta, vars) => {
      let v = buscar(dict, ruta);
      if (v === undefined && fallback) v = buscar(fallback, ruta);
      if (v === undefined) return ruta;
      if (typeof v !== 'string') return v;
      return v.replace(/\{(\w+)\}/g, (_, k) => (vars?.[k] ?? V[k] ?? `{${k}}`));
    };

    const tl = (ruta) => { const v = t(ruta); return Array.isArray(v) ? v : []; };

    const fmtDate = (iso) => {
      const [y, m, d] = iso.split('-').map(Number);
      return new Intl.DateTimeFormat(lang, { day: 'numeric', month: 'long' }).format(new Date(y, m - 1, d));
    };

    return { lang, langs: LANGS, setLang, t, tl, fmtDate, V, listo: dict !== null };
  }, [lang, dict, fallback, setLang]);

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

const useI18n = () => React.useContext(I18nContext);

/* Selector de idioma — los mismos cinco chips que el launcher. */
function LangSwitch() {
  const { lang, langs, setLang } = useI18n();
  return (
    <div className="lang" role="group" aria-label="Language">
      {langs.map(l => (
        <button
          key={l.code}
          className={l.code === lang ? 'on' : ''}
          onClick={() => setLang(l.code)}
          aria-current={l.code === lang ? 'true' : undefined}
          title={l.name}
        >
          {l.label}
        </button>
      ))}
    </div>
  );
}

Object.assign(window, { I18nProvider, useI18n, LangSwitch, LANGS, V, pathFor });
