/* global React, useLang, I18N_lookup, TypedHeadline */
const { useMemo, useState, useCallback, useEffect, useRef } = React;

// ============ Precios ============
// Hero, packs prearmados, calculadora del plan Basic, cómo funciona y bloque Enterprise.
// Textos en pricing.* (pricing_messages.py → i18n-messages.js). Los precios viven acá como
// números y se formatean con el locale del idioma activo.
// Formulario POST multipart → window.FORSVAR_CONTACT_FORM_ENDPOINT (/api/contact, contact-config.js).
// /api/contact sólo acepta nombre/email/asunto/msg: el resto del pedido viaja dentro de msg.

const MIN_MONTHLY = 490;
const CONTACT_EMAIL = "contacto@forsvar.io";
const LOCALES = { es: "es-UY", en: "en-US", pt: "pt-BR" };

// Módulos de Actividad digital y Transacciones (mismos precios por evento).
const EVENT_GROUPS = (prod) => [
  { g: "dev", items: [
    { id: "sdk", p: 0.0100, def: true },
    { id: "geo", p: 0.0045 },
    { id: "graph", p: 0.0021 }
  ] },
  { g: "risk", items: [
    { id: "tree", p: 0.0100, def: true },
    { id: "case", p: 0.0009 }
  ] },
  { g: "ai", items: [{ id: "ml", p: 0.0050 }] },
  { g: "rf", items: [{ id: "rf", p: 0.0010 }] },
  { g: "anom", items: [{ id: "anom", p: 0.0045, key: "pricing.mod." + prod + ".anom" }] }
];

// Precios USD por unidad: Onboarding, columna "1 - 999" de la tabla de pricing; Actividad
// digital y Transacciones, columna "10.000 - 49.999".
const PRODUCTS = [
  { key: "onb", dec: 2, max: 10000, step: 10, def: 900, modNs: "onb", free: 3,
    groups: [
      { g: "idv", items: [
        { id: "ocr", p: 0.30, def: true },
        { id: "live", p: 0.20, def: true },
        { id: "m11", p: 0.10, def: true },
        { id: "m1n", p: 0.20 },
        { id: "gov", p: 0.20 },
        { id: "wl", p: 0.15 }
      ] },
      { g: "scr", items: [
        { id: "aml", p: 0.05 },
        { id: "adv", p: 0.05 },
        { id: "email", p: 0.10 }
      ] },
      { g: "dev", items: [
        { id: "sdk", p: 0.10 },
        { id: "geo", p: 0.05 },
        { id: "graph", p: 0.05 }
      ] },
      { g: "risk", items: [
        { id: "mx", p: 0.10 },
        { id: "tree", p: 0.10 },
        { id: "case", p: 0.02 }
      ] },
      { g: "anom", items: [{ id: "anom", p: 0.10 }] }
    ] },
  { key: "dig", dec: 4, max: 50000, step: 500, def: 5000, modNs: "ev", free: 3, chips: 2,
    groups: EVENT_GROUPS("dig") },
  { key: "trx", dec: 4, max: 50000, step: 500, def: 10000, modNs: "ev", free: 4, chips: 3,
    groups: EVENT_GROUPS("trx") }
];
PRODUCTS.forEach((P) => {
  P.items = [].concat(...P.groups.map((g) => g.items));
  P.items.forEach((it) => { if (!it.key) it.key = "pricing.mod." + P.modNs + "." + it.id; });
});

// Packs prearmados: configuran servicios y módulos; el volumen sale de la regla de abajo.
const PACKS = {
  screening: { price: 0.05, unit: "onb", items: 4, mods: { onb: ["aml"] } },
  kyc: { price: 0.60, unit: "onb", items: 3, mods: { onb: ["ocr", "live", "m11"] } },
  compliance: { price: 0.70, unit: "onb", items: 3, mods: { onb: ["ocr", "live", "m11", "aml", "adv"] } },
  onb_full: { price: 1.87, unit: "onb", items: 4, mods: { onb: "all" } },
  dig_basic: { price: 0.021, unit: "dig", items: 4, mods: { dig: ["sdk", "tree", "case"] } },
  fraude: { price: 0.015, unit: "trx", items: 2, mods: { trx: ["tree", "ml"] } },
  trx_full: { price: 0.038, unit: "trx", items: 5, mods: { trx: "all" } },
  custom: { items: 4, mods: { onb: ["ocr", "live", "m11"], dig: ["sdk", "tree"], trx: ["sdk", "tree"] } }
};
const PACK_ORDER = ["screening", "kyc", "compliance", "onb_full", "dig_basic", "fraude", "trx_full", "custom"];

// Países del formulario (ISO 3166-1 alfa-2). El nombre lo pone Intl.DisplayNames en el idioma activo;
// Latinoamérica primero porque es el mercado principal.
const COUNTRIES_LATAM = ["AR", "BO", "BR", "CL", "CO", "CR", "CU", "DO", "EC", "GT", "HN", "MX", "NI", "PA", "PE", "PR", "PY", "SV", "UY", "VE"];
const COUNTRIES_REST = ("AD AE AF AG AI AL AM AO AQ AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BQ BS BT BV BW BY BZ " +
  "CA CC CD CF CG CH CI CK CM CN CV CW CX CY CZ DE DJ DK DM DZ EE EG EH ER ES ET FI FJ FK FM FO FR GA GB GD GE GF GG GH GI GL " +
  "GM GN GP GQ GR GS GU GW GY HK HM HR HT HU ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ LA LB " +
  "LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ MR MS MT MU MV MW MY MZ NA NC NE NF NG NL NO NP NR NU " +
  "NZ OM PF PG PH PK PL PM PN PS PT PW QA RE RO RS RU RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR SS ST SX SY SZ TC TD TF " +
  "TG TH TJ TK TL TM TN TO TR TT TV TW TZ UA UG UM US UZ VA VC VG VI VN VU WF WS XK YE YT ZA ZM ZW").split(" ");

