/* listo.jsx — pantalla de cierre (#listo).

   Lo que el cliente ve cuando termina la entrevista: la felicitación, SU PUESTO
   en la lista de espera y en cuántos días estimamos tener su web.

   Los dos números los calcula el dashboard (migración 0059) y viajan de vuelta
   en la respuesta de /api/intake/complete, que `intake.jsx` guarda en
   localStorage antes de navegar aquí. Por eso esta pantalla LEE y no pide nada:
   una ruta pública para consultar puestos se podría sondear con ids ajenos.

   Sin número —entrega fallida, red caída, o alguien que entra a #listo de
   frente— la pantalla degrada a una versión sin cifras. Nunca inventa un puesto. */

function ListoPage({ navigate }) {
  const { t } = useT();
  const l = t.listo;
  const portalUrl = (window.AF_ENV && window.AF_ENV.PORTAL_URL) || "";

  // El resultado de la finalización se lee UNA vez: es un dato ya cerrado y
  // releerlo en cada render no lo haría más verdadero.
  const [finish] = useState(() => window.HovexAPI.loadFinish());
  const queue = finish && finish.queue ? finish.queue : null;

  // Vuelta de Stripe: ?checkout=paid | cancelled (lo pone la propia pasarela).
  // 🔴 Esto SOLO cambia lo que se le dice al cliente. Quien de verdad lo mueve
  // de cola es el webhook firmado que Stripe manda al dashboard: este parámetro
  // se puede escribir a mano en la barra de direcciones.
  const [outcome] = useState(() => {
    try { return new URLSearchParams(window.location.search).get("checkout") || ""; }
    catch (_e) { return ""; }
  });

  const [paying, setPaying] = useState(false);
  const [payError, setPayError] = useState("");
  const checkoutToken = finish && finish.checkout_token ? finish.checkout_token : "";
  // El adelanto solo se ofrece a quien está en la cola GRATIS y tiene token. Un
  // cliente que ya pagó no puede volver a pagar lo mismo.
  const canUpgrade =
    Boolean(checkoutToken) && queue && queue.tier !== "paid" && outcome !== "paid";

  const startCheckout = async () => {
    if (paying) return;
    setPaying(true);
    setPayError("");
    try {
      const res = await fetch("/api/queue-checkout", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ checkout_token: checkoutToken }),
      });
      const data = await res.json().catch(() => null);
      if (!res.ok || !data || !data.url) throw new Error("checkout_failed");
      // Se sale de la SPA hacia Stripe. No se limpia nada: si el cliente vuelve
      // con «cancelar», su puesto y su token siguen donde estaban.
      window.location.assign(data.url);
    } catch (_err) {
      setPayError(l.upError);
      setPaying(false);
    }
  };

  // Conversión: CompleteRegistration (pixel + CAPI, deduplicado dentro de
  // afTrack). Una sola vez por montaje — el servidor ya dispara su mitad.
  const fired = useRef(false);
  useEffect(() => {
    if (fired.current) return;
    fired.current = true;
    if (window.afTrack) {
      window.afTrack.completeRegistration({ form: "hovex-express" }, {});
    }
  }, []);

  const days = queue ? Number(queue.eta_days) : 0;
  const dayWord = days === 1 ? l.etaDay : l.etaDays;

  return (
    <section className="getstarted-section">
      <div className="shell lst-shell">
        <Reveal>
          <div className="success-mark">
            <svg viewBox="0 0 64 64" width="64" height="64" aria-hidden="true">
              <circle cx="32" cy="32" r="30" fill="none" stroke="currentColor" strokeWidth="2" opacity="0.3" />
              <path d="M18 33 l10 10 l18 -22" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </div>
        </Reveal>

        <Reveal delay={100}>
          <div className="eyebrow lst-eyebrow">{l.eyebrow}</div>
        </Reveal>

        <h1 className="gs-success-title">
          <Words text={l.h1a} delay={200} />
          <em><Words text={l.h1b} delay={420} /></em>
        </h1>

        <Reveal delay={320}>
          <p className="gs-success-sub">{l.sub}</p>
        </Reveal>

        {queue ? (
          <Reveal delay={420}>
            <div className="lst-stats">
              <div className="lst-stat">
                <div className="lst-stat-label mono">{l.positionLabel}</div>
                {/* El «#» va aparte del número para que el lector de pantalla
                    no lea «almohadilla veinte» y el número mantenga su peso. */}
                <div className="lst-stat-value">
                  <span className="lst-hash" aria-hidden="true">#</span>{queue.position}
                </div>
                <p className="lst-stat-hint">{l.positionHint}</p>
              </div>

              <div className="lst-stat">
                <div className="lst-stat-label mono">{l.etaLabel}</div>
                <div className="lst-stat-value">
                  {days} <span className="lst-unit">{dayWord}</span>
                </div>
                <p className="lst-stat-hint">{l.etaHint}</p>
              </div>
            </div>
          </Reveal>
        ) : (
          <Reveal delay={420}>
            <div className="lst-pending">
              <div className="lst-stat-label mono">{l.pendingTitle}</div>
              <p className="lst-stat-hint">{l.pendingSub}</p>
            </div>
          </Reveal>
        )}

        {/* Vuelta de la pasarela: se le cuenta al cliente qué pasó. El cambio
            de cola real puede tardar unos segundos (llega por el webhook), así
            que el texto no promete un número nuevo ya mismo. */}
        {outcome === "paid" && (
          <Reveal delay={460}>
            <p className="lst-pay-note ok mono">{l.upDone}</p>
          </Reveal>
        )}
        {outcome === "cancelled" && (
          <Reveal delay={460}>
            <p className="lst-pay-note mono">{l.upCancelled}</p>
          </Reveal>
        )}

        {canUpgrade && (
          <Reveal delay={480}>
            <div className="lst-upgrade">
              <div className="lst-upgrade-head">
                <h2 className="lst-upgrade-title">{l.upTitle}</h2>
                <div className="lst-upgrade-price">
                  {l.upPrice} <span className="lst-once">{l.upOnce}</span>
                </div>
              </div>
              <p className="lst-upgrade-sub">{l.upSub}</p>
              {payError && <p className="form-error mono" role="alert">{payError}</p>}
              <button
                type="button"
                className="btn btn-lg"
                onClick={startCheckout}
                disabled={paying}
              >
                {paying ? l.upWorking : l.upCta} <ArrowIcon />
              </button>
            </div>
          </Reveal>
        )}

        <Reveal delay={520}>
          <div className="lst-dash">
            <h2 className="lst-dash-title">{l.dashTitle}</h2>
            <p className="lst-dash-sub">{l.dashSub}</p>
            {/* La línea de credenciales SOLO aparece cuando la cuenta se creó de
                verdad. El backend lo dirá con `account_created` cuando esa pieza
                exista; hasta entonces no se le promete al cliente un correo que
                nadie ha enviado. */}
            {finish && finish.account_created && (
              <p className="lst-dash-creds mono">{l.credentials}</p>
            )}
            {portalUrl && (
              <a className="btn btn-lg" href={portalUrl} rel="noopener">
                {l.dashCta} <ArrowIcon />
              </a>
            )}
          </div>
        </Reveal>
      </div>
    </section>
  );
}

Object.assign(window, { ListoPage });
