// Carimbou signup — 3-step wizard (chunk 2 of self-checkout v2)
// Served at /signup via GET /signup (no-store HTML hull in src/routes/signup.js)
//
// Flow:
//   Step 1: business name + WhatsApp do negócio + first/last name + (conditional)
//           personal WhatsApp + two consent checkboxes  →  POST /signup/leads
//   Step 2: legal name + CPF/CNPJ + email do negócio  →  PATCH /signup/leads/:token
//   Step 3: payment method picker — "Em breve" placeholder (chunk 3 wires this)
//
// Persistence:
//   - localStorage 'cb_lead_token' carries the lead token across reloads.
//   - On mount, hydrate from URL (?lead=<token>) first, then localStorage,
//     then server lookup by personal phone (deferred to step-1 submit).
//   - Token cleared when the lead converts to a business (chunk 3).
//
// Important: this is a static asset, NOT a server-side template literal,
// so the backslash-escape caveat from CLAUDE.md does not apply here. All
// JS regex literals can be written normally.

const { useState, useEffect, useRef } = React;

const LEAD_TOKEN_STORAGE_KEY = 'cb_lead_token';

// ─── Formatting helpers ─────────────────────────────────────────────────────

function formatCpfCnpj(value) {
  const digits = value.replace(/\D/g, '').slice(0, 14);
  if (digits.length <= 11) {
    return digits
      .replace(/(\d{3})(\d)/, '$1.$2')
      .replace(/(\d{3})(\d)/, '$1.$2')
      .replace(/(\d{3})(\d{1,2})$/, '$1-$2');
  }
  return digits
    .replace(/(\d{2})(\d)/, '$1.$2')
    .replace(/(\d{3})(\d)/, '$1.$2')
    .replace(/(\d{3})(\d)/, '$1/$2')
    .replace(/(\d{4})(\d{1,2})$/, '$1-$2');
}

function formatPhone(value) {
  const digits = value.replace(/\D/g, '').slice(0, 11);
  if (digits.length <= 10) {
    return digits.replace(/(\d{2})(\d{4})(\d{0,4})/, '($1) $2-$3').trim().replace(/-$/, '');
  }
  return digits.replace(/(\d{2})(\d{5})(\d{0,4})/, '($1) $2-$3').trim().replace(/-$/, '');
}

// Convert a stored / normalized phone (`+5521997640107`) into the display
// form (`(21) 99764-0107`). Strips the leading 55 country code so the
// `(DD) NNNNN-NNNN` regex in formatPhone gets the local 10-11 digits it
// expects — otherwise the display ends up as `(55) 21997-6401` and the
// next submit double-prefixes to `+5555219976401`. (Test-7 staging bug.)
function displayPhone(stored) {
  const digits = String(stored || '').replace(/\D/g, '');
  if (!digits) return '';
  // Brazilian numbers stored as +55 + DDD + 8/9 digits = 12 or 13 chars.
  const local = (digits.length === 12 || digits.length === 13) && digits.startsWith('55')
    ? digits.slice(2)
    : digits;
  return formatPhone(local);
}

// ─── Styles ─────────────────────────────────────────────────────────────────