function countryNamer(lang) {
  let dn = null;
  try { dn = new Intl.DisplayNames([LOCALES[lang] || LOCALES.es], { type: "region" }); } catch (_) { /* navegador sin DisplayNames */ }
  return (code) => { try { return (dn && dn.of(code)) || code; } catch (_) { return code; } };
}
function countryOptions(lang) {
  const name = countryNamer(lang);
  const loc = LOCALES[lang] || LOCALES.es;
  const sorted = (codes) => codes.map((c) => ({ c, n: name(c) })).sort((x, y) => x.n.localeCompare(y.n, loc));
  return { latam: sorted(COUNTRIES_LATAM), rest: sorted(COUNTRIES_REST) };
}

// Rangos del formulario Enterprise (umbrales numéricos; el texto sale de i18n).
const RANGES = {
  onb: [1000, 10000, 50000, 100000],
  dig: [10000, 50000, 200000, 1000000],
  trx: [50000, 200000, 500000, 1000000]
};

function initialCalc() {
  const s = {};
  PRODUCTS.forEach((P) => {
    s[P.key] = { on: true, mods: P.items.filter((it) => it.def).map((it) => it.id), v: P.def, text: String(P.def), over: false };
  });
  return s;
}

function unitPrice(P, mods) {
  const sum = P.items.filter((it) => mods.indexOf(it.id) > -1).reduce((a, it) => a + it.p, 0);
  return Math.round(sum * 100000) / 100000;
}

// Cálculo puro del pack: costo por servicio, total y ajuste al mínimo de la cuenta.
function computePricing(calc) {
  let raw = 0;
  const res = {};
  PRODUCTS.forEach((P) => {
    const c = calc[P.key];
    const u = unitPrice(P, c.mods);
    const active = c.on && u > 0;
    const cost = active ? u * c.v : 0;
    res[P.key] = { on: c.on, active, u, v: c.v, cost };
    raw += cost;
  });
  const actives = PRODUCTS.filter((P) => res[P.key].active);
  return {
    res,
    raw,
    total: Math.max(MIN_MONTHLY, raw),
    actives: actives.length,
    // Ajuste al mínimo en dólares enteros: con 489,97 no se muestra un "+ USD 0".
    adj: Math.round(Math.max(0, MIN_MONTHLY - raw)),
    below: actives.filter((P) => res[P.key].cost < MIN_MONTHLY).length
  };
}

// Volumen sugerido de un pack de un solo servicio: lo que entra en los USD 490 del plan Basic.
function suggestedVolume(P, mods) {
  const u = unitPrice(P, mods);
  return u > 0 ? Math.min(P.max, Math.max(1, Math.floor(MIN_MONTHLY / u + 1e-9))) : P.def;
}

// "**negrita**" → <b>. Evita meter HTML en los mensajes.
function rich(text) {
  return String(text).split("**").map((part, i) => (i % 2 ? <b key={i}>{part}</b> : part));
}
function fill(text, vars) {
  return String(text).replace(/\{(\w+)\}/g, (m, k) => (k in vars ? vars[k] : m));
}

function useFormat(lang) {
  return useMemo(() => {
    const loc = LOCALES[lang] || LOCALES.es;
    const int = (n) => Math.round(n).toLocaleString(loc);
    return {
      int,
      usd0: (n) => "USD " + int(n),
      usdU: (n, dec) => "USD " + n.toLocaleString(loc, { minimumFractionDigits: dec, maximumFractionDigits: dec }),
      usdP: (n) => "USD " + n.toLocaleString(loc, { minimumFractionDigits: 2, maximumFractionDigits: 4 })
    };
  }, [lang]);
}

