/* intake.jsx — the chat intake experience (#intake).

   Drives the conversation with the VPS turn engine. The browser holds the intake
   JSON (localStorage via HovexAPI) and re-sends it each turn — the server is
   stateless. Renders agent/user bubbles, tap-option buttons, a 7-step progress
   bar, the B7 summary card, and (Phase 4) inline upload / palette directives.

   Resume: same-browser continuation from localStorage. On DONE → #listo. */

function IntakePage({ navigate }) {
  const { t, lang } = useT();
  const es = lang !== "en";
  const tr = (esT, enT) => (es ? esT : enT);

  const [session] = useState(() => window.HovexAPI.loadSession());
  const [messages, setMessages] = useState([]); // {role, text, ui?}
  const [taps, setTaps] = useState([]);
  const [input, setInput] = useState("");
  const [block, setBlock] = useState("B0");
  const [progress, setProgress] = useState(0);
  const [sending, setSending] = useState(false);
  const [done, setDone] = useState(false);
  const [fatal, setFatal] = useState("");
  const stateRef = useRef(session.state);
  const scrollRef = useRef(null);
  const started = useRef(false);

  // Auto-scroll to the newest message.
  useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages, sending, taps]);

  // Kick off the opening turn once.
  useEffect(() => {
    if (started.current) return;
    started.current = true;
    if (!session.state || !session.token) return; // handled by the empty-state render
    sendTurn("", { silent: true });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  /**
   * Cierra el embudo: compila el paquete, lo entrega al dashboard y trae el
   * puesto en la lista de espera. Luego navega a #listo.
   *
   * Se espera a que termine (hasta un tope) para que la pantalla de cierre ya
   * tenga el número: navegar antes obligaría a #listo a enseñar un hueco y
   * rellenarlo después, que es peor que esperar un segundo más.
   */
  async function finish(finalState) {
    // Compilar el paquete y entregarlo puede tardar. Dos topes:
    //  - MIN: el mensaje de cierre tiene que poder leerse antes de saltar.
    //  - MAX: nadie se queda mirando el chat si el servidor no contesta.
    const MIN_DWELL_MS = 1400;
    const MAX_WAIT_MS = 20000;
    const dwell = new Promise((r) => setTimeout(r, MIN_DWELL_MS));
    const capped = Promise.race([
      window.HovexAPI.complete(finalState, session.token),
      new Promise((r) => setTimeout(() => r(null), MAX_WAIT_MS)),
    ]).catch(() => null); // La entrega falló o tardó demasiado: #listo enseña
                          // su copy sin número. Reintentar aquí duplicaría el
                          // lead, y la parte del cliente ya está hecha.
    await Promise.all([capped, dwell]);
    navigate("listo");
  }

  async function sendTurn(text, opts = {}) {
    const token = session.token;
    const state = stateRef.current;
    if (!state || !token) return;

    if (text && !opts.silent) {
      setMessages((m) => [...m, { role: "user", text }]);
    }
    setTaps([]);
    setInput("");
    setSending(true);
    setFatal("");
    try {
      const res = await window.HovexAPI.turn(state, token, text);
      if (!res || !res.ok) throw new Error((res && res.error) || "bad_response");
      stateRef.current = res.state;
      setBlock(res.block);
      setProgress(typeof res.progress === "number" ? res.progress : 0);
      if (res.say) setMessages((m) => [...m, { role: "agent", text: res.say, ui: res.ui }]);
      setTaps(res.tap_options || []);
      if (res.done) {
        setDone(true);
        // 🔴 Aquí se FINALIZA de verdad: se compila el paquete, el lead llega al
        // dashboard y vuelve el puesto en la lista de espera. Antes se navegaba
        // directo a #listo sin llamar a nada, así que el lead del funnel NUNCA
        // llegaba al dashboard — el pipeline estaba entero menos el disparador.
        //
        // No bloquea la navegación: si la finalización falla, el cliente ve la
        // pantalla de cierre sin número (copy alternativo) en vez de quedarse
        // atrapado en el chat.
        finish(res.state);
      }
    } catch (err) {
      const code = err && (err.code || err.message);
      if (code === "bad_token" || code === "token_intake_mismatch" || code === "invalid_state") {
        setFatal(tr(
          "Tu sesión expiró o no es válida. Empieza de nuevo.",
          "Your session expired or is invalid. Please start over."
        ));
      } else {
        // Transient — let them retry the same message.
        setMessages((m) => [...m, {
          role: "agent",
          text: tr("Ups, hubo un problema de conexión. Intenta enviar de nuevo.",
                   "Oops, a connection problem. Try sending again."),
        }]);
      }
    } finally {
      setSending(false);
    }
  }

  const onSubmit = (e) => {
    e.preventDefault();
    const v = input.trim();
    if (!v || sending) return;
    sendTurn(v);
  };

  // ── Empty / fatal states ────────────────────────────────────────────────────
  if (!session.state || !session.token) {
    return (
      <section className="hx-chat-wrap">
        <div className="hx-empty">
          <p className="gs-sub">{tr("No encontramos un proyecto en curso.", "No project in progress found.")}</p>
          <button className="btn btn-lg" onClick={() => navigate("crear")}>
            {tr("Empezar", "Get started")} <ArrowIcon />
          </button>
        </div>
      </section>
    );
  }

  const bizName = (stateRef.current && stateRef.current.business && stateRef.current.business.name) || "";
  const steps = [1, 2, 3, 4, 5, 6, 7];
  const doneSteps = Math.round(progress * 7);

  return (
    <section className="hx-chat-wrap">
      <div className="hx-chat">
        {/* Header + progress */}
        <div className="hx-head">
          <div className="hx-head-name mono">{bizName}</div>
          <div className="hx-progress" role="progressbar" aria-valuenow={doneSteps} aria-valuemin={0} aria-valuemax={7}>
            {steps.map((n) => (
              <span key={n} className={`hx-step ${n <= doneSteps ? "done" : ""}`} />
            ))}
          </div>
        </div>

        {/* Messages */}
        <div className="hx-messages" ref={scrollRef}>
          {messages.map((m, i) => (
            <div key={i} className={`hx-bubble ${m.role}`}>
              {m.text}
              {m.ui && m.ui.kind === "summary_card" && <SummaryCard data={m.ui.data} es={es} />}
              {m.ui && m.ui.kind === "upload_logo" && (
                <div className="hx-hint mono">{tr("(La carga de logo se habilita pronto — puedes continuar sin logo.)",
                  "(Logo upload coming soon — you can continue without one.)")}</div>
              )}
            </div>
          ))}
          {sending && (
            <div className="hx-bubble agent hx-typing"><span></span><span></span><span></span></div>
          )}
          {fatal && (
            <div className="hx-empty">
              <p className="form-error mono">{fatal}</p>
              <button className="btn" onClick={() => { window.HovexAPI.clearSession(); navigate("crear"); }}>
                {tr("Empezar de nuevo", "Start over")}
              </button>
            </div>
          )}
        </div>

        {/* Composer */}
        {!done && !fatal && (
          <div className="hx-composer">
            {taps.length > 0 && (
              <div className="hx-taps">
                {taps.map((opt) => (
                  <button key={opt} type="button" className="hx-tap" disabled={sending}
                    onClick={() => sendTurn(opt)}>{opt}</button>
                ))}
              </div>
            )}
            <form className="hx-input-row" onSubmit={onSubmit}>
              <input
                type="text" className="hx-input" maxLength={1000}
                placeholder={tr("Escribe tu respuesta…", "Type your answer…")}
                value={input} onChange={(e) => setInput(e.target.value)}
                disabled={sending} autoFocus
              />
              <button type="submit" className="hx-send" disabled={sending || !input.trim()} aria-label="Enviar">
                <ArrowIcon />
              </button>
            </form>
          </div>
        )}
      </div>
    </section>
  );
}

// Review card rendered from JSON (never from raw model text).
function SummaryCard({ data, es }) {
  if (!data) return null;
  return (
    <div className="hx-summary">
      <div className="hx-summary-title">{data.business_name}</div>
      <dl className="hx-summary-rows">
        {(data.rows || []).map((r, i) => (
          <div className="hx-summary-row" key={i}>
            <dt>{r.label}</dt>
            <dd>{r.value}</dd>
          </div>
        ))}
      </dl>
    </div>
  );
}

Object.assign(window, { IntakePage });