const styles = {
  page: {
    minHeight: '100vh',
    background: '#EDE6D6',
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    padding: '40px 16px 60px',
  },
  logo: {
    fontSize: 28,
    fontWeight: 700,
    color: '#2D8A6B',
    marginBottom: 32,
    letterSpacing: '-0.5px',
  },
  card: {
    background: '#fff',
    borderRadius: 20,
    padding: '36px 32px',
    width: '100%',
    maxWidth: 480,
    boxShadow: '0 4px 24px rgba(0,0,0,0.08)',
  },
  progressRow: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: 8,
    marginBottom: 24,
  },
  progressDot: {
    width: 8,
    height: 8,
    borderRadius: '50%',
    background: '#E0D9CC',
    transition: 'background 0.2s, width 0.2s',
  },
  progressDotActive: {
    background: '#2D8A6B',
    width: 24,
    borderRadius: 4,
  },
  progressDotComplete: {
    background: '#2D8A6B',
  },
  progressLabel: {
    fontSize: 12,
    color: '#888',
    textAlign: 'center',
    marginBottom: 24,
    fontWeight: 600,
    letterSpacing: '0.4px',
    textTransform: 'uppercase',
  },
  title: {
    fontSize: 22,
    fontWeight: 700,
    color: '#1a1a2e',
    marginBottom: 6,
  },
  subtitle: {
    fontSize: 14,
    color: '#666',
    marginBottom: 28,
    lineHeight: 1.5,
  },
  section: {
    fontSize: 11,
    fontWeight: 600,
    color: '#2D8A6B',
    textTransform: 'uppercase',
    letterSpacing: '0.8px',
    marginTop: 24,
    marginBottom: 12,
  },
  field: {
    marginBottom: 16,
  },
  label: {
    display: 'block',
    fontSize: 13,
    fontWeight: 600,
    color: '#333',
    marginBottom: 6,
  },
  input: {
    width: '100%',
    padding: '11px 14px',
    borderRadius: 10,
    border: '1.5px solid #E0D9CC',
    fontSize: 15,
    color: '#1a1a2e',
    background: '#FAFAF8',
    outline: 'none',
    transition: 'border-color 0.15s',
    fontFamily: 'inherit',
  },
  inputFocus: {
    borderColor: '#2D8A6B',
    background: '#fff',
  },
  checkRow: {
    display: 'flex',
    alignItems: 'flex-start',
    gap: 10,
    marginTop: 8,
    marginBottom: 16,
  },
  checkbox: {
    marginTop: 2,
    accentColor: '#2D8A6B',
    width: 16,
    height: 16,
    cursor: 'pointer',
    flexShrink: 0,
  },
  checkLabel: {
    fontSize: 13,
    color: '#555',
    lineHeight: 1.5,
    cursor: 'pointer',
  },
  consent: {
    fontSize: 12,
    color: '#888',
    lineHeight: 1.5,
    marginTop: 16,
    textAlign: 'center',
  },
  btn: {
    width: '100%',
    padding: '14px',
    borderRadius: 12,
    border: 'none',
    background: '#2D8A6B',
    color: '#fff',
    fontSize: 16,
    fontWeight: 700,
    cursor: 'pointer',
    fontFamily: 'inherit',
    transition: 'background 0.15s, opacity 0.15s',
  },
  btnSecondary: {
    background: 'transparent',
    color: '#2D8A6B',
    border: '1.5px solid #2D8A6B',
  },
  btnDisabled: {
    opacity: 0.6,
    cursor: 'not-allowed',
  },
  error: {
    background: '#fff0f3',
    border: '1px solid #ffc0cb',
    borderRadius: 10,
    padding: '12px 14px',
    color: '#c00',
    fontSize: 14,
    marginBottom: 20,
  },
  info: {
    background: '#fff8e6',
    border: '1px solid #ffe2a0',
    borderRadius: 10,
    padding: '12px 14px',
    color: '#8a6a0a',
    fontSize: 13,
    marginBottom: 20,
    lineHeight: 1.5,
  },
  termsLink: {
    color: '#2D8A6B',
    fontWeight: 600,
    textDecoration: 'none',
  },
  placeholderBlock: {
    background: '#FAFAF8',
    border: '1.5px dashed #E0D9CC',
    borderRadius: 12,
    padding: '24px 18px',
    textAlign: 'center',
    color: '#888',
    fontSize: 14,
    lineHeight: 1.6,
    marginTop: 12,
    marginBottom: 24,
  },
};

// ─── Reusable: Progress dots ────────────────────────────────────────────────

function ProgressDots({ step }) {
  // step is 1, 2, or 3
  return (
    <div>
      <div style={styles.progressRow}>
        {[1, 2, 3].map(n => (
          <div
            key={n}
            style={{
              ...styles.progressDot,
              ...(n === step ? styles.progressDotActive : {}),
              ...(n < step ? styles.progressDotComplete : {}),
            }}
          />
        ))}
      </div>
      <div style={styles.progressLabel}>Passo {step} de 3</div>
    </div>
  );
}

// ─── Reusable: text field with focus styling ────────────────────────────────

function Field({ label, value, onChange, placeholder, type, inputMode, required, autoFocus, name }) {
  const [focused, setFocused] = useState(false);
  return (
    <div style={styles.field}>
      <label style={styles.label}>{label}{required ? ' *' : ''}</label>
      <input
        name={name}
        type={type || 'text'}
        inputMode={inputMode}
        style={{ ...styles.input, ...(focused ? styles.inputFocus : {}) }}
        value={value || ''}
        onChange={e => onChange(e.target.value)}
        onFocus={() => setFocused(true)}
        onBlur={() => setFocused(false)}
        placeholder={placeholder}
        required={required}
        autoFocus={autoFocus}
        autoComplete="off"
      />
    </div>
  );
}

// ─── Step 1: business + personal info + consent ─────────────────────────────