// Monto que se anima entre valores (respeta prefers-reduced-motion).
function Amount({ value, format }) {
  const [shown, setShown] = useState(value);
  const from = useRef(value);
  useEffect(() => {
    const start = from.current;
    from.current = value;
    if (start === value || window.matchMedia("(prefers-reduced-motion: reduce)").matches) { setShown(value); return; }
    const t0 = performance.now();
    let raf;
    const step = (t) => {
      const k = Math.min(1, (t - t0) / 380);
      setShown(start + (value - start) * (1 - Math.pow(1 - k, 3)));
      if (k < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [value]);
  return <>{format(shown)}</>;
}

// Checkbox con estado "parcial" (seleccionar todo de un grupo o de un servicio).
function TriCheck({ checked, indeterminate, onChange, ariaLabel }) {
  const ref = useRef(null);
  useEffect(() => { if (ref.current) ref.current.indeterminate = indeterminate; }, [indeterminate]);
  return <input ref={ref} type="checkbox" checked={checked} onChange={onChange} aria-label={ariaLabel} />;
}

const Check = ({ stroke = "currentColor", w = 2.2 }) => (
  <svg viewBox="0 0 12 12" fill="none" stroke={stroke} strokeWidth={w} strokeLinecap="round" strokeLinejoin="round"><path d="M2.5 6.2l2.3 2.3 4.7-5" /></svg>
);
const BoxCheck = () => <span className="fp-box"><Check stroke="#fff" /></span>;
const Info = () => (
  <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"><circle cx="8" cy="8" r="6.5" /><path d="M8 7.2v4M8 4.9v.1" /></svg>
);
const ICONS = {
  onb: <svg viewBox="0 0 24 24" fill="none" stroke="#e0b145" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="14" rx="2.5" /><circle cx="9" cy="11" r="2.2" /><path d="M5.8 16c.6-1.6 1.8-2.4 3.2-2.4s2.6.8 3.2 2.4M14.5 10h4M14.5 13.5h3" /></svg>,
  dig: <svg viewBox="0 0 24 24" fill="none" stroke="#e0b145" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="6" y="2.5" width="12" height="19" rx="2.5" /><rect x="9" y="9" width="6" height="5" rx="1" /><path d="M10 9V7.6a2 2 0 014 0V9M11 18.5h2" /></svg>,
  trx: <svg viewBox="0 0 24 24" fill="none" stroke="#e0b145" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M4 8h13l-3-3M20 16H7l3 3" /><circle cx="19.5" cy="8" r=".6" fill="#e0b145" /><circle cx="4.5" cy="16" r=".6" fill="#e0b145" /></svg>
};
const FACT_ICONS = [
  <svg viewBox="0 0 24 24" fill="none" stroke="#e0b145" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="18" height="14" rx="2.5" /><circle cx="9" cy="11" r="2.2" /><path d="M5.8 16c.6-1.6 1.8-2.4 3.2-2.4s2.6.8 3.2 2.4M14.5 10h4M14.5 13.5h3" /></svg>,
  <svg viewBox="0 0 24 24" fill="none" stroke="#e0b145" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M4 8h13l-3-3M20 16H7l3 3" /></svg>,
  <svg viewBox="0 0 24 24" fill="none" stroke="#e0b145" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4.5" width="18" height="16" rx="2.5" /><path d="M3 9.5h18M8 2.5v4M16 2.5v4" /></svg>,
  <svg viewBox="0 0 24 24" fill="none" stroke="#e0b145" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3l7 3v5.5c0 4.3-2.9 7.9-7 9.5-4.1-1.6-7-5.2-7-9.5V6l7-3z" /><path d="M9 12l2.2 2.2L15.5 10" /></svg>
];

// --- Hero ---
function PricingHero({ fmt }) {
  const { t, lang } = useLang();
  const facts = [fmt.usdP(0.70), fmt.usdP(0.01), fmt.usd0(MIN_MONTHLY), fmt.usd0(0)];
  const segments = useMemo(() => [
    { type: "text", value: t("pricing.hero.h1a") + " " + t("pricing.hero.h1b") },
    { type: "underline", value: t("pricing.hero.h1hl") },
    { type: "text", value: t("pricing.hero.h1c") }
  ], [lang, t]);
  return (
    <section className="hero" id="top">
      <div className="container">
        <div className="hero-grid" style={{ gridTemplateColumns: "1fr" }}>
          <div className="hero-lower-left" style={{ maxWidth: 1100 }}>
            <span className="kicker"><span className="dot" />{t("pricing.hero.kicker")}</span>
            <h1 className="hero-headline" style={{ marginTop: 22 }}>
              <TypedHeadline key={lang} segments={segments} />
            </h1>
            <p className="hero-sub" style={{ maxWidth: "62ch", marginTop: 36 }}>{t("pricing.hero.lead")}</p>
          </div>
        </div>
        <div className="fp-facts">
          {facts.map((num, i) =>
            <div className="fp-fact" key={i}>
              <span className="ic">{FACT_ICONS[i]}</span>
              <div>
                <span className="pre">{t("pricing.hero.f" + i + ".pre")}</span>
                <div className="num">{num}</div>
                <div className="lbl">{t("pricing.hero.f" + i + ".lbl")}</div>
              </div>
            </div>
          )}
        </div>
      </div>
    </section>
  );
}

// --- Packs prearmados ---
function PricingPacks({ fmt, onPack, onEnterprise }) {
  const { t } = useLang();
  const per = { onb: "pricing.prod.onb.unit", dig: "pricing.prod.dig.unit", trx: "pricing.prod.trx.unit" };
  const li = (id, n) => Array.from({ length: n }, (_, i) =>
    <li key={i}><Check /><span>{t("pricing.pack." + id + ".i" + i)}</span></li>
  );
  return (
    <section className="fp-packs" id="fp-packs">
      <div className="container">
        <div className="fp-packs-head">
          <span className="kicker"><span className="dot" />{t("pricing.packs.kicker")}</span>
          <h2>{t("pricing.packs.title")}</h2>
        </div>
        <div className="fp-packs-grid">
          {PACK_ORDER.map((id) => {
            const pk = PACKS[id];
            return (
              <a className={"fp-pack" + (id === "custom" ? " is-gray" : "")} href="#fp-calc" key={id} onClick={() => onPack(id)}>
                <span className="pk">{t("pricing.pack." + id + ".k")}</span>
                <span className="pn">{t("pricing.pack." + id + ".n")}</span>
                {id === "custom"
                  ? <span className="pp"><small>{t("pricing.packs.from")}</small>{fmt.usd0(MIN_MONTHLY)}<small>{t("pricing.packs.min_month")}</small></span>
                  : <span className="pp">{fmt.usdP(pk.price)}<small> / {t(per[pk.unit])}</small></span>}
                <ul>{li(id, pk.items)}</ul>
                <span className="pc">{t("pricing.packs.cta")} <span className="arrow" aria-hidden="true">→</span></span>
              </a>
            );
          })}
          <a className="fp-pack is-ent is-gold" href="#fp-enterprise" onClick={onEnterprise}>
            <span className="pk">{t("pricing.pack.enterprise.k")}</span>
            <span className="pn">{t("pricing.pack.enterprise.n")}</span>
            <span className="pp">{t("pricing.packs.custom_price")}</span>
            <ul>{li("enterprise", 4)}</ul>
            <span className="pc">{t("pricing.packs.cta_ent")} <span className="arrow" aria-hidden="true">→</span></span>
          </a>
        </div>
      </div>
    </section>
  );
}

// --- Card de un servicio de la calculadora ---
function ServiceCard({ P, c, r, fmt, setCalc }) {
  const { t } = useLang();
  const [open, setOpen] = useState(false);
  const title = t("pricing.prod." + P.key + ".title");
  const units = t("pricing.prod." + P.key + ".units");
  const update = (patch) => setCalc((s) => ({ ...s, [P.key]: { ...s[P.key], ...patch } }));
  const setMods = (ids, checked) => setCalc((s) => {
    const cur = s[P.key].mods.filter((id) => ids.indexOf(id) < 0);
    return { ...s, [P.key]: { ...s[P.key], mods: checked ? cur.concat(ids) : cur } };
  });
  const setVolume = (v, text, over) => update({ v, text: text == null ? String(v) : text, over: !!over });
  const onNumber = (e) => {
    const text = e.target.value;
    const n = parseInt(text, 10);
    if (isNaN(n)) { update({ text }); return; }
    setVolume(Math.min(P.max, Math.max(1, n)), text, n > P.max);
  };
  const onNumberBlur = () => setVolume(c.v, null, false);
  const allIds = P.items.map((it) => it.id);
  const nSel = c.mods.length;
  const scale = [0, 0.25, 0.5, 0.75, 1].map((k) => fmt.int(k === 0 ? 1 : P.max * k));
  const pct = (c.v / P.max) * 100;
  const showMin = r.active && r.cost < MIN_MONTHLY;
  const showCap = c.on && (c.v >= P.max || c.over);

  return (
    <article className={"fp-card" + (c.on ? "" : " is-off")} id={"fp-card-" + P.key}>
      <header className="fp-card-head">
        <div className="fp-ico">{ICONS[P.key]}</div>
        <div>
          <span className="kicker">{t("pricing.prod." + P.key + ".kicker")}</span>
          <h2>{title}</h2>
          <p className="desc">{t("pricing.prod." + P.key + ".desc")}</p>
          {P.chips ? <div className="fp-chips">{Array.from({ length: P.chips }, (_, i) => <span key={i}>{t("pricing.prod." + P.key + ".chip" + i)}</span>)}</div> : null}
        </div>
        <label className="fp-switch">
          <input type="checkbox" checked={c.on} onChange={(e) => update({ on: e.target.checked })} aria-label={fill(t("pricing.card.include"), { title })} />
          <span className="track" />
          <span className="lbl-on">{t("pricing.card.on")}</span><span className="lbl-off">{t("pricing.card.off")}</span>
        </label>
      </header>
      <div className="fp-stats">
        <div className="fp-stat">
          <span className="k">{t("pricing.prod." + P.key + ".unit_label")}</span>
          <span className="v">{fmt.usdU(c.on ? r.u : 0, P.dec)}</span>
          <span className="s">{t("pricing.card.unit_sub")}</span>
        </div>
        <div className="fp-stat">
          <span className="k">{t("pricing.card.month")}</span>
          <span className="v"><Amount value={c.on && r.active ? Math.max(MIN_MONTHLY, r.cost) : 0} format={fmt.usd0} /><small>{t("pricing.card.per_month")}</small></span>
          <span className="s">{fill(t("pricing.card.for_vol"), { n: fmt.int(c.v), units: c.v === 1 ? t("pricing.prod." + P.key + ".unit") : units })}</span>
        </div>
      </div>
      {showMin ? <div className="fp-note min show"><Info /><span>{rich(t("pricing.card.min_note"))}</span></div> : null}
      <div className="fp-body">
        <div className="fp-vol">
          <label className="t" htmlFor={P.key + "-num"}>
            <span>{t("pricing.prod." + P.key + ".vol")}</span>
            <span className="fp-numbox">
              <input type="number" id={P.key + "-num"} min="1" max={P.max} step="1" inputMode="numeric" value={c.text} onChange={onNumber} onBlur={onNumberBlur} />
              <span>{units}</span>
            </span>
          </label>
          <input className="fp-range" type="range" min="0" max={P.max} step={P.step} value={c.v} style={{ "--p": pct + "%" }}
            aria-label={fill(t("pricing.card.range_aria"), { units })}
            onChange={(e) => setVolume(Math.max(1, +e.target.value))} />
          <div className="fp-scale">{scale.map((s, i) => <span key={i}>{s}</span>)}</div>
          {showCap ?
            <div className="fp-cap show">
              <span>{rich(fill(t("pricing.card.cap"), { n: fmt.int(P.max), units }))}</span>
              <a href="#fp-enterprise">{t("pricing.card.cap_link")} →</a>
            </div> : null}
        </div>
        <button type="button" className="fp-expand" aria-expanded={open} aria-controls={"fp-more-" + P.key} onClick={() => setOpen(!open)}>
          <span><span className="lbl">{t(open ? "pricing.card.collapse" : "pricing.card.expand")}</span><span className="cnt">{fill(t("pricing.card.count"), { n: nSel, total: allIds.length })}</span></span>
          <span className="chev"><svg viewBox="0 0 12 12" fill="none" stroke="#e0b145" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 4.5l3 3 3-3" /></svg></span>
        </button>
        <div className={"fp-more" + (open ? " open" : "")} id={"fp-more-" + P.key}>
          <div>
            <label className="fp-all">
              <TriCheck checked={nSel === allIds.length} indeterminate={nSel > 0 && nSel < allIds.length} onChange={(e) => setMods(allIds, e.target.checked)} />
              <BoxCheck />{fill(t("pricing.card.all"), { title })}<span className="hint">{t("pricing.card.all_hint")}</span>
            </label>
            <div className="fp-mods">
              {P.groups.map((g) => {
                const ids = g.items.map((it) => it.id);
                const n = ids.filter((id) => c.mods.indexOf(id) > -1).length;
                const gName = t("pricing.grp." + g.g);
                return (
                  <div className="fp-group" key={g.g}>
                    <h4>
                      <span>{gName}</span>
                      {ids.length > 1 ?
                        <label className="fp-gall">
                          <TriCheck checked={n === ids.length} indeterminate={n > 0 && n < ids.length} onChange={(e) => setMods(ids, e.target.checked)}
                            ariaLabel={fill(t("pricing.card.group_all_aria"), { group: gName })} />
                          <BoxCheck />{t("pricing.card.group_all")}
                        </label> : null}
                    </h4>
                    {g.items.map((it) => {
                      const uid = P.key + "-" + it.id;
                      return (
                        <label className="fp-opt" htmlFor={uid} key={it.id}>
                          <input type="checkbox" id={uid} checked={c.mods.indexOf(it.id) > -1} onChange={(e) => setMods([it.id], e.target.checked)} />
                          <BoxCheck />
                          <span className="name">{t(it.key)}{it.def ? <span className="base">{t("pricing.card.base")}</span> : null}</span>
                          <span className="pr">+{fmt.usdU(it.p, P.dec).replace("USD ", "")}</span>
                        </label>
                      );
                    })}
                  </div>
                );
              })}
            </div>
            <div className="fp-free">
              <h4>{t("pricing.prod." + P.key + ".free.t")}</h4>
              <ul>
                {Array.from({ length: P.free }, (_, i) =>
                  <li key={i}><i><Check stroke="#fff" w={2.4} /></i><span>{t("pricing.prod." + P.key + ".free.i" + i)}</span></li>
                )}
              </ul>
            </div>
          </div>
        </div>
      </div>
    </article>
  );
}

// --- Resumen del pack ---
function PricingSummary({ pricing, fmt, onWant, summaryRef }) {
  const { t } = useLang();
  const { res, raw, total, actives, below } = pricing;
  const maxCost = Math.max(1, ...PRODUCTS.map((P) => res[P.key].cost));
  let flag = null;
  if (raw < MIN_MONTHLY) flag = t(actives > 1 ? "pricing.sum.flag_multi" : "pricing.sum.flag_single");
  else if (below) flag = t("pricing.sum.flag_below");
  return (
    <aside className="fp-summary" id="fp-summary" aria-live="polite" ref={summaryRef}>
      <div className="fp-plan"><span className="kicker"><span className="dot" />{t("pricing.sum.kicker")}</span></div>
      <div className="big"><Amount value={total} format={fmt.usd0} /></div>
      <p className="per">{t("pricing.sum.per")}</p>
      <div className="fp-perks">
        <span><Check />{t("pricing.sum.perk0")}</span>
        <span><Check />{t("pricing.sum.perk1")}</span>
      </div>
      <div className="fp-rows">
        {PRODUCTS.map((P) => {
          const r = res[P.key];
          return (
            <div className={"fp-row" + (r.active ? "" : " off")} key={P.key}>
              <div className="top"><span>{t("pricing.prod." + P.key + ".title")}</span><b>{r.active ? fmt.usd0(r.cost) : "USD 0"}</b></div>
              <div className="d">{r.active ? fmt.int(r.v) + " " + t("pricing.prod." + P.key + ".units") + " × " + fmt.usdU(r.u, P.dec) : t(r.on ? "pricing.sum.nomods" : "pricing.sum.off")}</div>
              <div className="bar"><i style={{ width: (r.active ? Math.max(4, (r.cost / maxCost) * 100) : 0) + "%" }} /></div>
            </div>
          );
        })}
        <div className="fp-row free"><div className="top"><span>{t("pricing.sum.free")}</span><b>{t("pricing.sum.free_v")}</b></div></div>
        {pricing.adj > 0 ?
          <div className="fp-row adj"><div className="top"><span>{t("pricing.sum.adj")}</span><b>+ {fmt.usd0(pricing.adj)}</b></div></div> : null}
      </div>
      {flag ? <div className="fp-flag show">{rich(flag)}</div> : null}
      <div className="fp-cta">
        <a className="fp-btn fp-btn-accent" href="#fp-form" onClick={onWant}>{t("pricing.sum.cta")} <span className="arrow" aria-hidden="true">→</span></a>
      </div>
      <p className="fp-pay">
        <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><rect x="1.5" y="3.5" width="13" height="9" rx="1.5" /><path d="M1.5 6.5h13M4 10h3" /></svg>
        {t("pricing.sum.pay")}
      </p>
    </aside>
  );
}

// --- Cómo funciona ---
function PricingHow() {
  const { t } = useLang();
  return (
    <section className="fp-how">
      <div className="container">
        <div className="fp-how-head">
          <div>
            <span className="kicker"><span className="dot" />{t("pricing.how.kicker")}</span>
            <h2>{t("pricing.how.title")}</h2>
          </div>
          <p className="lead">{t("pricing.how.lead")}</p>
        </div>
        <div className="fp-steps">
          {[0, 1, 2, 3].map((i) =>
            <div className={"fp-stepc" + (i === 2 ? " hl" : "")} key={i}>
              <div className="n">{"0" + (i + 1)}</div>
              <div className="box"><h3>{t("pricing.how.s" + i + ".t")}</h3><p>{t("pricing.how.s" + i + ".p")}</p></div>
            </div>
          )}
        </div>
      </div>
    </section>
  );
}

// --- Enterprise + formulario Basic / Enterprise ---
function PricingEnterprise({ pricing, fmt, plan, setPlan, prefill, onEnterprise, loadedPack }) {
  const { t, lang } = useLang();
  const [sent, setSent] = useState("");
  const [submitting, setSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState("");
  const basic = plan === "basic";
  const msgRef = useRef(null);
  const countries = useMemo(() => countryOptions(lang), [lang]);

  // "Solicitar cotización" / "Hablar con ventas" precargan el mensaje si está vacío.
  useEffect(() => {
    if (prefill && msgRef.current && !msgRef.current.value) msgRef.current.value = t("pricing.form.ent_prefill");
  }, [prefill]);

  const setFieldMessage = useCallback((ev) => {
    const el = ev.target;
    if (el.validity.valueMissing) el.setCustomValidity(t("pricing.form.val_missing"));
    else if (el.type === "email" && el.validity.typeMismatch) el.setCustomValidity(t("pricing.form.val_email"));
    else el.setCustomValidity("");
  }, [t]);
  const clearFieldMessage = useCallback((ev) => { ev.target.setCustomValidity(""); }, []);

  const rangeOptions = (key) => {
    const th = RANGES[key];
    const opts = [t("pricing.form.na"), fill(t("pricing.form.upto"), { n: fmt.int(th[0]) })];
    for (let i = 1; i < th.length; i++) opts.push(fmt.int(th[i - 1]) + " – " + fmt.int(th[i]));
    opts.push(fill(t("pricing.form.more"), { n: fmt.int(th[th.length - 1]) }));
    return opts;
  };

  // El mensaje a ventas va siempre en español, con el pack de la calculadora (no se muestra en el formulario).
  const buildMessage = (d) => {
    const es = (k) => I18N_lookup("es", k);
    const esFmt = (n, dec) => "USD " + n.toLocaleString(LOCALES.es, { minimumFractionDigits: dec, maximumFractionDigits: dec });
    const esInt = (n) => Math.round(n).toLocaleString(LOCALES.es);
    const pack = (loadedPack ? "Pack de partida: " + es("pricing.pack." + loadedPack + ".n") + "\n" : "") +
      PRODUCTS.map((P) => {
        const r = pricing.res[P.key];
        if (!r.active) return es("pricing.prod." + P.key + ".title") + ": no incluido";
        const mods = P.items.filter((it) => pricing.mods[P.key].indexOf(it.id) > -1)
          .map((it) => "  - " + es(it.key) + " (" + esFmt(it.p, P.dec) + ")").join("\n");
        return es("pricing.prod." + P.key + ".title") + ": " + esInt(r.v) + " " + es("pricing.prod." + P.key + ".units") +
          " × " + esFmt(r.u, P.dec) + " = USD " + esInt(r.cost) + "\n" + mods;
      }).join("\n") +
      (pricing.adj > 0 ? "\nAjuste al mínimo mensual: + USD " + esInt(pricing.adj) : "") +
      "\nTotal estimado: USD " + esInt(pricing.total) + "/mes";
    return "Plan: " + (basic ? "Basic" : "Enterprise") +
      "\nEmpresa: " + d.get("empresa") + "\nPaís: " + (d.get("pais") ? countryNamer("es")(d.get("pais")) : "-") + "\nIdioma de la página: " + lang +
      (basic ? "" : "\nOnboardings/mes: " + d.get("onboardings") + "\nActividad digital/mes: " + d.get("actividad_digital") + "\nTransacciones/mes: " + d.get("transacciones")) +
      "\n\nMensaje:\n" + (d.get("mensaje") || "(sin mensaje)") +
      "\n\n--- Pack armado en la calculadora ---\n" + pack;
  };

  const onSubmit = async (e) => {
    e.preventDefault();
    setSubmitError("");
    const form = e.currentTarget;
    const d = new FormData(form);
    const body = new FormData();
    body.append("nombre", d.get("nombre"));
    body.append("email", d.get("email"));
    body.append("asunto", "Precios · " + (basic ? "Plan Basic" : "Enterprise") + " · " + d.get("empresa"));
    body.append("msg", buildMessage(d));
    const url = window.FORSVAR_CONTACT_FORM_ENDPOINT || "/api/contact";
    setSubmitting(true);
    try {
      const res = await fetch(url, { method: "POST", headers: { Accept: "application/json" }, body });
      let data = null;
      try { data = await res.json(); } catch (_) { /* ignore */ }
      if (!res.ok || !data || !data.ok) throw new Error(data && data.message ? String(data.message) : "");
      setSent(String(d.get("email")));
      form.reset();
    } catch (err) {
      const reason = err && err.message ? err.message : t("pricing.form.err_net");
      setSubmitError(fill(t("pricing.form.err"), { reason }));
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <section className="fp-ent" id="fp-enterprise">
      <div className="container">
        <div className="fp-ent-grid">
          <div className="fp-ent-info">
            <span className="fp-ent-badge">{t("pricing.ent.badge")}</span>
            <div className="fp-ent-price">{t("pricing.ent.price")}</div>
            <p className="fp-ent-sub">{t("pricing.ent.sub_a")}<b>{t("pricing.ent.sub_b")}</b></p>
            <ul>
              {[0, 1, 2, 3, 4, 5].map((i) =>
                <li key={i}><i><svg viewBox="0 0 16 16" fill="none" stroke="#1a1a1a" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 8.5l3 3 7-7" /></svg></i><span>{t("pricing.ent.i" + i)}</span></li>
              )}
            </ul>
            <a className="fp-btn fp-btn-accent" href="#fp-form" onClick={onEnterprise}>{t("pricing.ent.cta")} <span className="arrow" aria-hidden="true">→</span></a>
          </div>

          <form className="fp-form" id="fp-form" onSubmit={onSubmit}>
            <div className="fp-plans" role="radiogroup" aria-label={t("pricing.form.plan_aria")}>
              <input type="radio" name="plan" id="f-plan-basic" value="basic" checked={basic} onChange={() => setPlan("basic")} />
              <label htmlFor="f-plan-basic">{t("pricing.form.plan_basic")}</label>
              <input type="radio" name="plan" id="f-plan-ent" value="enterprise" checked={!basic} onChange={() => setPlan("enterprise")} />
              <label htmlFor="f-plan-ent">{t("pricing.form.plan_ent")}</label>
            </div>
            <h3>{t(basic ? "pricing.form.title_basic" : "pricing.form.title_ent")}</h3>
            <p className="sub">{t(basic ? "pricing.form.sub_basic" : "pricing.form.sub_ent")}</p>
            {basic ?
              <div className="fp-fpack">
                <div className="head">
                  <span className="k">{t("pricing.form.pack_k")}</span>
                  {loadedPack ? <span className="from">{fill(t("pricing.form.pack_from"), { name: t("pricing.pack." + loadedPack + ".n") })}</span> : null}
                </div>
                <ul>
                  {PRODUCTS.map((P) => {
                    const r = pricing.res[P.key];
                    const mods = P.items.filter((it) => pricing.mods[P.key].indexOf(it.id) > -1);
                    return (
                      <li key={P.key} className={r.active ? "" : "off"}>
                        <div className="row">
                          <span>{t("pricing.prod." + P.key + ".title")}{r.active ? " · " + fmt.int(r.v) + " " + t("pricing.prod." + P.key + ".units") : ""}</span>
                          <b>{r.active ? fmt.usd0(r.cost) : t("pricing.form.pack_off")}</b>
                        </div>
                        {r.active ?
                          <details>
                            <summary>{mods.length === 1 ? t("pricing.form.mods1") : fill(t("pricing.form.mods"), { n: mods.length })}</summary>
                            <ul>{mods.map((it) => <li key={it.id}>{t(it.key)}</li>)}</ul>
                          </details> : null}
                      </li>
                    );
                  })}
                  {pricing.adj > 0 ?
                    <li><div className="row"><span>{t("pricing.sum.adj")}</span><b>+ {fmt.usd0(pricing.adj)}</b></div></li> : null}
                </ul>
                <div className="tot"><span>{t("pricing.form.pack_total")}</span><span>{fmt.usd0(pricing.total)}{t("pricing.card.per_month")}</span></div>
                <a href="#fp-calc">{t("pricing.form.pack_edit")}</a>
              </div> : null}
            {submitError ? <p className="ok err show" role="alert">{submitError}</p> : null}
            <div className="fp-fields">
              <div className="fp-field"><label htmlFor="f-name">{t("pricing.form.name")}</label><input id="f-name" name="nombre" required autoComplete="name" maxLength={200} disabled={submitting} onInvalid={setFieldMessage} onInput={clearFieldMessage} /></div>
              <div className="fp-field"><label htmlFor="f-email">{t("pricing.form.email")}</label><input id="f-email" name="email" type="email" required autoComplete="email" maxLength={320} disabled={submitting} onInvalid={setFieldMessage} onInput={clearFieldMessage} /></div>
              <div className="fp-field"><label htmlFor="f-company">{t("pricing.form.company")}</label><input id="f-company" name="empresa" required autoComplete="organization" maxLength={200} disabled={submitting} onInvalid={setFieldMessage} onInput={clearFieldMessage} /></div>
              <div className="fp-field"><label htmlFor="f-country">{t("pricing.form.country")}</label>
                <select id="f-country" name="pais" autoComplete="country" defaultValue="" disabled={submitting}>
                  <option value="">{t("pricing.form.country_ph")}</option>
                  <optgroup label={t("pricing.form.country_latam")}>{countries.latam.map((o) => <option key={o.c} value={o.c}>{o.n}</option>)}</optgroup>
                  <optgroup label={t("pricing.form.country_rest")}>{countries.rest.map((o) => <option key={o.c} value={o.c}>{o.n}</option>)}</optgroup>
                </select></div>
              {basic ? null :
                <>
                  <div className="fp-field full"><label htmlFor="f-onb">{t("pricing.form.onb")}</label>
                    <select id="f-onb" name="onboardings" disabled={submitting}>{rangeOptions("onb").map((o) => <option key={o}>{o}</option>)}</select></div>
                  <div className="fp-field"><label htmlFor="f-dig">{t("pricing.form.dig")}</label>
                    <select id="f-dig" name="actividad_digital" disabled={submitting}>{rangeOptions("dig").map((o) => <option key={o}>{o}</option>)}</select></div>
                  <div className="fp-field"><label htmlFor="f-trx">{t("pricing.form.trx")}</label>
                    <select id="f-trx" name="transacciones" disabled={submitting}>{rangeOptions("trx").map((o) => <option key={o}>{o}</option>)}</select></div>
                </>}
              <div className="fp-field full"><label htmlFor="f-msg">{t("pricing.form.msg")}</label>
                <textarea id="f-msg" name="mensaje" ref={msgRef} maxLength={2000} placeholder={t("pricing.form.msg_ph")} disabled={submitting} /></div>
            </div>
            <div className="actions">
              <button className="fp-btn fp-btn-ink" type="submit" disabled={submitting}>
                {t(submitting ? "pricing.form.sending" : "pricing.form.submit")} <span className="arrow" aria-hidden="true">→</span>
              </button>
              {basic ? null : <span className="legal">{t("pricing.form.legal")}</span>}
            </div>
            {sent ? <p className="ok show" role="status">{fill(t("pricing.form.ok"), { email: sent })}</p> : null}
          </form>
        </div>
        <p className="fp-foot-note">{t("pricing.foot")}</p>
      </div>
    </section>
  );
}

// --- Página ---
function PricingPage() {
  const { t, lang } = useLang();
  const fmt = useFormat(lang);
  const [calc, setCalc] = useState(initialCalc);
  const [loadedPack, setLoadedPack] = useState("");
  const [plan, setPlan] = useState("enterprise");
  const [prefill, setPrefill] = useState(0);
  const [mbarShow, setMbarShow] = useState(false);
  const cardsRef = useRef(null);
  const summaryRef = useRef(null);

  const pricing = useMemo(() => {
    const p = computePricing(calc);
    p.mods = {};
    PRODUCTS.forEach((P) => { p.mods[P.key] = calc[P.key].mods; });
    return p;
  }, [calc]);

  const applyPack = (id) => {
    const pk = PACKS[id];
    const next = {};
    PRODUCTS.forEach((P) => {
      const want = pk.mods[P.key];
      const mods = want === "all" ? P.items.map((it) => it.id) : (want || []).slice();
      const on = !!want;
      const v = id === "custom" || !on ? P.def : suggestedVolume(P, mods);
      next[P.key] = { on, mods, v, text: String(v), over: false };
    });
    setCalc(next);
    setLoadedPack(id);
  };
  const toEnterprise = () => {
    setPlan("enterprise");
    setPrefill((n) => n + 1);
  };

  // Barra fija en mobile: visible mientras la calculadora está en pantalla y el resumen no.
  useEffect(() => {
    if (!("IntersectionObserver" in window) || !cardsRef.current || !summaryRef.current) return undefined;
    let calcIn = false, sumIn = false;
    const upd = () => setMbarShow(calcIn && !sumIn);
    const a = new IntersectionObserver((e) => { calcIn = e[0].isIntersecting; upd(); }, { threshold: 0 });
    const b = new IntersectionObserver((e) => { sumIn = e[0].isIntersecting; upd(); }, { threshold: 0.15 });
    a.observe(cardsRef.current);
    b.observe(summaryRef.current);
    return () => { a.disconnect(); b.disconnect(); };
  }, []);

  return (
    <div className="fp" id="pricing">
      <PricingHero fmt={fmt} />
      <PricingPacks fmt={fmt} onPack={applyPack} onEnterprise={toEnterprise} />
      <section className="fp-calcs" id="fp-calc">
        <div className="container">
          <div className="fp-layout">
            <div>
              <h2 className="fp-calc-title">{t("pricing.calc.title")}</h2>
              <p className="fp-step">{t("pricing.calc.lead")}</p>
              {loadedPack ? <p className="fp-loaded">{rich(fill(t("pricing.calc.loaded"), { name: t("pricing.pack." + loadedPack + ".n") }))}</p> : null}
              <div className="fp-cards" ref={cardsRef}>
                {PRODUCTS.map((P) =>
                  <ServiceCard key={P.key} P={P} c={calc[P.key]} r={pricing.res[P.key]} fmt={fmt} setCalc={setCalc} />
                )}
              </div>
            </div>
            <PricingSummary pricing={pricing} fmt={fmt} onWant={() => setPlan("basic")} summaryRef={summaryRef} />
          </div>
        </div>
      </section>
      <PricingHow />
      <PricingEnterprise pricing={pricing} fmt={fmt} plan={plan} setPlan={setPlan} prefill={prefill} onEnterprise={toEnterprise} loadedPack={loadedPack} />
      <div className={"fp-mbar" + (mbarShow ? " show" : "")} aria-hidden={!mbarShow}>
        <div><div className="k">{t("pricing.mbar.k")}</div><div className="v"><Amount value={pricing.total} format={fmt.usd0} /></div></div>
        <a href="#fp-summary" tabIndex={mbarShow ? 0 : -1}>{t("pricing.mbar.cta")}</a>
      </div>
    </div>
  );
}

window.PricingPage = PricingPage;
