// payment.jsx — Page 2: Payment
// Provider hosted forms (Lava.top / Stripe) open in an overlay after "Оплатить".

function PaymentPage({ navigate, formData, setFormData, tweaks, devMode }) {
  const [method, setMethod] = React.useState("lava");
  const [checkoutOpen, setCheckoutOpen] = React.useState(false);
  const [loginOpen, setLoginOpen] = React.useState(false);
  const [emailErr, setEmailErr] = React.useState("");
  const [priceLabel, setPriceLabel] = React.useState("");
  const [pageContent, setPageContent] = React.useState(null);
  const [lavaWaiting, setLavaWaiting] = React.useState(false);
  const [lavaStatus, setLavaStatus] = React.useState("opening"); // opening | paying | blocked | failed | timeout | success
  const emailCardRef = React.useRef(null);
  const emailInputRef = React.useRef(null);
  const lavaPopupRef = React.useRef(null);
  const lavaUrlRef = React.useRef("");
  const lavaSinceRef = React.useRef("");
  const lavaIntervalRef = React.useRef(null);

  React.useEffect(() => {
    fetch("/api/payment-page")
      .then(r => r.ok ? r.json() : null)
      .then(d => {
        if (!d) return;
        setPageContent(d);
        if (d.price) setPriceLabel("$" + d.price);
        if (d.destination_default) setFormData(prev => ({...prev, destination: d.destination_default}));
      })
      .catch(() => {});
  }, []);

  const pc = pageContent || {};

  React.useEffect(() => {
    if (method === "lava" && pc.lava_enabled === false) setMethod("stripe");
    if (method === "stripe" && pc.stripe_enabled === false) setMethod("lava");
  }, [pc.lava_enabled, pc.stripe_enabled]);

  const isValidEmail = (e) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test((e||"").trim());
  const emailOk = isValidEmail(formData.email) && formData.emailVerified;

  const guardEmail = () => {
    setEmailErr(formData.emailVerified ? "Укажите корректный email перед оплатой" : (pc.pay_button_locked_text || "Сначала подтвердите email") + " кодом из письма");
    emailCardRef.current && emailCardRef.current.scrollIntoView({block:"center", behavior:"smooth"});
    setTimeout(() => emailInputRef.current && emailInputRef.current.focus(), 350);
  };

  const openLava = () => {
    if (!emailOk) { guardEmail(); return; }
    const sw = screen.width, sh = screen.height;
    const pw = Math.min(780, sw - 40), ph = Math.min(700, sh - 40);
    const win = window.open("about:blank", "lava_checkout",
      `width=${pw},height=${ph},left=${Math.round((sw-pw)/2)},top=${Math.round((sh-ph)/2)}`);
    lavaPopupRef.current = win;
    lavaUrlRef.current = "";
    setLavaStatus(win ? "opening" : "blocked");
    setLavaWaiting(true);
    const meta = collectClientMeta();
    (async () => {
      try {
        const customerName = [formData.firstName, formData.lastName].filter(Boolean).join(" ").trim();
        const res = await fetch("/api/payments/lava/create-invoice", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ email: formData.email, name: customerName || undefined, meta }),
        });
        if (!res.ok) throw new Error("invoice_error");
        const data = await res.json();
        if (!data.url) throw new Error("no_url");
        lavaUrlRef.current = data.url;
        lavaSinceRef.current = data.since || "";
        if (win && !win.closed) {
          win.location.href = data.url;
          setLavaStatus("paying");
        } else {
          setLavaStatus("blocked");
        }
        const startTime = Date.now();
        const id = setInterval(async () => {
          if (Date.now() - startTime > 5 * 60 * 1000) {
            clearInterval(id);
            setLavaStatus(s => s === "success" ? s : "timeout");
            return;
          }
          try {
            const sinceParam = lavaSinceRef.current ? `&since=${encodeURIComponent(lavaSinceRef.current)}` : "";
            const pr = await fetch(`/api/payments/poll?email=${encodeURIComponent(formData.email)}${sinceParam}`);
            const pd = await pr.json();
            if (pd.status === "succeeded") {
              clearInterval(id);
              const w = lavaPopupRef.current;
              if (w && !w.closed) w.close();
              setLavaStatus("success");
              setTimeout(async () => {
                try {
                  const cr = await fetch("/api/auth/claim-payment", {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ email: formData.email, since: lavaSinceRef.current }),
                  });
                  const cd = await cr.json();
                  if (cd.token) { window.location.href = `/?token=${cd.token}`; return; }
                } catch {}
                setLavaWaiting(false);
                navigate("setup");
              }, 1100);
            } else if (pd.status === "failed") {
              clearInterval(id);
              setLavaStatus("failed");
            }
          } catch {}
        }, 3000);
        lavaIntervalRef.current = id;
      } catch {
        setLavaStatus("failed");
      }
    })();
  };

  const closeLava = () => {
    if (lavaIntervalRef.current) clearInterval(lavaIntervalRef.current);
    const w = lavaPopupRef.current;
    if (w && !w.closed) w.close();
    setLavaWaiting(false);
  };

  const openCheckout = () => {
    if (!emailOk) { guardEmail(); return; }
    if (method === "lava") { openLava(); return; }
    setCheckoutOpen(true);
  };
  const openLogin = () => setLoginOpen(true);
  const onCheckoutSuccess = () => {
    setCheckoutOpen(false);
    setTimeout(() => navigate("setup"), 200);
  };
  const onLoginSuccess = () => {
    setLoginOpen(false);
    setTimeout(() => navigate("setup"), 200);
  };

  return (
    <div className="page">
      {!pageContent && (
        <div style={{position:"fixed",inset:0,zIndex:8888,background:"rgba(255,255,255,.72)",
                     backdropFilter:"blur(3px)",display:"grid",placeItems:"center",pointerEvents:"none"}}>
          <svg width="40" height="40" viewBox="0 0 40 40" fill="none"
               style={{animation:"spin 0.8s linear infinite",opacity:.5}}>
            <circle cx="20" cy="20" r="16" stroke="#6366f1" strokeWidth="4" strokeDasharray="60 40"
                    strokeLinecap="round"/>
          </svg>
        </div>
      )}
      <Header minimal />
      <main className="container container-main" style={{flex:1}}>
        <ProgressSteps current={1} show={tweaks.showProgress} />

        <div style={{maxWidth:680,margin:"24px auto 0",textAlign:"center"}}>
          <div className="eyebrow">Шаг 1 из 3 · Оплата</div>
          <h1 className="h1 mt-16">{pc.heading || "Подтверждение консультации"}</h1>
          <p className="lead mt-16">
            {pc.subheading || "Оплатите консультацию, чтобы получить доступ к подготовке и бронированию времени."}
          </p>

          {/* Returning-user entry point (device-bound magic links → user is always sent here) */}
          <button type="button" onClick={openLogin} className="login-banner mt-24">
            <span className="lb-ico"><MailIcon/></span>
            <span className="lb-txt">
              <b>{pc.login_banner_title || "Уже оплачивали консультацию?"}</b>
              <small>{pc.login_banner_subtitle || "Войдите по ссылке из письма — на новом устройстве или в другом браузере"}</small>
            </span>
            <span className="lb-cta">{pc.login_link_cta || "Войти по email"} <Icon.Arrow style={{width:14,height:14}}/></span>
          </button>
        </div>

        <div style={{display:"grid",gridTemplateColumns:"1.2fr 1fr",gap:28,maxWidth:1080,margin:"40px auto 0",alignItems:"start"}}
             className="pay-grid">

          {/* Left: email + included + method */}
          <div className="stack gap-20 anim-in" style={{minWidth:0}}>
            {/* Email для входа — критическое поле для device-bound magic links */}
            <EmailGateCard
              ref={emailCardRef}
              inputRef={emailInputRef}
              email={formData.email}
              verified={formData.emailVerified}
              onEmailChange={(v) => { setFormData({...formData, email: v}); if (emailErr) setEmailErr(""); }}
              onVerifiedChange={(v) => setFormData({...formData, emailVerified: v})}
              error={emailErr}
              isValidEmail={isValidEmail}
              devMode={devMode}
              pc={pc}
            />

            <div className="card card-pad">
              <div className="eyebrow">{pc.bullets_section_title || "Что входит в консультацию"}</div>
              <h3 className="h3 mt-8">{pc.bullets_heading || "60-минутный личный разбор"}</h3>
              <ul className="ck mt-16">
                {(pc.bullets || [
                  "Анализ вашей ситуации и профиля",
                  "Подбор оптимальной стратегии переезда",
                  "Ответы на все ваши вопросы",
                  "План дальнейших шагов",
                  "Рекомендации и полезные ресурсы",
                ]).map((b, i) => (
                  <li key={i}><span className="ico"><Icon.Check/></span>{b}</li>
                ))}
              </ul>

              <div style={{marginTop:24,paddingTop:20,borderTop:"1px solid var(--line)",display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:14,fontSize:13}}>
                <div><div className="muted" style={{marginBottom:3}}>Длительность</div><b style={{color:"var(--ink)"}}>{pc.duration || "60 минут"}</b></div>
                <div><div className="muted" style={{marginBottom:3}}>Формат</div><b style={{color:"var(--ink)"}}>{pc.format || "Zoom"}</b></div>
                <div><div className="muted" style={{marginBottom:3}}>Язык</div><b style={{color:"var(--ink)"}}>{pc.language || "RU / EN"}</b></div>
              </div>
            </div>

            <div className="card card-pad">
              <h3 className="h3">{pc.payment_method_title || "Способ оплаты"}</h3>
              <p className="muted" style={{fontSize:13.5,marginTop:6,marginBottom:16,lineHeight:1.5}}>
                {pc.payment_method_subtitle || "Выберите тип карты — после нажатия «Оплатить» откроется защищённая форма провайдера."}
              </p>

              {(pc.lava_enabled === false && pc.stripe_enabled === false) ? (
                <div style={{padding:"16px",background:"#fef2f2",borderRadius:10,color:"#dc2626",fontSize:13,textAlign:"center"}}>
                  Оплата временно недоступна. Пожалуйста, свяжитесь с нами.
                </div>
              ) : (
                <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:10}} className="pay-method-grid">
                  {pc.lava_enabled !== false && (
                    <button type="button" onClick={()=>setMethod("lava")}
                            style={{padding:"18px 18px",borderRadius:12,cursor:"pointer",textAlign:"left",transition:"all .15s",
                                    background: method==="lava" ? "color-mix(in srgb, var(--brand) 5%, white)" : "#fff",
                                    border: method==="lava" ? "1.5px solid var(--brand)" : "1.5px solid var(--line)",
                                    boxShadow: method==="lava" ? "0 0 0 3px color-mix(in srgb, var(--brand) 12%, transparent)" : "none"}}>
                      <div className="hstack" style={{justifyContent:"space-between",marginBottom:8}}>
                        <b style={{fontSize:15,color:"var(--ink)"}}>{pc.lava_label || "Обычная карта"}</b>
                        <RadioDot sel={method==="lava"}/>
                      </div>
                      <div className="hstack gap-8" style={{flexWrap:"wrap"}}>
                        <CardBadge type="mir"/>
                        <CardBadge type="visa"/>
                        <CardBadge type="mc"/>
                      </div>
                      <div className="muted" style={{fontSize:12,marginTop:10}}>{pc.lava_sublabel || "Платёж через Lava.top"}</div>
                    </button>
                  )}

                  {pc.stripe_enabled !== false && (
                    <button type="button" onClick={()=>setMethod("stripe")}
                            style={{padding:"18px 18px",borderRadius:12,cursor:"pointer",textAlign:"left",transition:"all .15s",
                                    background: method==="stripe" ? "color-mix(in srgb, var(--brand) 5%, white)" : "#fff",
                                    border: method==="stripe" ? "1.5px solid var(--brand)" : "1.5px solid var(--line)",
                                    boxShadow: method==="stripe" ? "0 0 0 3px color-mix(in srgb, var(--brand) 12%, transparent)" : "none"}}>
                      <div className="hstack" style={{justifyContent:"space-between",marginBottom:8}}>
                        <b style={{fontSize:15,color:"var(--ink)"}}>{pc.stripe_label || "Международная карта"}</b>
                        <RadioDot sel={method==="stripe"}/>
                      </div>
                      <div className="hstack gap-8" style={{flexWrap:"wrap"}}>
                        <CardBadge type="visa"/>
                        <CardBadge type="mc"/>
                        <CardBadge type="amex"/>
                      </div>
                      <div className="muted" style={{fontSize:12,marginTop:10}}>{pc.stripe_sublabel || "Платёж через Stripe"}</div>
                    </button>
                  )}
                </div>
              )}

              <div className="hstack gap-8 mt-24" style={{fontSize:12.5,color:"var(--ink-3)",lineHeight:1.5}}>
                <Icon.Lock style={{width:14,height:14,flexShrink:0}}/>
                {pc.card_data_note || "Данные карты вводятся на стороне провайдера. Мы не получаем и не храним их."}
              </div>
            </div>
          </div>

          {/* Right: order summary */}
          <aside className="anim-in" style={{position:"sticky",top:88,animationDelay:".05s",minWidth:0}}>
            <div className="card card-pad">
              <div className="eyebrow">Стоимость консультации</div>
              <div style={{fontSize:48,fontWeight:700,letterSpacing:"-.02em",marginTop:8,color:"var(--ink)"}}>{priceLabel}</div>
              <div className="muted" style={{marginTop:4}}>или эквивалент в вашей валюте</div>

              <hr className="divider" style={{margin:"22px 0"}}/>

              <div className="stack gap-12">
                <div className="hstack" style={{justifyContent:"space-between",alignItems:"flex-start",gap:12}}>
                  <span className="muted">Email</span>
                  <div style={{textAlign:"right",minWidth:0}}>
                    <b style={{color: formData.email ? (formData.emailVerified ? "var(--ink)" : "var(--ink-2)") : "var(--ink-3)",
                               fontSize:14, display:"block", overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap", maxWidth:200}}>
                      {formData.email || "не указан"}
                    </b>
                    <div className="hstack gap-8" style={{justifyContent:"flex-end",marginTop:3,fontSize:11.5}}>
                      {formData.email && formData.emailVerified && (
                        <span style={{color:"var(--ok)",fontWeight:600,display:"inline-flex",alignItems:"center",gap:3}}>
                          <Icon.Check style={{width:10,height:10}}/> подтверждён
                        </span>
                      )}
                      {formData.email && !formData.emailVerified && (
                        <span style={{color:"var(--warn)",fontWeight:600}}>не подтверждён</span>
                      )}
                      <button type="button"
                              onClick={() => {
                                emailCardRef.current && emailCardRef.current.scrollIntoView({block:"center", behavior:"smooth"});
                                setTimeout(() => emailInputRef.current && emailInputRef.current.focus(), 350);
                              }}
                              style={{background:"transparent",border:0,padding:0,fontSize:11.5,color:"var(--brand-deep)",cursor:"pointer",fontFamily:"inherit",fontWeight:600}}>
                        Изменить
                      </button>
                    </div>
                  </div>
                </div>
                <div className="hstack" style={{justifyContent:"space-between"}}>
                  <span className="muted">{pc.direction_label || "Направление"}</span>
                  <b style={{color:"var(--ink)",fontSize:14}}>{formData.destination || "—"}</b>
                </div>
                <div className="hstack" style={{justifyContent:"space-between"}}>
                  <span className="muted">Провайдер</span>
                  <b style={{color:"var(--ink)",fontSize:14}}>{method==="lava" ? "Lava.top" : "Stripe"}</b>
                </div>
              </div>

              <button className={"btn btn-primary btn-lg btn-block mt-24" + (emailOk ? "" : " btn-locked")}
                      onClick={openCheckout}
                      title={emailOk ? "" : (pc.pay_button_locked_text || "Сначала подтвердите email")}>
                {emailOk ? (
                  <>{pc.pay_button_text || "Оплатить"} {priceLabel} <Icon.Lock style={{width:14,height:14}}/></>
                ) : (
                  <><Icon.Lock style={{width:14,height:14}}/> {pc.pay_button_locked_text || "Сначала подтвердите email"}</>
                )}
              </button>

              {method === "lava" && emailOk && (
                <div style={{marginTop:8,display:"flex",alignItems:"center",gap:5,fontSize:12,
                             color:"var(--ink-3)",lineHeight:1.4}}>
                  <span style={{fontSize:13,flexShrink:0}}>↗</span>
                  Форма оплаты откроется в новом окне — разрешите всплывающие окна для этого сайта
                </div>
              )}

              <button type="button" onClick={openLogin}
                      style={{marginTop:10,width:"100%",background:"transparent",border:0,padding:"8px 0",
                              fontSize:13,color:"var(--ink-3)",cursor:"pointer",fontFamily:"inherit",
                              display:"flex",alignItems:"center",justifyContent:"center",gap:6}}>
                {pc.login_link_text || "Уже оплачивали?"} <b style={{color:"var(--brand-deep)",borderBottom:"1px solid color-mix(in srgb, var(--brand) 40%, transparent)"}}>{pc.login_link_cta || "Войти по email"}</b>
              </button>

              <div className="hstack gap-12 mt-16" style={{padding:"12px 14px",background:"var(--brand-soft)",borderRadius:10,alignItems:"flex-start"}}>
                <Icon.Shield style={{width:18,height:18,color:"var(--brand)",flexShrink:0,marginTop:1}}/>
                <div style={{fontSize:12.5,color:"var(--brand-deep)",lineHeight:1.5}}>
                  <b style={{display:"block",marginBottom:2}}>{pc.security_badge_title || "Безопасная оплата"}</b>
                  {pc.security_badge || "Платежи защищены 3D-Secure и обрабатываются через сертифицированных провайдеров."}
                </div>
              </div>

              <div className="muted mt-16 text-c" style={{fontSize:12.5,lineHeight:1.5}}>
                {pc.post_payment_note || "После оплаты вы получите доступ к подготовке и сможете забронировать удобное время."}
              </div>
            </div>
          </aside>
        </div>
      </main>

      {lavaWaiting && (
        <LavaWaitingOverlay
          status={lavaStatus}
          email={formData.email}
          lavaUrl={lavaUrlRef.current}
          onClose={closeLava}
        />
      )}

      {checkoutOpen && (
        <CheckoutModal provider={method} amount={priceLabel} formData={formData}
                       onClose={()=>setCheckoutOpen(false)}
                       onSuccess={onCheckoutSuccess}/>
      )}

      {loginOpen && (
        <MagicLinkModal defaultEmail={formData.email}
                        onClose={()=>setLoginOpen(false)}
                        onSuccess={onLoginSuccess}
                        devMode={devMode}
                        pc={pc}/>
      )}

      <style>{`
        @media (max-width:880px){.pay-grid{grid-template-columns:1fr !important}}
        @media (max-width:420px){.pay-method-grid{grid-template-columns:1fr !important}}

        /* Email gate */
        .email-gate{transition:border-color .2s, box-shadow .2s}
        .email-gate.ok{border-color: color-mix(in srgb, var(--ok) 35%, var(--line))}
        .email-gate.pending{border-color: color-mix(in srgb, var(--brand) 35%, var(--line))}
        .email-gate.err{border-color:var(--warn);box-shadow:0 0 0 4px rgba(239,68,68,.10)}
        .email-gate .eg-ico{
          width:24px;height:24px;border-radius:6px;
          background:var(--brand-soft);color:var(--brand);
          display:grid;place-items:center;
        }
        .email-gate .eg-ico svg{width:13px;height:13px}
        .email-gate.err .eg-ico{background:color-mix(in srgb, var(--warn) 14%, white);color:var(--warn)}
        .email-gate .eg-required{
          color:var(--ink-3);font-weight:500;letter-spacing:.04em;
          text-transform:none;margin-left:2px;
        }
        .email-gate .eg-note{
          margin-top:14px;padding-top:14px;border-top:1px solid var(--line-2);
          display:flex;gap:8px;align-items:flex-start;
          font-size:12.5px;color:var(--ink-3);line-height:1.5;
        }
        .email-gate .eg-demo{
          margin-top:14px;padding:10px 12px;background:var(--bg-tint);border-radius:8px;
          font-size:11.5px;color:var(--ink-3);line-height:1.5;
        }
        .email-gate .eg-demo b{color:var(--ink-2);font-weight:600}
        .email-gate .eg-demo code{
          background:#fff;border:1px solid var(--line);padding:1px 6px;border-radius:5px;
          font-size:11px;font-family:ui-monospace,'SF Mono',Menlo,Consolas,monospace;
        }

        /* OTP input row */
        .otp-row{display:grid;grid-template-columns:repeat(6, minmax(0, 1fr));gap:8px;max-width:340px}
        .otp-cell{
          width:100%;min-width:0;
          height:54px;border:1.5px solid var(--line);border-radius:10px;background:#fff;
          text-align:center;font-size:22px;font-weight:600;color:var(--ink);
          padding:0;outline:none;transition:border-color .12s, box-shadow .12s;
          font-variant-numeric:tabular-nums;
        }
        .otp-cell:focus{border-color:var(--brand);box-shadow:0 0 0 4px color-mix(in srgb, var(--brand) 14%, transparent)}
        .otp-cell.err{border-color:var(--warn);box-shadow:0 0 0 3px rgba(239,68,68,.10)}
        .otp-cell:disabled{background:var(--bg-tint);color:var(--ink-3)}
        @media (max-width:380px){
          .otp-row{gap:6px;max-width:none}
          .otp-cell{height:48px;font-size:18px}
        }

        /* Locked pay button (email not verified) */
        .btn-locked{
          background: var(--line-2) !important;
          color: var(--ink-3) !important;
          box-shadow: none !important;
          cursor: not-allowed;
        }
        .btn-locked:hover{background: var(--line-2) !important}

        .login-banner{
          appearance:none;border:1px solid var(--line);background:#fff;
          width:100%;max-width:560px;margin-left:auto;margin-right:auto;
          display:flex;align-items:center;gap:14px;padding:12px 14px 12px 12px;
          border-radius:12px;cursor:pointer;text-align:left;
          transition:border-color .15s, box-shadow .15s, transform .08s;
          font-family:inherit;color:var(--ink-2);
        }
        .login-banner:hover{border-color: color-mix(in srgb, var(--brand) 45%, var(--line));
          box-shadow:0 4px 14px -6px color-mix(in srgb, var(--brand) 35%, transparent)}
        .login-banner:active{transform:translateY(1px)}
        .login-banner .lb-ico{
          flex-shrink:0;width:36px;height:36px;border-radius:10px;
          background:var(--brand-soft);color:var(--brand);display:grid;place-items:center;
        }
        .login-banner .lb-ico svg{width:18px;height:18px}
        .login-banner .lb-txt{flex:1;display:flex;flex-direction:column;gap:2px;line-height:1.35}
        .login-banner .lb-txt b{font-size:13.5px;font-weight:600;color:var(--ink)}
        .login-banner .lb-txt small{font-size:12px;color:var(--ink-3);font-weight:400}
        .login-banner .lb-cta{
          flex-shrink:0;display:inline-flex;align-items:center;gap:5px;
          font-size:13px;font-weight:600;color:var(--brand-deep);white-space:nowrap;
        }
        @media (max-width:560px){
          .login-banner{flex-wrap:wrap}
          .login-banner .lb-cta{width:100%;justify-content:flex-end;padding-left:50px}
        }
      `}</style>
    </div>
  );
}