function Step1({ form, setForm, onSubmit, loading, error }) {
  function set(key, value) { setForm(f => ({ ...f, [key]: value })); }

  function submit(e) {
    e.preventDefault();
    onSubmit();
  }

  const canSubmit = form.businessName
    && form.businessWhatsappPhone
    && form.firstName
    && form.lastName
    && (form.samePhone || form.personalWhatsappPhone)
    && form.consentTerms
    && form.consentMessaging;

  return (
    <form onSubmit={submit}>
      <div style={styles.title}>Vamos começar</div>
      <div style={styles.subtitle}>
        Plano Premium · R$100/mês · Carimbos ilimitados.<br/>
        Primeiro, conta pra gente quem é você.
      </div>

      {error && <div style={styles.error}>{error}</div>}

      <div style={styles.section}>Negócio</div>

      <Field
        label="Nome do negócio"
        value={form.businessName}
        onChange={v => set('businessName', v)}
        placeholder="Ex: Padaria Central"
        required
      />

      <Field
        label="WhatsApp do negócio"
        value={form.businessWhatsappPhone}
        onChange={v => set('businessWhatsappPhone', formatPhone(v))}
        placeholder="(21) 99999-9999"
        inputMode="tel"
        required
      />

      <div style={styles.section}>Você</div>

      <Field
        label="Seu nome"
        value={form.firstName}
        onChange={v => set('firstName', v)}
        placeholder="Nome"
        required
      />

      <Field
        label="Seu sobrenome"
        value={form.lastName}
        onChange={v => set('lastName', v)}
        placeholder="Sobrenome"
        required
      />

      <div style={styles.checkRow}>
        <input
          type="checkbox"
          id="samePhone"
          style={styles.checkbox}
          checked={!!form.samePhone}
          onChange={e => set('samePhone', e.target.checked)}
        />
        <label htmlFor="samePhone" style={styles.checkLabel}>
          Meu WhatsApp pessoal é o mesmo do negócio
        </label>
      </div>

      {!form.samePhone && (
        <Field
          label="Seu WhatsApp pessoal"
          value={form.personalWhatsappPhone}
          onChange={v => set('personalWhatsappPhone', formatPhone(v))}
          placeholder="(21) 99999-9999"
          inputMode="tel"
          required
        />
      )}

      <div style={{ ...styles.section, marginTop: 20 }}>Consentimentos</div>

      <div style={styles.checkRow}>
        <input
          type="checkbox"
          id="consentTerms"
          style={styles.checkbox}
          checked={!!form.consentTerms}
          onChange={e => set('consentTerms', e.target.checked)}
        />
        <label htmlFor="consentTerms" style={styles.checkLabel}>
          Li e aceito os <a href="#" target="_blank" style={styles.termsLink}>Termos de Uso</a> da Carimbou
        </label>
      </div>

      <div style={styles.checkRow}>
        <input
          type="checkbox"
          id="consentMessaging"
          style={styles.checkbox}
          checked={!!form.consentMessaging}
          onChange={e => set('consentMessaging', e.target.checked)}
        />
        <label htmlFor="consentMessaging" style={styles.checkLabel}>
          Concordo em receber comunicações da Carimbou por WhatsApp, SMS e email
        </label>
      </div>

      <button
        type="submit"
        style={{ ...styles.btn, marginTop: 12, ...(loading || !canSubmit ? styles.btnDisabled : {}) }}
        disabled={loading || !canSubmit}
      >
        {loading ? 'Salvando…' : 'Continuar →'}
      </button>
    </form>
  );
}

// ─── Step 2: legal data ─────────────────────────────────────────────────────

function Step2({ form, setForm, onSubmit, onBack, loading, error }) {
  function set(key, value) { setForm(f => ({ ...f, [key]: value })); }

  function submit(e) {
    e.preventDefault();
    onSubmit();
  }

  const cleanCpf = (form.cpfCnpj || '').replace(/\D/g, '');
  const validCpf = cleanCpf.length === 11 || cleanCpf.length === 14;
  const canSubmit = form.legalName && validCpf && form.businessEmail;

  return (
    <form onSubmit={submit}>
      <div style={styles.title}>Dados legais</div>
      <div style={styles.subtitle}>
        Usamos esses dados para emitir a nota fiscal e contatar o financeiro do
        seu negócio.
      </div>

      {error && <div style={styles.error}>{error}</div>}

      <Field
        label="Nome / Razão Social"
        value={form.legalName}
        onChange={v => set('legalName', v)}
        placeholder="Nome completo ou razão social"
        required
        autoFocus
      />

      <Field
        label="CPF ou CNPJ"
        value={form.cpfCnpj}
        onChange={v => set('cpfCnpj', formatCpfCnpj(v))}
        placeholder="000.000.000-00 ou 00.000.000/0000-00"
        inputMode="numeric"
        required
      />

      <Field
        label="Email do negócio"
        value={form.businessEmail}
        onChange={v => set('businessEmail', v)}
        placeholder="contato@seunegocio.com.br"
        type="email"
        required
      />

      <button
        type="submit"
        style={{ ...styles.btn, marginTop: 12, ...(loading || !canSubmit ? styles.btnDisabled : {}) }}
        disabled={loading || !canSubmit}
      >
        {loading ? 'Salvando…' : 'Continuar →'}
      </button>

      <button
        type="button"
        onClick={onBack}
        style={{ ...styles.btn, ...styles.btnSecondary, marginTop: 10 }}
        disabled={loading}
      >
        ← Voltar
      </button>
    </form>
  );
}

// ─── Step 3 styles (additions) ──────────────────────────────────────────────

