// SQSEO i18n layer (I18N plan Phase L1). Runtime dictionaries, no build step:
//   t("nav.dashboard")            -> the active locale's string
//   t("x.y", { n: 3 })            -> "{n}" placeholders substituted
// Fallback chain: active locale -> en -> the key itself (logged once in dev).
// Locales: '' /'en' (default), 'pl', 'de', 'nl', 'da'. Pseudo-locale 'xx'
// brackets every English string (⟦…⟧) so untranslated chrome is visible in QA.
// The user's choice lives in users.locale (PATCH /api/account { locale }) and
// rides in on /api/bootstrap; localStorage mirrors it for pre-boot paint.
(function init(){
if(!window.LTQ){ window.LTQ = {}; }
const React = window.React;
const LOCALES = ["en", "pl", "de", "nl", "da"];
let lang = "en";
let dict = {};   // active locale strings
let dictEn = {}; // fallback
const warned = new Set();

const bracket = (s) => "⟦" + s + "⟧"; // ⟦…⟧ pseudo-locale marker

async function fetchDict(l) {
  try {
    const r = await fetch("/locales/app." + l + ".json", { credentials: "same-origin" });
    if (!r.ok) return null;
    return await r.json();
  } catch (e) { return null; }
}

function t(key, params) {
  let s = dict[key];
  if (s === undefined) s = dictEn[key];
  if (s === undefined) {
    if (!warned.has(key)) { warned.add(key); try { console.warn("[i18n] missing key: " + key); } catch (e) {} }
    return key;
  }
  if (lang === "xx") s = bracket(s);
  if (params) for (const k of Object.keys(params)) s = s.split("{" + k + "}").join(String(params[k]));
  return s;
}

const intlLocale = () => (lang === "xx" || lang === "" ? "en" : lang);
const fmtNumber = (n, opts) => { try { return new Intl.NumberFormat(intlLocale(), opts).format(n); } catch (e) { return String(n); } };
const fmtDate = (d, opts) => { try { return new Intl.DateTimeFormat(intlLocale(), opts).format(typeof d === "string" ? new Date(d) : d); } catch (e) { return String(d); } };
// One decimal, locale separator: 3.1 -> "3,1" for pl/de/nl/da. The % variant
// keeps the product's tight suffix (no space) across locales.
const fmtDec1 = (v) => fmtNumber(Number(v) || 0, { minimumFractionDigits: 1, maximumFractionDigits: 1 });
const fmtPct1 = (v) => fmtDec1(v) + "%";

/** Resolve the locale (boot > localStorage > browser), load dictionaries. */
async function i18nInit() {
  const boot = window.LTQ.boot || {};
  let l = (boot.user && boot.user.locale) || "";
  if (!l) { try { l = localStorage.getItem("sqseo_locale") || ""; } catch (e) {} }
  // Shared cross-surface choice: the marketing site + server detector persist the
  // language in the `sqseo_locale` COOKIE, so a first-time app visitor who picked
  // Dutch on the site lands in a Dutch app.
  if (!l) { try { const m = /(?:^|; )sqseo_locale=([^;]+)/.exec(document.cookie || ""); if (m) { const c = decodeURIComponent(m[1]); if (LOCALES.includes(c)) l = c; } } catch (e) {} }
  if (!l) { const nav = (navigator.language || "en").slice(0, 2).toLowerCase(); if (LOCALES.includes(nav)) l = nav; }
  if (!l) l = "en";
  await applyLocale(l, { persist: false, reload: false });
}

async function applyLocale(l, opts) {
  const target = l === "" ? "en" : l;
  dictEn = (await fetchDict("en")) || dictEn || {};
  dict = target === "en" ? dictEn : target === "xx" ? dictEn : (await fetchDict(target)) || dictEn;
  lang = target;
  try { localStorage.setItem("sqseo_locale", target); } catch (e) {}
  // Mirror into the shared cookie so the marketing site + server detector agree
  // with the app's choice (site ignores app-only locales like `de`).
  try { if (target !== "xx") document.cookie = "sqseo_locale=" + target + "; Path=/; Max-Age=31536000; SameSite=Lax"; } catch (e) {}
  try { document.documentElement.lang = target === "xx" ? "en" : target; } catch (e) {}
  if (!opts || opts.persist !== false) {
    if (window.LTQ.api && LOCALES.includes(target)) await window.LTQ.api.patch("/api/account", { locale: target }).catch(() => {});
  }
  // re-render the shell (same channel project/workspace switches use)
  if (window.LTQ.reloadBoot && (!opts || opts.reload !== false)) await window.LTQ.reloadBoot();
}

// ---- country + language metadata (I18N L2) ----------------------------------
// The 5 platform languages, shown in their own language (native names never
// translate — a Pole looks for "Polski" whatever the current UI language).
const LOCALE_OPTIONS = [
  { id: "en", name: "English" },
  { id: "pl", name: "Polski" },
  { id: "de", name: "Deutsch" },
  { id: "nl", name: "Nederlands" },
  { id: "da", name: "Dansk" },
];

// ISO 3166-1 alpha-2. EU/EEA/UK/CH first (our market), then the rest of the
// world. Display names come from Intl.DisplayNames in the active UI language.
const EU_FIRST = ("AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE " +
  "NO IS LI CH GB").split(" ");
const REST = ("US CA MX BR AR CL CO PE UY EC VE BO PY CR PA GT DO PR AU NZ JP KR CN TW HK SG MY TH VN PH ID IN PK BD LK NP " +
  "AE SA QA KW BH OM IL TR JO LB EG MA TN DZ LY NG GH KE TZ UG ET ZA ZW ZM MZ AO SN CI CM RW MU " +
  "UA MD GE AM AZ BY RS BA MK AL ME XK RU KZ UZ KG TM TJ MN " +
  "AD MC SM VA GI FO GL AX JE GG IM MT " +
  "FJ PG NC PF WS TO VU SB TL BN KH LA MM MO AF IQ IR SY YE PS " +
  "CU JM TT BB BS BZ HT HN NI SV GY SR").split(" ");
const COUNTRY_CODES = [...new Set([...EU_FIRST, ...REST])];

const countryName = (code) => {
  try { return new Intl.DisplayNames([intlLocale()], { type: "region" }).of(code) || code; } catch (e) { return code; }
};
// Country -> suggested platform language. A suggestion the user can override.
const localeForCountry = (code) => ({ PL: "pl", DE: "de", AT: "de", NL: "nl", BE: "nl", DK: "da" })[code] || "en";

/** Searchable country dropdown (wizard Business step + Settings project card). */
function CountrySelect({ value, onChange, placeholder, autoFocus }) {
  const [open, setOpen] = React.useState(false);
  const [q, setQ] = React.useState("");
  const [sel, setSel] = React.useState(0);
  const rootRef = React.useRef(null);
  const norm = (s) => s.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
  const options = React.useMemo(() => {
    const named = COUNTRY_CODES.map((c, i) => ({ code: c, name: countryName(c), eu: i < EU_FIRST.length }));
    named.sort((a, b) => (a.eu === b.eu ? a.name.localeCompare(b.name, intlLocale()) : a.eu ? -1 : 1));
    const needle = norm(q.trim());
    return needle
      ? named.filter((o) => norm(o.name).includes(needle) || o.code.toLowerCase().startsWith(needle))
      : named;
  }, [q, lang, open]);
  React.useEffect(() => { setSel(0); }, [q, open]);
  // Keep the keyboard-highlighted option visible in the scrolling list.
  React.useEffect(() => {
    if (!open || !rootRef.current) return;
    const el = rootRef.current.querySelectorAll("[data-country-option]")[sel];
    if (el && el.scrollIntoView) el.scrollIntoView({ block: "nearest" });
  }, [sel, open]);
  React.useEffect(() => {
    const onDoc = (e) => { if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, []);
  const pick = (code) => { onChange(code); setOpen(false); setQ(""); };
  const shown = open ? q : value ? countryName(value) : "";
  return (
    <div ref={rootRef} data-country-select style={{ position: "relative" }}>
      <input
        value={shown}
        placeholder={value && !open ? countryName(value) : placeholder}
        autoFocus={autoFocus}
        onFocus={() => setOpen(true)}
        onChange={(e) => { setQ(e.target.value); if (!open) setOpen(true); }}
        onKeyDown={(e) => {
          if (!open) return;
          if (e.key === "ArrowDown") { e.preventDefault(); setSel((s) => Math.min(s + 1, options.length - 1)); }
          else if (e.key === "ArrowUp") { e.preventDefault(); setSel((s) => Math.max(s - 1, 0)); }
          else if (e.key === "Enter") { e.preventDefault(); if (options[sel]) pick(options[sel].code); }
          else if (e.key === "Escape") { setOpen(false); setQ(""); }
        }}
        style={{ width: "100%", minHeight: 42, padding: "10px 12px", borderRadius: 10, background: "var(--surface-card)",
          border: "1px solid var(--border-strong)", fontFamily: "var(--font-sans)", fontSize: 14, color: "var(--text-strong)", outline: "none" }}
      />
      <span style={{ position: "absolute", right: 11, top: "50%", transform: "translateY(-50%)", pointerEvents: "none", color: "var(--text-faint)", fontSize: 11, fontWeight: 700 }}>
        {value && !open ? value : "▾"}
      </span>
      {open && (
        <div className="lt-scroll" style={{ position: "absolute", zIndex: 60, top: "calc(100% + 4px)", left: 0, right: 0, maxHeight: 240,
          overflowY: "auto", background: "var(--paper)", border: "1px solid var(--border-strong)", borderRadius: 10, boxShadow: "var(--shadow-md)" }}>
          {options.length === 0 && <div style={{ padding: "10px 12px", fontSize: 13, color: "var(--text-faint)" }}>—</div>}
          {options.map((o, i) => (
            <button key={o.code} data-country-option={o.code} onMouseDown={(e) => { e.preventDefault(); pick(o.code); }} onMouseEnter={() => setSel(i)}
              style={{ display: "flex", width: "100%", alignItems: "center", gap: 8, padding: "8px 12px", border: "none", textAlign: "left",
                cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 13.5, color: "var(--text-strong)",
                background: i === sel ? "var(--ink-50)" : "transparent" }}>
              <span style={{ flex: 1 }}>{o.name}</span>
              <span style={{ fontSize: 11, fontWeight: 700, color: "var(--text-faint)", fontFamily: "var(--font-mono)" }}>{o.code}</span>
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

Object.assign(window.LTQ, {
  t,
  i18nInit,
  setLocale: (l) => applyLocale(l),
  getLocale: () => lang,
  fmtNumber,
  fmtDate,
  fmtDec1,
  fmtPct1,
  I18N_LOCALES: LOCALES,
  LOCALE_OPTIONS,
  COUNTRY_CODES,
  countryName,
  localeForCountry,
  CountrySelect,
});
})();