/* ───── Mail icon (local — not in shared.jsx) ───── */
function MailIcon(props) {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...props}>
      <rect x="3" y="5" width="18" height="14" rx="2"/>
      <polyline points="3 7 12 13 21 7"/>
    </svg>
  );
}

/* ───── Magic-link login modal ─────
   Device-bound magic links: returning users on a new device enter their email
   to receive a fresh sign-in link. Simulated 2-step flow.
*/
function MagicLinkModal({ defaultEmail, onClose, onSuccess, devMode, pc = {} }) {
  const [email, setEmail] = React.useState("");
  const [err, setErr] = React.useState("");
  const [sending, setSending] = React.useState(false);
  const [step, setStep] = React.useState("form"); // form | sent
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    const onKey = (e) => e.key === "Escape" && !sending && onClose();
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    setTimeout(() => inputRef.current && inputRef.current.focus(), 80);
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [sending, onClose]);

  const validEmail = (e) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e.trim());

  const sendLink = async (e) => {
    e && e.preventDefault();
    if (!validEmail(email)) { setErr("Введите корректный email"); return; }
    setErr("");
    setSending(true);
    try {
      const res = await fetch("/api/auth/request", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email: email.trim().toLowerCase() }),
      });
      if (res.status === 429) {
        setErr("Слишком много запросов. Попробуйте через 10 минут.");
        setSending(false);
        return;
      }
      if (!res.ok) {
        setErr("Ошибка сервера. Попробуйте позже.");
        setSending(false);
        return;
      }
      setStep("sent");
    } catch {
      setErr("Нет соединения. Проверьте интернет и попробуйте снова.");
    } finally {
      setSending(false);
    }
  };

  // Demo helper: "open the link" → continue into the app
  const openLink = () => {
    setSending(true);
    setTimeout(onSuccess, 600);
  };

  return (
    <div role="dialog" aria-modal="true"
         style={{position:"fixed",inset:0,zIndex:9999,background:"rgba(15,23,42,.6)",backdropFilter:"blur(4px)",
                 display:"grid",placeItems:"center",padding:20,animation:"fadeIn .2s ease"}}
         onClick={(e) => { if (e.target === e.currentTarget && !sending) onClose(); }}>
      <div style={{width:"100%",maxWidth:440,background:"#fff",borderRadius:16,
                   boxShadow:"0 30px 80px rgba(0,0,0,.4)",overflow:"hidden",
                   display:"flex",flexDirection:"column",animation:"fadeIn .25s ease"}}
           onClick={(e)=>e.stopPropagation()}>

        <div style={{padding:"16px 20px",borderBottom:"1px solid var(--line)",
                     display:"flex",alignItems:"center",justifyContent:"space-between"}}>
          <div className="hstack gap-8">
            <span style={{width:24,height:24,borderRadius:6,background:"var(--brand-soft)",color:"var(--brand)",display:"grid",placeItems:"center"}}>
              <MailIcon style={{width:14,height:14}}/>
            </span>
            <b style={{fontSize:14.5,fontWeight:700,color:"var(--ink)",letterSpacing:"-.005em"}}>{pc.login_modal_title || "Вход по email"}</b>
          </div>
          {!sending && (
            <button onClick={onClose}
                    style={{appearance:"none",border:0,background:"transparent",color:"var(--ink-3)",
                            width:30,height:30,borderRadius:8,cursor:"pointer",fontSize:20,lineHeight:1}}>×</button>
          )}
        </div>

        <div style={{padding:"22px 24px 24px"}}>
          {step === "form" && (
            <form className="anim-in" onSubmit={sendLink}>
              <h3 style={{fontSize:18,fontWeight:700,margin:"0 0 6px",color:"var(--ink)",letterSpacing:"-.01em"}}>
                {pc.login_modal_heading || "Войдите на этом устройстве"}
              </h3>
              <p style={{fontSize:13.5,color:"var(--ink-3)",margin:"0 0 18px",lineHeight:1.5}}>
                {pc.login_modal_description || "Введите email, который вы указывали при оплате. Мы отправим ссылку для входа — действительна 15 минут."}
              </p>

              <div className={"field" + (err ? " err" : "")}>
                <label htmlFor="ml-email">{pc.login_modal_email_label || "Email"}</label>
                <input ref={inputRef} id="ml-email" className="input" type="email"
                       placeholder={pc.login_modal_placeholder || "you@example.com"} autoComplete="email"
                       value={email}
                       onChange={(e)=>{setEmail(e.target.value); if(err) setErr("");}}/>
                {err && <div className="err-msg">{err}</div>}
              </div>

              {defaultEmail && defaultEmail !== email && (
                <button type="button" onClick={()=>setEmail(defaultEmail)}
                        style={{marginTop:8,background:"transparent",border:0,padding:0,fontSize:12.5,
                                color:"var(--brand-deep)",cursor:"pointer",fontFamily:"inherit",fontWeight:500}}>
                  Использовать {defaultEmail}
                </button>
              )}

              <button type="submit" className="btn btn-primary btn-lg btn-block mt-24" disabled={sending}>
                {sending ? <span className="hstack gap-8"><Spinner/> Отправка…</span> : <>{pc.login_modal_button || "Получить ссылку"} <Icon.Arrow style={{width:14,height:14}}/></>}
              </button>

              <div style={{marginTop:18,padding:"12px 14px",background:"var(--bg-tint)",borderRadius:10,
                           display:"flex",gap:10,alignItems:"flex-start"}}>
                <Icon.Shield style={{width:16,height:16,color:"var(--ink-3)",flexShrink:0,marginTop:1}}/>
                <div style={{fontSize:12,color:"var(--ink-3)",lineHeight:1.5}}>
                  {pc.login_modal_note || "Ссылка для входа привязана к устройству, на котором её открыли. Никто другой не сможет войти по ней."}
                </div>
              </div>
            </form>
          )}

          {step === "sent" && (
            <div className="anim-in" style={{textAlign:"center",padding:"8px 0 0"}}>
              <div style={{width:72,height:72,margin:"0 auto",borderRadius:"50%",
                           background:"var(--brand-soft)",color:"var(--brand)",display:"grid",placeItems:"center"}}>
                <MailIcon style={{width:32,height:32}}/>
              </div>
              <h3 style={{fontSize:19,fontWeight:700,margin:"18px 0 8px",color:"var(--ink)",letterSpacing:"-.01em"}}>
                Проверьте почту
              </h3>
              <p style={{fontSize:14,color:"var(--ink-2)",margin:"0 auto 4px",maxWidth:340,lineHeight:1.55}}>
                Мы отправили ссылку для входа на <b style={{color:"var(--ink)"}}>{email}</b>.
              </p>
              <p style={{fontSize:13,color:"var(--ink-3)",margin:"0 auto 22px",maxWidth:340,lineHeight:1.55}}>
                Откройте письмо <b>на этом устройстве</b>, чтобы войти. Ссылка действительна 15 минут.
              </p>

              {/* Demo CTA — only in dev mode */}
              {devMode && (
                <>
                  <button onClick={openLink} disabled={sending} className="btn btn-primary btn-block"
                          style={{height:46}}>
                    {sending ? <span className="hstack gap-8"><Spinner/> Открываем…</span> : <>Открыть ссылку из письма <Icon.Arrow style={{width:14,height:14}}/></>}
                  </button>
                  <div style={{fontSize:11,color:"var(--ink-3)",marginTop:8,fontStyle:"italic"}}>
                    · demo · в реальном продукте этот шаг происходит из почты
                  </div>
                </>
              )}

              <div style={{marginTop:18,paddingTop:16,borderTop:"1px solid var(--line)",fontSize:12.5,color:"var(--ink-3)",lineHeight:1.55}}>
                Не получили письмо? Проверьте «Спам» или{" "}
                <button type="button" onClick={()=>{setStep("form");}}
                        style={{background:"transparent",border:0,padding:0,color:"var(--brand-deep)",cursor:"pointer",fontWeight:600,fontFamily:"inherit",fontSize:"inherit"}}>
                  отправьте повторно
                </button>.
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function RadioDot({ sel }) {
  return (
    <div style={{width:18,height:18,borderRadius:"50%",border: sel ? "5px solid var(--brand)" : "1.5px solid var(--line)",background:"#fff",transition:"all .15s"}}/>
  );
}

function CardBadge({ type }) {
  const styles = {
    width: 32, height: 22, borderRadius: 4, display: "inline-grid", placeItems: "center",
    fontSize: 9, fontWeight: 700, color: "#fff", letterSpacing: ".02em",
  };
  if (type === "visa") return <span style={{...styles, background: "#1a1f71"}}>VISA</span>;
  if (type === "mc") return <span style={{...styles, background: "linear-gradient(90deg,#eb001b 50%,#f79e1b 50%)"}}>MC</span>;
  if (type === "amex") return <span style={{...styles, background: "#006fcf"}}>AMEX</span>;
  if (type === "mir") return <span style={{...styles, background: "#0f754e"}}>МИР</span>;
  return null;
}

/* ───── Checkout modal ─────
   Simulated provider-hosted form. Visually differentiated:
   - Lava.top: white/coral accent header with Lava branding
   - Stripe: dark Stripe header, Stripe-style form
*/
function CheckoutModal({ provider, amount, formData, onClose, onSuccess }) {
  const [processing, setProcessing] = React.useState(false);
  const [step, setStep] = React.useState("form"); // form | success

  // Stripe — store instances in refs to avoid re-render on assignment
  const stripeRef = React.useRef({ inst: null, elems: null });
  const stripeContainerRef = React.useRef(null);
  const [stripeStatus, setStripeStatus] = React.useState("loading"); // loading | ready | error
  const [stripeError, setStripeError] = React.useState("");

  React.useEffect(() => {
    const onKey = (e) => e.key === "Escape" && !processing && onClose();
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [processing, onClose]);

  // Init Stripe Payment Element — runs once when modal opens for Stripe
  React.useEffect(() => {
    if (provider !== "stripe") return;
    let mounted = true;
    const meta = collectClientMeta();
    (async () => {
      try {
        const customerName = [formData.firstName, formData.lastName].filter(Boolean).join(" ").trim();
        const res = await fetch("/api/payments/stripe/create-intent", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ email: formData.email, name: customerName || undefined, meta }),
        });
        if (!res.ok) {
          const body = await res.json().catch(() => ({}));
          if (mounted) { setStripeError(body.detail || "Ошибка инициализации платежа"); setStripeStatus("error"); }
          return;
        }
        const { clientSecret, publishableKey } = await res.json();
        if (!mounted || !stripeContainerRef.current) return;
        const stripe = Stripe(publishableKey);
        const elements = stripe.elements({ clientSecret, locale: "ru" });
        const paymentEl = elements.create("payment");
        // Attach listener before mount so we never miss the event
        paymentEl.on("ready", () => { if (mounted) setStripeStatus("ready"); });
        paymentEl.mount(stripeContainerRef.current);
        stripeRef.current = { inst: stripe, elems: elements };
      } catch (e) {
        if (mounted) { setStripeError("Не удалось загрузить форму оплаты"); setStripeStatus("error"); }
      }
    })();
    return () => { mounted = false; };
  }, [provider]);

  const pay = async () => {
    const { inst, elems } = stripeRef.current;
    if (!inst || !elems) return;
    setProcessing(true);
    setStripeError("");
    const { error, paymentIntent } = await inst.confirmPayment({
      elements: elems,
      confirmParams: { return_url: window.location.href },
      redirect: "if_required",
    });
    if (error) {
      setStripeError(error.message);
      setProcessing(false);
    } else if (paymentIntent) {
      setStep("success");
      setProcessing(false);
      setTimeout(onSuccess, 1100);
    }
  };

  const isLava = provider === "lava";
  const accent = isLava ? "#ff6b35" : "#635bff"; // lava orange / stripe purple
  const accentDark = isLava ? "#e85a2a" : "#5851ec";

  return (
    <div role="dialog" aria-modal="true"
         style={{position:"fixed",inset:0,zIndex:9999,background:"rgba(15,23,42,.6)",backdropFilter:"blur(4px)",
                 display:"grid",placeItems:"center",padding:20,animation:"fadeIn .2s ease"}}
         onClick={(e) => { if (e.target === e.currentTarget && !processing) onClose(); }}>
      <div style={{width:"100%",maxWidth: provider === "lava" ? 600 : 480,maxHeight:"calc(100vh - 40px)",background:"#fff",
                   borderRadius:16,boxShadow:"0 30px 80px rgba(0,0,0,.4)",overflow:"hidden",
                   display:"flex",flexDirection:"column",animation:"fadeIn .25s ease"}}
           onClick={(e)=>e.stopPropagation()}>

        {/* Provider header */}
        <div style={{padding:"16px 20px",background: isLava ? "#0a0a0a" : "#0a2540",color:"#fff",
                     display:"flex",alignItems:"center",justifyContent:"space-between",flexShrink:0}}>
          <div className="hstack gap-12">
            <ProviderLogo provider={provider}/>
          </div>
          {!processing && step !== "success" && (
            <button onClick={onClose}
                    style={{appearance:"none",border:0,background:"rgba(255,255,255,.1)",color:"#fff",
                            width:32,height:32,borderRadius:8,cursor:"pointer",fontSize:16}}>×</button>
          )}
        </div>

        <div style={{padding:"24px 24px 22px",overflow:"auto"}}>
          {step === "form" && (
            <div className="anim-in">
              <div style={{display:"flex",alignItems:"baseline",justifyContent:"space-between",marginBottom:18}}>
                <div>
                  <div style={{fontSize:13,color:"#64748b",fontWeight:500}}>KiwiEducation · Консультация</div>
                  <div style={{fontSize:13,color:"#64748b",marginTop:2}}>{formData.email || ""}</div>
                </div>
                <div style={{fontSize:24,fontWeight:700,color:"#0f172a",letterSpacing:"-.01em"}}>{amount}</div>
              </div>

              <div style={{marginBottom:4}}>
                {stripeError && (
                  <div style={{color:"#dc2626",fontSize:13,marginBottom:12,padding:"10px 12px",background:"#fef2f2",borderRadius:8}}>
                    {stripeError}
                  </div>
                )}
                {stripeStatus === "loading" && !stripeError && (
                  <div style={{display:"flex",alignItems:"center",justifyContent:"center",gap:8,padding:"40px 0",color:"#94a3b8",fontSize:13}}>
                    <Spinner/> Загрузка формы…
                  </div>
                )}
                <div ref={stripeContainerRef} style={{display: stripeStatus === "loading" ? "none" : "block"}} />
              </div>

              <button onClick={pay} disabled={processing || stripeStatus !== "ready"}
                      style={{width:"100%",height:48,marginTop:18,border:0,borderRadius:10,cursor:"pointer",
                              background: accent, color:"#fff",fontSize:15,fontWeight:600,letterSpacing:"-.005em",
                              boxShadow:`0 6px 16px -6px ${accent}`,transition:"background .15s",
                              opacity: stripeStatus !== "ready" ? .5 : 1}}
                      onMouseOver={(e)=>{ if (!e.currentTarget.disabled) e.currentTarget.style.background=accentDark; }}
                      onMouseOut={(e)=>e.currentTarget.style.background=accent}>
                {processing ? <span className="hstack gap-8" style={{justifyContent:"center"}}><Spinner/> Обработка…</span> : `Оплатить ${amount}`}
              </button>

              <div style={{textAlign:"center",marginTop:14,fontSize:11.5,color:"#94a3b8",lineHeight:1.5}}>
                <Icon.Lock style={{width:11,height:11,display:"inline",verticalAlign:"-1px",marginRight:3}}/>
                Защищено · Stripe · PCI DSS Level 1
              </div>
            </div>
          )}

          {step === "success" && (
            <div className="anim-in" style={{textAlign:"center",padding:"24px 0 8px"}}>
              <div style={{width:72,height:72,margin:"0 auto",borderRadius:"50%",background:"#dcfce7",display:"grid",placeItems:"center",color:"#16a34a"}}>
                <Icon.Check style={{width:36,height:36}}/>
              </div>
              <h3 style={{fontSize:20,fontWeight:700,marginTop:18,marginBottom:6,color:"#0f172a"}}>Платёж успешно проведён</h3>
              <p style={{fontSize:13.5,color:"#64748b",margin:"0 auto",maxWidth:320,lineHeight:1.5}}>
                Письмо с доступом к консультации отправлено на <b style={{color:"#0f172a"}}>{formData.email}</b>.
              </p>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function LavaWaitingOverlay({ status, email, lavaUrl, onClose }) {
  const isSuccess = status === "success";
  const isBlocked = status === "blocked";
  const canClose = isBlocked || status === "failed" || status === "timeout";

  React.useEffect(() => {
    document.body.style.overflow = "hidden";
    return () => { document.body.style.overflow = ""; };
  }, []);

  const openManually = () => {
    if (lavaUrl) window.open(lavaUrl, "lava_checkout",
      `width=${Math.min(780,screen.width-40)},height=${Math.min(700,screen.height-40)}`);
  };

  const titles = {
    opening: "Открываем форму оплаты…",
    paying:  "Форма оплаты открыта",
    blocked: "Браузер заблокировал окно",
    failed:  "Платёж не прошёл",
    timeout: "Время ожидания истекло",
    success: "Платёж успешно проведён",
  };
  const bodies = {
    opening: "Создаём счёт и открываем окно оплаты…",
    paying:  "Завершите оплату в открывшемся окне. Эта страница обновится автоматически.",
    blocked: "Браузер не разрешил открыть окно оплаты. Нажмите кнопку ниже, чтобы открыть вручную.",
    failed:  "Закройте это сообщение и попробуйте снова.",
    timeout: "Не получили подтверждение за 5 минут. Если оплата прошла — проверьте почту.",
    success: null,
  };

  return (
    <div role="dialog" aria-modal="true"
         style={{position:"fixed",inset:0,zIndex:9999,background:"rgba(15,23,42,.6)",
                 backdropFilter:"blur(4px)",display:"grid",placeItems:"center",
                 padding:20,animation:"fadeIn .2s ease"}}>
      <div style={{width:"100%",maxWidth:400,background:"#fff",borderRadius:16,
                   boxShadow:"0 30px 80px rgba(0,0,0,.4)",padding:"28px 24px 24px",
                   textAlign:"center",animation:"fadeIn .25s ease"}}>

        {isSuccess ? (
          <div style={{width:72,height:72,margin:"0 auto",borderRadius:"50%",
                       background:"#dcfce7",display:"grid",placeItems:"center",color:"#16a34a"}}>
            <Icon.Check style={{width:36,height:36}}/>
          </div>
        ) : isBlocked || status === "failed" ? (
          <div style={{width:72,height:72,margin:"0 auto",borderRadius:"50%",
                       background:"#fef2f2",display:"grid",placeItems:"center",
                       color:"#dc2626",fontSize:36,fontWeight:300,lineHeight:1}}>×</div>
        ) : (
          <div style={{width:72,height:72,margin:"0 auto",borderRadius:"50%",
                       background:"#fff7ed",display:"grid",placeItems:"center"}}>
            <span style={{width:32,height:32,border:"3px solid #ff6b35",borderTopColor:"transparent",
                          borderRadius:"50%",display:"block",animation:"spin .8s linear infinite"}}/>
          </div>
        )}

        <h3 style={{fontSize:18,fontWeight:700,margin:"16px 0 8px",color:"#0f172a",letterSpacing:"-.01em"}}>
          {titles[status] || ""}
        </h3>

        <p style={{fontSize:13.5,color:"#64748b",margin:"0 auto 20px",maxWidth:320,lineHeight:1.55}}>
          {isSuccess
            ? <>Письмо с доступом отправлено на <b style={{color:"#0f172a"}}>{email}</b>.</>
            : bodies[status] || ""}
        </p>

        {isBlocked && lavaUrl && (
          <button onClick={openManually}
                  style={{width:"100%",height:44,border:0,borderRadius:10,cursor:"pointer",
                          background:"#ff6b35",color:"#fff",fontSize:14,fontWeight:600,
                          fontFamily:"inherit",marginBottom:10}}>
            Открыть форму оплаты ↗
          </button>
        )}

        {canClose && (
          <button onClick={onClose}
                  style={{width:"100%",height:40,border:"1.5px solid var(--line)",borderRadius:10,
                          cursor:"pointer",background:"#fff",color:"var(--ink-2)",fontSize:14,
                          fontWeight:500,fontFamily:"inherit"}}>
            Закрыть
          </button>
        )}

        {!canClose && !isSuccess && (
          <button onClick={onClose}
                  style={{background:"transparent",border:0,padding:0,fontSize:12.5,
                          color:"var(--ink-3)",cursor:"pointer",fontFamily:"inherit",marginTop:4}}>
            Отменить
          </button>
        )}
      </div>
    </div>
  );
}

function ProviderLogo({ provider }) {
  if (provider === "lava") {
    return (
      <div className="hstack gap-8">
        <span style={{width:24,height:24,borderRadius:6,background:"#ff6b35",display:"grid",placeItems:"center",fontSize:13,fontWeight:700}}>L</span>
        <b style={{fontSize:15,fontWeight:700,letterSpacing:"-.01em"}}>lava<span style={{opacity:.7}}>.top</span></b>
      </div>
    );
  }
  // Stripe
  return (
    <div className="hstack gap-8">
      <span style={{fontSize:17,fontWeight:700,letterSpacing:"-.02em",fontFamily:"'Inter',system-ui",lineHeight:1}}>stripe</span>
    </div>
  );
}

function Spinner() {
  return (
    <span style={{display:"inline-block",width:16,height:16,border:"2px solid rgba(255,255,255,.4)",borderTopColor:"#fff",borderRadius:"50%",animation:"spin .8s linear infinite"}}/>
  );
}

/* ───── Email gate card ─────
   Email is the user's identity for device-bound magic links — must be CORRECT
   and VERIFIED before payment unlocks.
   Flow: empty → enter email → "Подтвердить" sends 6-digit code → enter code
   → verified ✓ → can pay. "Изменить" resets back to step 1.

   Demo code: any 6 digits works; "000000" is rejected to show the error state.
*/
const EmailGateCard = React.forwardRef(function EmailGateCard(
  { email, verified, onEmailChange, onVerifiedChange, error, isValidEmail, inputRef, devMode, pc = {} }, ref
) {
  // step: "enter" (typing email) | "code" (OTP) | "verified"
  const initialStep = verified ? "verified" : "enter";
  const [step, setStep] = React.useState(initialStep);
  const [draft, setDraft] = React.useState(email || "");
  const [code, setCode] = React.useState(["","","","","",""]);
  const [sending, setSending] = React.useState(false);
  const [verifying, setVerifying] = React.useState(false);
  const [localErr, setLocalErr] = React.useState("");
  const [codeErr, setCodeErr] = React.useState("");
  const [resendIn, setResendIn] = React.useState(0);
  const codeRefs = React.useRef([]);

  React.useEffect(() => { setDraft(email || ""); }, [email]);
  React.useEffect(() => {
    if (resendIn <= 0) return;
    const t = setInterval(() => setResendIn(s => s > 0 ? s - 1 : 0), 1000);
    return () => clearInterval(t);
  }, [resendIn]);

  const sendCode = () => {
    if (!isValidEmail(draft)) { setLocalErr("Введите корректный email"); return; }
    setLocalErr("");
    setSending(true);
    if (devMode) {
      setTimeout(() => {
        onEmailChange(draft.trim());
        setSending(false);
        setStep("code");
        setCode(["","","","","",""]);
        setCodeErr("");
        setResendIn(30);
        setTimeout(() => codeRefs.current[0] && codeRefs.current[0].focus(), 60);
      }, 700);
    } else {
      fetch("/api/auth/email/send", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email: draft.trim() }),
      })
        .then(r => r.ok ? r.json() : Promise.reject(r.status))
        .then(() => {
          onEmailChange(draft.trim());
          setSending(false);
          setStep("code");
          setCode(["","","","","",""]);
          setCodeErr("");
          setResendIn(30);
          setTimeout(() => codeRefs.current[0] && codeRefs.current[0].focus(), 60);
        })
        .catch(status => {
          setSending(false);
          setLocalErr(status === 429
            ? "Слишком много запросов. Попробуйте через 10 минут."
            : "Не удалось отправить код. Попробуйте снова.");
        });
    }
  };

  const verifyCode = (full) => {
    const c = (full || code.join("")).trim();
    if (c.length !== 6) { setCodeErr("Введите 6 цифр"); return; }
    setVerifying(true);
    setCodeErr("");
    if (devMode) {
      setTimeout(() => {
        setVerifying(false);
        if (c === "000000") {
          setCodeErr("Неверный код. Попробуйте ещё раз.");
          setCode(["","","","","",""]);
          setTimeout(() => codeRefs.current[0] && codeRefs.current[0].focus(), 60);
          return;
        }
        onVerifiedChange(true);
        setStep("verified");
      }, 700);
    } else {
      fetch("/api/auth/email/verify", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email: draft.trim(), code: c }),
      })
        .then(r => r.ok ? r.json() : Promise.reject())
        .then(data => {
          setVerifying(false);
          if (data.verified) {
            onVerifiedChange(true);
            setStep("verified");
          } else {
            setCodeErr("Неверный код. Попробуйте ещё раз.");
            setCode(["","","","","",""]);
            setTimeout(() => codeRefs.current[0] && codeRefs.current[0].focus(), 60);
          }
        })
        .catch(() => {
          setVerifying(false);
          setCodeErr("Ошибка проверки кода. Попробуйте снова.");
        });
    }
  };

  const changeEmail = () => {
    onVerifiedChange(false);
    setStep("enter");
    setCode(["","","","","",""]);
    setCodeErr("");
    setLocalErr("");
    setTimeout(() => inputRef.current && inputRef.current.focus(), 60);
  };

  const onCodeInput = (i, v) => {
    const digit = v.replace(/\D/g, "").slice(-1);
    const next = [...code];
    next[i] = digit;
    setCode(next);
    if (codeErr) setCodeErr("");
    if (digit && i < 5) codeRefs.current[i+1] && codeRefs.current[i+1].focus();
    if (next.every(d => d !== "") && next.join("").length === 6) {
      setTimeout(() => verifyCode(next.join("")), 100);
    }
  };
  const onCodeKey = (i, e) => {
    if (e.key === "Backspace" && !code[i] && i > 0) {
      codeRefs.current[i-1] && codeRefs.current[i-1].focus();
    }
  };
  const onCodePaste = (e) => {
    const txt = (e.clipboardData.getData("text") || "").replace(/\D/g,"").slice(0,6);
    if (txt.length === 6) {
      e.preventDefault();
      const next = txt.split("");
      setCode(next);
      codeRefs.current[5] && codeRefs.current[5].focus();
      setTimeout(() => verifyCode(txt), 100);
    }
  };

  const showErr = step === "enter" ? (localErr || error) : "";

  return (
    <div ref={ref} className={"card card-pad email-gate" + (showErr ? " err" : "") + (step === "verified" ? " ok" : "") + (step === "code" ? " pending" : "")}>
      {/* Header */}
      <div className="hstack" style={{justifyContent:"space-between",alignItems:"center",gap:12,marginBottom:4}}>
        <div className="hstack gap-8" style={{alignItems:"center"}}>
          <span className="eg-ico"><MailIcon/></span>
          <div className="eyebrow" style={{color: showErr ? "var(--warn)" : "var(--brand)"}}>
            {pc.email_gate_label || "Email для входа"}
            <span className="eg-required"> · обязательно</span>
          </div>
        </div>
        {step === "verified" && (
          <span className="hstack gap-8" style={{fontSize:12.5,color:"var(--ok)",fontWeight:600}}>
            <span style={{width:18,height:18,borderRadius:"50%",background:"color-mix(in srgb, var(--ok) 18%, transparent)",display:"grid",placeItems:"center",color:"var(--ok)"}}>
              <Icon.Check style={{width:10,height:10}}/>
            </span>
            подтверждён
          </span>
        )}
        {step === "code" && (
          <span style={{fontSize:12.5,color:"var(--ink-3)",fontWeight:500}}>
            Шаг 2 из 2
          </span>
        )}
      </div>

      {/* STEP: enter email */}
      {step === "enter" && (
        <div className="anim-in" style={{marginTop:10}}>
          <div className={"field" + (showErr ? " err" : "")}>
            <input
              ref={inputRef}
              className="input"
              type="email"
              autoComplete="email"
              placeholder={pc.email_gate_placeholder || "you@example.com"}
              value={draft}
              onChange={(e)=>{ setDraft(e.target.value); if (localErr) setLocalErr(""); }}
              onKeyDown={(e)=>{ if (e.key === "Enter") { e.preventDefault(); sendCode(); } }}
              style={{fontSize:16,height:50}}
              disabled={sending}
            />
            {showErr && <div className="err-msg">{showErr}</div>}
          </div>
          <button type="button" onClick={sendCode} disabled={sending || !draft}
                  className="btn btn-primary btn-block"
                  style={{marginTop:12,height:44}}>
            {sending ? <span className="hstack gap-8"><Spinner/> Отправляем код…</span> : <>{pc.email_gate_button || "Отправить код подтверждения"} <Icon.Arrow style={{width:14,height:14}}/></>}
          </button>
        </div>
      )}

      {/* STEP: enter code */}
      {step === "code" && (
        <div className="anim-in" style={{marginTop:10}}>
          <div style={{fontSize:13.5,color:"var(--ink-2)",lineHeight:1.5,marginBottom:14}}>
            Мы отправили 6-значный код на{" "}
            <b style={{color:"var(--ink)"}}>{email}</b>.{" "}
            <button type="button" onClick={changeEmail}
                    style={{background:"transparent",border:0,padding:0,color:"var(--brand-deep)",cursor:"pointer",fontWeight:600,fontFamily:"inherit",fontSize:"inherit"}}>
              Изменить email
            </button>
          </div>

          <div className="otp-row" onPaste={onCodePaste}>
            {code.map((d, i) => (
              <input key={i}
                     ref={el => codeRefs.current[i] = el}
                     className={"otp-cell" + (codeErr ? " err" : "")}
                     inputMode="numeric" maxLength={1}
                     value={d}
                     onChange={(e)=>onCodeInput(i, e.target.value)}
                     onKeyDown={(e)=>onCodeKey(i, e)}
                     disabled={verifying}/>
            ))}
          </div>
          {codeErr && <div className="err-msg" style={{marginTop:8}}>{codeErr}</div>}

          <div className="hstack" style={{justifyContent:"space-between",alignItems:"center",marginTop:14,gap:12,flexWrap:"wrap"}}>
            <button type="button" onClick={()=>verifyCode()} disabled={verifying || code.join("").length !== 6}
                    className="btn btn-primary"
                    style={{height:40,padding:"0 18px",fontSize:14,borderRadius:10}}>
              {verifying ? <span className="hstack gap-8"><Spinner/> Проверка…</span> : "Подтвердить"}
            </button>
            <button type="button" onClick={sendCode} disabled={resendIn > 0 || sending}
                    style={{background:"transparent",border:0,padding:0,
                            color: resendIn > 0 ? "var(--ink-3)" : "var(--brand-deep)",
                            cursor: resendIn > 0 ? "default" : "pointer",
                            fontWeight:600,fontFamily:"inherit",fontSize:13}}>
              {resendIn > 0 ? `Отправить повторно через ${resendIn} с` : "Отправить код повторно"}
            </button>
          </div>

          {devMode && (
            <div className="eg-demo">
              <b>· demo ·</b> любые 6 цифр подтверждают вход. Введите <code>000000</code>, чтобы увидеть ошибку.
            </div>
          )}
        </div>
      )}

      {/* STEP: verified */}
      {step === "verified" && (
        <div className="anim-in" style={{display:"flex",alignItems:"center",justifyContent:"space-between",gap:12,marginTop:10}}>
          <div style={{minWidth:0}}>
            <div style={{fontSize:20,fontWeight:600,color:"var(--ink)",letterSpacing:"-.005em",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>
              {email}
            </div>
            <div style={{fontSize:12.5,color:"var(--ink-3)",marginTop:2}}>
              Код подтверждён · доступ привязан к этому адресу
            </div>
          </div>
          <button type="button" onClick={changeEmail}
                  style={{flexShrink:0,background:"#fff",border:"1px solid var(--line)",borderRadius:9,
                          height:36,padding:"0 14px",fontSize:13,fontWeight:600,color:"var(--ink-2)",
                          cursor:"pointer",fontFamily:"inherit"}}>
            Изменить
          </button>
        </div>
      )}

      {/* Note */}
      <div className="eg-note">
        <Icon.Shield style={{width:14,height:14,flexShrink:0,marginTop:1,color:"var(--ink-3)"}}/>
        <span>
          {pc.email_gate_note || "На этот адрес придёт ссылка для входа. Это единственный способ войти с другого устройства — проверьте email до оплаты."}
        </span>
      </div>
    </div>
  );
});

if (!document.getElementById("spin-style")) {
  const s = document.createElement("style");
  s.id = "spin-style";
  s.textContent = "@keyframes spin{to{transform:rotate(360deg)}}";
  document.head.appendChild(s);
}

function collectClientMeta() {
  const params = new URLSearchParams(window.location.search);
  const meta = {};
  const utmMap = [
    ["utm_source", "utmSource"],
    ["utm_medium", "utmMedium"],
    ["utm_campaign", "utmCampaign"],
    ["utm_term", "utmTerm"],
    ["utm_content", "utmContent"],
  ];
  for (const [param, key] of utmMap) {
    const val = params.get(param);
    if (val) meta[key] = val;
  }
  try {
    meta.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
    meta.language = navigator.language;
    meta.screenWidth = String(screen.width);
    meta.screenHeight = String(screen.height);
    meta.pixelRatio = String(window.devicePixelRatio || 1);
  } catch {}
  return meta;
}

window.PaymentPage = PaymentPage;