const step3Styles = {
  methodCard: {
    border: '1.5px solid #E0D9CC',
    borderRadius: 14,
    padding: '16px 18px',
    marginBottom: 12,
    cursor: 'pointer',
    background: '#FAFAF8',
    transition: 'border-color 0.15s, background 0.15s',
    display: 'flex',
    alignItems: 'flex-start',
    gap: 14,
  },
  methodCardSelected: {
    borderColor: '#2D8A6B',
    background: '#fff',
    boxShadow: '0 0 0 3px rgba(45,138,107,0.12)',
  },
  methodRadio: {
    marginTop: 4,
    accentColor: '#2D8A6B',
    width: 18,
    height: 18,
    flexShrink: 0,
  },
  methodBody: {
    flex: 1,
  },
  methodTitle: {
    fontSize: 15,
    fontWeight: 700,
    color: '#1a1a2e',
    marginBottom: 4,
  },
  methodSub: {
    fontSize: 13,
    color: '#666',
    lineHeight: 1.45,
  },
  methodBadge: {
    display: 'inline-block',
    background: '#2D8A6B',
    color: '#fff',
    fontSize: 10,
    fontWeight: 700,
    padding: '2px 8px',
    borderRadius: 999,
    marginLeft: 6,
    letterSpacing: '0.3px',
    textTransform: 'uppercase',
  },
  qrContainer: {
    textAlign: 'center',
    margin: '16px 0',
  },
  qrImage: {
    width: 280,
    height: 280,
    maxWidth: '100%',
    background: '#fff',
    border: '1.5px solid #E0D9CC',
    borderRadius: 16,
    padding: 8,
  },
  pixCode: {
    fontSize: 11,
    color: '#666',
    background: '#FAFAF8',
    border: '1.5px solid #E0D9CC',
    borderRadius: 10,
    padding: '10px 12px',
    wordBreak: 'break-all',
    fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
    marginBottom: 12,
    maxHeight: 80,
    overflow: 'auto',
  },
  copyBtn: {
    width: '100%',
    padding: '10px',
    borderRadius: 10,
    border: '1.5px solid #2D8A6B',
    background: 'transparent',
    color: '#2D8A6B',
    fontSize: 14,
    fontWeight: 600,
    cursor: 'pointer',
    fontFamily: 'inherit',
    marginBottom: 12,
  },
  statusPill: {
    display: 'inline-block',
    padding: '6px 14px',
    borderRadius: 999,
    background: '#fff8e6',
    border: '1px solid #ffe2a0',
    color: '#8a6a0a',
    fontSize: 13,
    fontWeight: 600,
  },
  statusPillActive: {
    background: '#e8f7ef',
    border: '1px solid #a8e0c0',
    color: '#1e6b48',
  },
  instructions: {
    fontSize: 13,
    color: '#555',
    lineHeight: 1.6,
    background: '#FAFAF8',
    border: '1.5px solid #E0D9CC',
    borderRadius: 10,
    padding: '12px 14px',
    marginBottom: 12,
  },
  instructionsList: {
    margin: '8px 0 0 18px',
    padding: 0,
  },
};

// ─── Step 3a: method picker ─────────────────────────────────────────────────

function Step3Picker({ method, setMethod, onSubmit, onBack, loading, error, lastStep3Error }) {
  function submit(e) {
    e.preventDefault();
    onSubmit();
  }
  return (
    <form onSubmit={submit}>
      <div style={styles.title}>Forma de pagamento</div>
      <div style={styles.subtitle}>
        Plano Premium · R$100/mês · Carimbos ilimitados.<br/>
        Escolha como pagar.
      </div>

      {error && <div style={styles.error}>{error}</div>}
      {!error && lastStep3Error && (
        <div style={styles.error}>
          A tentativa anterior falhou: {lastStep3Error}. Corrija seus dados nas etapas anteriores se necessário e tente de novo.
        </div>
      )}

      <label
        style={{
          ...step3Styles.methodCard,
          ...(method === 'pix_automatic' ? step3Styles.methodCardSelected : {}),
        }}
      >
        <input
          type="radio"
          name="method"
          value="pix_automatic"
          checked={method === 'pix_automatic'}
          onChange={() => setMethod('pix_automatic')}
          style={step3Styles.methodRadio}
        />
        <div style={step3Styles.methodBody}>
          <div style={step3Styles.methodTitle}>
            Pix Automático
            <span style={step3Styles.methodBadge}>Recomendado</span>
          </div>
          <div style={step3Styles.methodSub}>
            Você autoriza no seu banco uma vez e a Carimbou cobra R$100 todo mês automaticamente.
            Sem cartão, sem renovação manual.
          </div>
        </div>
      </label>

      <label
        style={{
          ...step3Styles.methodCard,
          ...(method === 'credit_card' ? step3Styles.methodCardSelected : {}),
        }}
      >
        <input
          type="radio"
          name="method"
          value="credit_card"
          checked={method === 'credit_card'}
          onChange={() => setMethod('credit_card')}
          style={step3Styles.methodRadio}
        />
        <div style={step3Styles.methodBody}>
          <div style={step3Styles.methodTitle}>
            Cartão de Crédito
          </div>
          <div style={step3Styles.methodSub}>
            Cadastre seu cartão e a cobrança mensal de R$100 é feita automaticamente.
            Você pode trocar o cartão depois.
          </div>
        </div>
      </label>

      <button
        type="submit"
        style={{ ...styles.btn, marginTop: 16, ...(loading || !method ? styles.btnDisabled : {}) }}
        disabled={loading || !method}
      >
        {loading ? 'Criando assinatura…' : 'Confirmar e ir para pagamento →'}
      </button>

      <button
        type="button"
        onClick={onBack}
        style={{ ...styles.btn, ...styles.btnSecondary, marginTop: 10 }}
        disabled={loading}
      >
        ← Voltar à etapa 2
      </button>
    </form>
  );
}

// ─── Step 3b: Pix Automático QR + polling ───────────────────────────────────

function PixAuthScreen({ pix, token, firstName, businessId, botPhone }) {
  const [status, setStatus] = useState('pending'); // 'pending' | 'active'
  const [copied, setCopied] = useState(false);
  const [pollExpired, setPollExpired] = useState(false);
  const startedAtRef = useRef(Date.now());
  const POLL_INTERVAL_MS = 5000;
  const POLL_CAP_MS = 15 * 60 * 1000; // 15 min per Q8

  useEffect(() => {
    let cancelled = false;
    async function tick() {
      try {
        const res = await fetch('/signup/leads/' + encodeURIComponent(token) + '/payment-status');
        const data = await res.json();
        if (cancelled) return;
        if (data?.status === 'active') {
          setStatus('active');
          // Clear the lead token from storage now that we're activated.
          writeTokenToStorage(null);
          return;
        }
      } catch (e) { /* keep polling */ }
      if (cancelled) return;
      if (Date.now() - startedAtRef.current > POLL_CAP_MS) {
        setPollExpired(true);
        return;
      }
      setTimeout(tick, POLL_INTERVAL_MS);
    }
    tick();
    return () => { cancelled = true; };
  }, [token]);

  if (status === 'active') {
    return <ActivatedScreen firstName={firstName} botPhone={botPhone} />;
  }

  function copy() {
    if (!pix?.payload) return;
    navigator.clipboard.writeText(pix.payload).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2500);
    }).catch(() => {});
  }

  const qrSrc = pix?.encodedImage
    ? (pix.encodedImage.startsWith('data:') ? pix.encodedImage : 'data:image/png;base64,' + pix.encodedImage)
    : null;

  return (
    <div>
      <div style={styles.title}>Autorize o Pix Automático</div>
      <div style={styles.subtitle}>
        Escaneie o QR Code no app do seu banco. Seu banco vai pedir para autorizar
        a cobrança recorrente de R$100/mês — isso é o normal do Pix Automático.
      </div>

      {qrSrc && (
        <div style={step3Styles.qrContainer}>
          <img src={qrSrc} alt="QR Code Pix Automático" style={step3Styles.qrImage} />
        </div>
      )}

      {pix?.payload && (
        <>
          <div style={step3Styles.pixCode}>{pix.payload}</div>
          <button type="button" onClick={copy} style={step3Styles.copyBtn}>
            {copied ? '✓ Código copiado' : 'Copiar código Pix'}
          </button>
        </>
      )}

      <div style={step3Styles.instructions}>
        <strong>Como pagar:</strong>
        <ol style={step3Styles.instructionsList}>
          <li>Abra seu app bancário</li>
          <li>Escolha "Pagar com Pix" → "QR Code"</li>
          <li>Aponte para o QR ou cole o código acima</li>
          <li>Confirme o pagamento de R$100,00</li>
          <li><strong>Autorize a cobrança automática mensal</strong> quando o banco perguntar</li>
        </ol>
      </div>

      <div style={{ textAlign: 'center', margin: '12px 0' }}>
        <span style={step3Styles.statusPill}>
          {pollExpired ? '⏱ Aguardando há um tempo — você pode pagar mais tarde' : '⏳ Aguardando pagamento…'}
        </span>
      </div>

      <p style={styles.consent}>
        Você também receberá este código pelo WhatsApp. Já enviamos um link de
        acesso à plataforma — feche esta página com tranquilidade.
      </p>
    </div>
  );
}

// ─── Step 3c: Cartão hosted-checkout redirect ───────────────────────────────
// Same-tab redirect to ASAAS hosted checkout. When the user lands back on
// /signup (?status=cc) we render the polling screen.

function CreditCardRedirect({ invoiceUrl }) {
  const redirectedRef = useRef(false);
  useEffect(() => {
    if (redirectedRef.current) return;
    redirectedRef.current = true;
    // Mark that we're heading to the hosted checkout so a return visit can show the right screen
    try { sessionStorage.setItem('cb_signup_cc_started', '1'); } catch (e) {}
    // Small delay so the user sees the screen state before redirect
    setTimeout(() => { if (invoiceUrl) window.location.href = invoiceUrl; }, 800);
  }, [invoiceUrl]);

  return (
    <div>
      <div style={styles.title}>Redirecionando para o pagamento…</div>
      <div style={styles.subtitle}>
        Você será levado(a) para a página segura da ASAAS para inserir os dados do cartão.
      </div>
      <div style={{ textAlign: 'center', margin: '20px 0', color: '#888' }}>↻</div>
      {invoiceUrl && (
        <p style={styles.consent}>
          Se não redirecionar automaticamente,{' '}
          <a href={invoiceUrl} style={{ color: '#2D8A6B', fontWeight: 600 }}>clique aqui</a>.
        </p>
      )}
    </div>
  );
}

// ─── Step 3d: post-payment polling (return from Cartão hosted checkout) ─────

function CardReturnPolling({ token, firstName, botPhone }) {
  const [status, setStatus] = useState('pending');
  const [pollExpired, setPollExpired] = useState(false);
  const startedAtRef = useRef(Date.now());
  const POLL_INTERVAL_MS = 5000;
  const POLL_CAP_MS = 15 * 60 * 1000;

  useEffect(() => {
    let cancelled = false;
    async function tick() {
      try {
        const res = await fetch('/signup/leads/' + encodeURIComponent(token) + '/payment-status');
        const data = await res.json();
        if (cancelled) return;
        if (data?.status === 'active') {
          setStatus('active');
          writeTokenToStorage(null);
          try { sessionStorage.removeItem('cb_signup_cc_started'); } catch (e) {}
          return;
        }
      } catch (e) {}
      if (cancelled) return;
      if (Date.now() - startedAtRef.current > POLL_CAP_MS) {
        setPollExpired(true);
        return;
      }
      setTimeout(tick, POLL_INTERVAL_MS);
    }
    tick();
    return () => { cancelled = true; };
  }, [token]);

  if (status === 'active') {
    return <ActivatedScreen firstName={firstName} botPhone={botPhone} />;
  }

  return (
    <div>
      <div style={styles.title}>Confirmando seu pagamento…</div>
      <div style={styles.subtitle}>
        Estamos aguardando a confirmação do seu cartão. Isso costuma levar alguns segundos.
      </div>
      <div style={{ textAlign: 'center', margin: '24px 0' }}>
        <span style={step3Styles.statusPill}>
          {pollExpired ? '⏱ Está demorando — entre em contato se precisar' : '⏳ Aguardando confirmação…'}
        </span>
      </div>
      <p style={styles.consent}>
        Já enviamos um link de acesso à plataforma pelo WhatsApp.
      </p>
    </div>
  );
}

// ─── Activated success screen (both paths converge here) ────────────────────

function ActivatedScreen({ firstName, botPhone }) {
  const [showWhatsApp, setShowWhatsApp] = useState(false);
  useEffect(() => {
    const t = setTimeout(() => setShowWhatsApp(true), 60000); // 60s per Q8
    return () => clearTimeout(t);
  }, []);
  const cleanBot = (botPhone || '').replace(/\D/g, '');
  const waLink = cleanBot.length > 6
    ? ('https://wa.me/' + cleanBot + '?text=' + encodeURIComponent('login'))
    : null;
  return (
    <div style={{ textAlign: 'center' }}>
      <div style={{ fontSize: 48, marginBottom: 16 }}>🎉</div>
      <div style={{ ...styles.title, marginBottom: 8 }}>
        Conta ativada{firstName ? ', ' + firstName : ''}!
      </div>
      <div style={{ ...styles.subtitle, marginBottom: 24 }}>
        Sua Carimbou Premium está ativa. Próxima cobrança em 30 dias.
      </div>
      <div style={{ textAlign: 'center', margin: '16px 0' }}>
        <span style={{ ...step3Styles.statusPill, ...step3Styles.statusPillActive }}>
          ✓ Pagamento confirmado
        </span>
      </div>
      {showWhatsApp && waLink && (
        <a
          href={waLink}
          target="_blank"
          rel="noreferrer"
          style={{
            display: 'block',
            ...styles.btn,
            background: '#25D366',
            textDecoration: 'none',
            textAlign: 'center',
            marginTop: 16,
          }}
        >
          Entrar pelo WhatsApp
        </a>
      )}
      <p style={{ ...styles.consent, marginTop: 18 }}>
        Você também recebeu um link de acesso pelo WhatsApp.
      </p>
    </div>
  );
}

// ─── Initial-load resume / hydration helpers ────────────────────────────────

function readTokenFromUrl() {
  try {
    const params = new URLSearchParams(window.location.search);
    return params.get('lead') || null;
  } catch (e) { return null; }
}

function readTokenFromStorage() {
  try { return localStorage.getItem(LEAD_TOKEN_STORAGE_KEY); }
  catch (e) { return null; }
}

function writeTokenToStorage(token) {
  try {
    if (token) localStorage.setItem(LEAD_TOKEN_STORAGE_KEY, token);
    else       localStorage.removeItem(LEAD_TOKEN_STORAGE_KEY);
  } catch (e) {}
}

// Convert API lead shape into local form state, preserving display formatting
// on phones / CPF (server returns raw normalized data).
//
// Returns ONLY the keys the lead actually has populated. Used with object
// spread so that null/missing fields don't clobber a user's locally-typed
// values (e.g., user types step-2 fields, hits Voltar to step 1, then
// Continuar — the POST response carries only step-1 data, and we don't
// want to wipe their step-2 inputs).
//
// Booleans are always included because false is a meaningful value
// (consent unchecked, samePhone unchecked).
function leadToForm(lead) {
  const out = {};
  if (lead.businessName)          out.businessName = lead.businessName;
  if (lead.businessWhatsappPhone) out.businessWhatsappPhone = displayPhone(lead.businessWhatsappPhone);
  if (lead.personalWhatsappPhone) out.personalWhatsappPhone = displayPhone(lead.personalWhatsappPhone);
  if (lead.firstName)             out.firstName = lead.firstName;
  if (lead.lastName)              out.lastName = lead.lastName;
  if (lead.legalName)             out.legalName = lead.legalName;
  if (lead.cpfCnpj)               out.cpfCnpj = formatCpfCnpj(lead.cpfCnpj);
  if (lead.businessEmail)         out.businessEmail = lead.businessEmail;
  // Booleans: always echo what the server has (false means "explicitly unchecked")
  out.samePhone        = !!lead.samePhone;
  out.consentMessaging = !!lead.consentMessaging;
  out.consentTerms     = !!lead.consentTerms;
  return out;
}

const EMPTY_FORM = {
  businessName: '',
  businessWhatsappPhone: '',
  personalWhatsappPhone: '',
  samePhone: true,
  firstName: '',
  lastName: '',
  consentMessaging: false,
  consentTerms: false,
  legalName: '',
  cpfCnpj: '',
  businessEmail: '',
};

// ─── Wizard orchestrator ────────────────────────────────────────────────────

function SignupWizard() {
  const [step, setStep] = useState(1);
  const [token, setToken] = useState(null);
  const [form, setForm] = useState(EMPTY_FORM);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [hydrating, setHydrating] = useState(true);
  // Step 3 sub-state
  const [method, setMethod] = useState(null);                 // 'pix_automatic' | 'credit_card'
  const [step3Phase, setStep3Phase] = useState('picker');     // 'picker' | 'pix' | 'cc-redirect' | 'cc-return'
  const [pix, setPix] = useState(null);                       // { encodedImage, payload, authorizationId }
  const [convertedBusinessId, setConvertedBusinessId] = useState(null);
  const [lastStep3Error, setLastStep3Error] = useState(null);
  const botPhone = (typeof window !== 'undefined' && window.__BOT_PHONE__) || '';

  // Hydrate from URL ?lead= or localStorage on mount.
  useEffect(() => {
    let cancelled = false;
    async function hydrate() {
      const urlToken = readTokenFromUrl();
      const storageToken = readTokenFromStorage();
      const t = urlToken || storageToken;
      if (!t) { setHydrating(false); return; }
      try {
        const res = await fetch('/signup/leads/by-token/' + encodeURIComponent(t));
        if (!res.ok) {
          // Stale token (lead expired, was deleted, etc.) — drop it silently.
          writeTokenToStorage(null);
          if (!cancelled) setHydrating(false);
          return;
        }
        const data = await res.json();
        if (cancelled) return;
        if (data?.lead) {
          setToken(data.lead.token);
          writeTokenToStorage(data.lead.token);
          setForm(leadToForm(data.lead));
          setStep(Math.min(data.lead.currentStep || 1, 3));
          if (data.lead.lastStep3Error) setLastStep3Error(data.lead.lastStep3Error);
          // If the user is returning from the Cartão hosted checkout, show
          // the polling-for-activation screen instead of the picker.
          let ccStarted = false;
          try { ccStarted = sessionStorage.getItem('cb_signup_cc_started') === '1'; } catch (e) {}
          if (data.lead.convertedBusinessId) {
            setConvertedBusinessId(data.lead.convertedBusinessId);
            setStep(3);
            setStep3Phase(ccStarted ? 'cc-return' : 'cc-return');
          }
        }
      } catch (e) {
        // network error during hydration — fall back to fresh start
        console.error('[signup] hydrate failed:', e);
      } finally {
        if (!cancelled) setHydrating(false);
      }
    }
    hydrate();
    return () => { cancelled = true; };
  }, []);

  async function submitStep1() {
    setError(null);
    setLoading(true);
    try {
      const body = {
        businessName:           form.businessName,
        businessWhatsappPhone:  form.businessWhatsappPhone.replace(/\D/g, ''),
        personalWhatsappPhone:  form.samePhone ? '' : form.personalWhatsappPhone.replace(/\D/g, ''),
        samePhone:              !!form.samePhone,
        firstName:              form.firstName,
        lastName:               form.lastName,
        consentMessaging:       !!form.consentMessaging,
        consentTerms:           !!form.consentTerms,
      };
      const res = await fetch('/signup/leads', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      });
      const data = await res.json();
      if (!res.ok) {
        setError(data.error || 'Erro ao salvar. Tente novamente.');
        return;
      }
      // Backend's currentStep represents "next screen to show".
      // After step 1 it's >=2, after step 2 it's 3.
      setToken(data.lead.token);
      writeTokenToStorage(data.lead.token);
      setForm(f => ({ ...f, ...leadToForm(data.lead) }));
      setStep(Math.min(data.lead.currentStep || 2, 3));
    } catch (e) {
      setError('Erro de conexão. Verifique sua internet e tente novamente.');
    } finally {
      setLoading(false);
    }
  }

  async function submitStep2() {
    if (!token) { setError('Sessão expirou. Recarregue a página.'); return; }
    setError(null);
    setLoading(true);
    try {
      const body = {
        legalName:     form.legalName,
        cpfCnpj:       form.cpfCnpj.replace(/\D/g, ''),
        businessEmail: form.businessEmail,
      };
      const res = await fetch('/signup/leads/' + encodeURIComponent(token), {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      });
      const data = await res.json();
      if (!res.ok) {
        setError(data.error || 'Erro ao salvar. Tente novamente.');
        return;
      }
      setForm(f => ({ ...f, ...leadToForm(data.lead) }));
      setStep(Math.min(data.lead.currentStep || 2, 3));
    } catch (e) {
      setError('Erro de conexão. Verifique sua internet e tente novamente.');
    } finally {
      setLoading(false);
    }
  }

  async function submitStep3() {
    if (!token) { setError('Sessão expirou. Recarregue a página.'); return; }
    if (!method) { setError('Escolha uma forma de pagamento.'); return; }
    setError(null);
    setLoading(true);
    try {
      const res = await fetch('/signup/leads/' + encodeURIComponent(token) + '/step3', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ method }),
      });
      const data = await res.json();
      if (!res.ok) {
        setError(data.error || 'Erro ao processar pagamento. Tente novamente.');
        if (data?.lastError) setLastStep3Error(data.lastError);
        return;
      }
      setConvertedBusinessId(data.businessId);
      setLastStep3Error(null);
      if (data.method === 'pix_automatic') {
        setPix(data.pix);
        setStep3Phase('pix');
      } else {
        if (data.creditCard?.invoiceUrl) {
          // Render the redirect screen — it kicks the same-tab redirect on mount.
          // When the user returns to /signup later, hydration sets phase='cc-return'.
          setStep3Phase('cc-redirect');
          // Cache the invoice URL on the form state for the CC redirect component
          setForm(f => ({ ...f, _ccInvoiceUrl: data.creditCard.invoiceUrl }));
        } else {
          setError('A assinatura foi criada mas não conseguimos gerar o link de pagamento. Recarregue a página.');
        }
      }
    } catch (e) {
      setError('Erro de conexão. Verifique sua internet e tente novamente.');
    } finally {
      setLoading(false);
    }
  }

  function goBack() {
    setError(null);
    if (step === 3 && step3Phase !== 'picker') {
      // From inside a step-3 sub-screen, back returns to the picker
      setStep3Phase('picker');
      return;
    }
    setStep(s => Math.max(1, s - 1));
  }

  if (hydrating) {
    return (
      <div style={styles.page}>
        <div style={styles.logo}>Carimbou</div>
        <div style={{ ...styles.card, textAlign: 'center', color: '#888' }}>
          Carregando…
        </div>
      </div>
    );
  }

  return (
    <div style={styles.page}>
      <div style={styles.logo}>Carimbou</div>
      <div style={styles.card}>
        <ProgressDots step={step} />
        {step === 1 && (
          <Step1
            form={form}
            setForm={setForm}
            onSubmit={submitStep1}
            loading={loading}
            error={error}
          />
        )}
        {step === 2 && (
          <Step2
            form={form}
            setForm={setForm}
            onSubmit={submitStep2}
            onBack={goBack}
            loading={loading}
            error={error}
          />
        )}
        {step === 3 && step3Phase === 'picker' && (
          <Step3Picker
            method={method}
            setMethod={setMethod}
            onSubmit={submitStep3}
            onBack={goBack}
            loading={loading}
            error={error}
            lastStep3Error={lastStep3Error}
          />
        )}
        {step === 3 && step3Phase === 'pix' && (
          <PixAuthScreen
            pix={pix}
            token={token}
            firstName={form.firstName}
            businessId={convertedBusinessId}
            botPhone={botPhone}
          />
        )}
        {step === 3 && step3Phase === 'cc-redirect' && (
          <CreditCardRedirect invoiceUrl={form._ccInvoiceUrl} />
        )}
        {step === 3 && step3Phase === 'cc-return' && (
          <CardReturnPolling
            token={token}
            firstName={form.firstName}
            botPhone={botPhone}
          />
        )}
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(React.createElement(SignupWizard));
