/* global React, ReactDOM, Icon, Button, Badge, Card, Field, brl, fmtDatetime */

// ─── Mercado Pago — Fase 1: Pix + link de pagamento ──────────────────────────
// O objetivo não é "aceitar pagamento": é o título baixar SOZINHO. A Erica gera
// o Pix/link daqui, manda pro cliente pelo WhatsApp, e quando ele paga o
// webhook dá a baixa com valor, taxa, conta e data certos.
//
// Segurança: este arquivo NÃO conhece o Access Token. Ele cria a linha em
// `cobrancas` (RLS, usuário logado) e pede pro mercadopago-proxy fazer o resto.

const MP_CHIP = {
  // status da cobrança → chip na tela de Contas a Receber
  pix_pendente:    { l: 'Pix gerado',            tone: 'info'    },
  link_pendente:   { l: 'Link enviado',          tone: 'info'    },
  boleto_pendente: { l: 'Boleto enviado',        tone: 'info'    },
  pago:            { l: 'Pago via Mercado Pago', tone: 'success' },
};

function mpChipDe(cobranca) {
  if (!cobranca) return null;
  if (cobranca.status === 'pago') return MP_CHIP.pago;
  if (cobranca.status === 'pendente') {
    if (cobranca.metodo === 'pix') return MP_CHIP.pix_pendente;
    if (cobranca.metodo === 'boleto') return MP_CHIP.boleto_pendente;
    return MP_CHIP.link_pendente;
  }
  return null;   // expirado / cancelado / estornado não poluem a listagem
}

// Desdobramento do pagamento MP: Cobrado · Taxa · Líquido. Só APRESENTAÇÃO —
// o banco continua com valor cheio no título e taxa como despesa (regra da
// casa). Se taxa_mp é null (pagamento antigo ou não-MP), não renderiza nada.
function mpDesdobramentoDe(cobranca) {
  if (!cobranca || cobranca.status !== 'pago') return null;
  const taxa = cobranca.taxaMp;
  if (taxa === null || taxa === undefined) return null;
  const cobrado = Number(cobranca.valorPago != null ? cobranca.valorPago : cobranca.valor) || 0;
  const liquido = cobrado - (Number(taxa) || 0);
  return { cobrado, taxa: Number(taxa) || 0, liquido,
    texto: `Cobrado R$ ${brl(cobrado)} · Taxa MP − R$ ${brl(taxa)} · Líquido R$ ${brl(liquido)}` };
}

function MpDesdobramento({ cobranca }) {
  const d = mpDesdobramentoDe(cobranca);
  if (!d) return null;
  return (
    <div className="mp-desdobra">
      <span>Cobrado <b>R$ {brl(d.cobrado)}</b></span>
      <span className="mp-desdobra-taxa">Taxa MP <b>&minus; R$ {brl(d.taxa)}</b></span>
      <span className="mp-desdobra-liq">L&iacute;quido <b>R$ {brl(d.liquido)}</b></span>
    </div>
  );
}

function MpChip({ cobranca }) {
  const chip = mpChipDe(cobranca);
  if (!chip) return null;
  const d = mpDesdobramentoDe(cobranca);
  // Pago com taxa conhecida: o chip carrega o líquido; o hover conta a conta inteira.
  if (d) {
    return (
      <span title={d.texto}>
        <Badge tone={chip.tone}>Pago via MP &middot; l&iacute;q. R$ {brl(d.liquido)}</Badge>
      </span>
    );
  }
  return <Badge tone={chip.tone}>{chip.l}</Badge>;
}

const mpUsuario = () => {
  const p = window.tmUserProfile || {};
  return p.nome || p.name || (window.tmUser && window.tmUser.email) || '';
};

const mpFmtValidade = (iso) => iso ? (fmtDatetime(iso) || String(iso).slice(0, 16).replace('T', ' ')) : '';

// A URL da página de pagamento com a marca da TopMix (Fase 2b). É o link que
// vai no WhatsApp — o cliente paga sem nunca ver a cara do Mercado Pago.
const mpUrlPagina = (cobranca) =>
  cobranca && cobranca.publicToken ? `https://app.topmixprofissional.com/pagar/${cobranca.publicToken}` : '';

// "A língua do cliente": título de pedido vira "o pedido 7482 (parcela 2/3)" —
// "título COB-260826-1657" é código interno e o cliente estranha. Sem pedido,
// a referência continua.
function mpNomeCobranca(titulo) {
  const ped = titulo.ped || titulo.pedido_ref;
  if (ped) {
    const total = titulo.total_parcelas || titulo.totalParcelas || 1;
    const parc = titulo.parc || titulo.parcela;
    const parcTxt = total > 1
      ? ` (parcela ${titulo.numero_parcela || titulo.numParcela || String(parc || '').split('/')[0] || 1}/${total})`
      : (parc && /\//.test(String(parc)) && String(parc) !== '1/1' ? ` (parcela ${parc})` : '');
    return `do pedido ${ped}${parcTxt}`;
  }
  const ref = titulo.ref || titulo.referencia;
  return ref ? `do título ${ref}` : 'da cobrança';
}

// A mensagem que a Erica cola no WhatsApp — é assim que isto vai ser usado de
// verdade. Texto completo: valor, referência e o código/link prontos.
function mpMensagemWhats(metodo, titulo, cobranca) {
  const cliente = (titulo.cli || titulo.cliente_nome || '').split(' ')[0];
  const ola = cliente ? `Olá, ${cliente}!` : 'Olá!';
  const de = mpNomeCobranca(titulo);
  const valor = `R$ ${brl(cobranca.valor)}`;
  const pagina = mpUrlPagina(cobranca);
  if (metodo === 'pix') {
    const abraLa = pagina ? `\n\nOu abra e pague por aqui: ${pagina}` : '';
    return `${ola} Segue o Pix pra pagamento ${de} — ${valor}.\n\n` +
      `Pix copia e cola:\n${cobranca.mpQrCode}${abraLa}\n\n` +
      `Vale até ${mpFmtValidade(cobranca.expiraEm)}. Qualquer dúvida, me chama!`;
  }
  if (metodo === 'boleto') {
    const linha = cobranca.mpBoletoLinha ? `\n\nLinha digitável:\n${cobranca.mpBoletoLinha}` : '';
    return `${ola} Segue o boleto ${de} — ${valor}.\n\n` +
      `Boleto: ${pagina || cobranca.mpBoletoUrl}${linha}\n\n` +
      `Vencimento: ${mpFmtValidade(cobranca.expiraEm).slice(0, 10)}. Qualquer dúvida, me chama!`;
  }
  // método "link": o WhatsApp aponta pra NOSSA página (o Checkout Pro do MP
  // continua existindo por trás como fallback interno — não foi removido)
  return `${ola} Segue o link pra pagamento ${de} — ${valor}:\n${pagina || cobranca.mpLinkUrl}\n\n` +
    `Qualquer dúvida, me chama!`;
}

// ── Modal CENTRAL (pedido de UX da Naii) ─────────────────────────────────────
// Cobrança é momento de foco: cliente na frente, não painel lateral. Mesma
// anatomia do Drawer (eyebrow/título/subtítulo/corpo/rodapé) pra troca ser
// indolor, mas centralizado na tela. ESC e clique no fundo fecham.
function MpModalCentral({ eyebrow, titulo, subtitulo, footer, onClose, largura = 500, children }) {
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose && onClose(); };
    document.addEventListener('keydown', onKey);
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = prev; };
  }, [onClose]);
  return ReactDOM.createPortal(
    <div className="mp-central-overlay" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="mp-central" style={{ maxWidth: largura }}>
        <div className="mp-central-head">
          <div style={{ flex: 1 }}>
            {eyebrow && <div className="mp-central-eyebrow">{eyebrow}</div>}
            <div className="mp-central-titulo">{titulo}</div>
            {subtitulo && <div className="mp-central-sub">{subtitulo}</div>}
          </div>
          <Button variant="ghost" size="sm" icon="x" onClick={onClose} />
        </div>
        <div className="mp-central-body">{children}</div>
        {footer && <div className="mp-central-foot">{footer}</div>}
      </div>
    </div>,
    document.body
  );
}

// Botão de copiar com feedback — usado pro copia-e-cola, pro link e pra mensagem.
function MpBotaoCopiar({ texto, rotulo, icone = 'copy', variant = 'secondary' }) {
  const [copiado, setCopiado] = React.useState(false);
  const copiar = async () => {
    try { await navigator.clipboard.writeText(texto); }
    catch (e) {
      const ta = document.createElement('textarea');
      ta.value = texto; document.body.appendChild(ta); ta.select();
      document.execCommand('copy'); ta.remove();
    }
    setCopiado(true); setTimeout(() => setCopiado(false), 2000);
  };
  return (
    <Button variant={variant} size="sm" icon={copiado ? 'check' : icone} onClick={copiar}>
      {copiado ? 'Copiado!' : rotulo}
    </Button>
  );
}

// ── O modal de cobrança (Pix ou link) ────────────────────────────────────────
// Fluxo: cria/reabre a cobrança em `cobrancas` → pede o Pix/link ao proxy →
// mostra QR + copia-e-cola + mensagem de WhatsApp. Se já havia uma cobrança
// pendente do mesmo título, REABRE a existente (aviso na tela) em vez de criar
// outra — dois QRs ativos pro mesmo título é receita de pagamento em dobro.
function CobrancaMpModal({ titulo, metodo, parcelas, onClose, onMudou }) {
  const [fase, setFase] = React.useState('criando');   // criando | pagador | trocar | pronto | erro
  const [metodoAtivo, setMetodoAtivo] = React.useState(metodo);
  const [cobranca, setCobranca] = React.useState(null);
  const [reaberta, setReaberta] = React.useState(false);
  const [erro, setErro] = React.useState('');
  const [trocando, setTrocando] = React.useState(false);
  // boleto: dados do pagador (pré-preenchidos do cadastro; ela completa o resto)
  const [pagador, setPagador] = React.useState(null);
  // troca de método: a cobrança pendente de OUTRO método que precisa morrer antes
  const [troca, setTroca] = React.useState(null);

  // `m` explícito porque a troca de método chama gerar logo após setMetodoAtivo
  // (o estado ainda não virou no closure). `aposTroca` pula a re-detecção.
  const gerar = React.useCallback(async (forcarNova, dadosPagador, m, aposTroca) => {
    const met = m || metodoAtivo;
    setFase('criando'); setErro('');
    try {
      if (forcarNova && cobranca) {
        await window.mpApi.cancelar(cobranca.id);
        onMudou && onMudou();
      }
      // INVARIANTE: nunca duas cobranças pendentes do mesmo título. Pendente de
      // OUTRO método (o cenário "boleto vencido, cliente quer Pix na hora") →
      // oferece a troca: cancelar → criar, nessa ordem, com confirmação.
      if (!aposTroca && !forcarNova) {
        const pendentes = await window.tmDb.cobrancasPendentesDoTitulo(titulo.id);
        const outra = pendentes.find(c => c.metodo !== met);
        if (outra) { setTroca(outra); setMetodoAtivo(met); setFase('trocar'); return; }
      }
      const r = await window.tmDb.criarCobranca({
        contaReceberId: titulo.id, pedidoId: titulo.pedido_id || null,
        metodo: met, valor: titulo.valor, criadoPor: mpUsuario(),
        ...(parcelas || {}),           // escolhido no form; sem ele, o global entra no criarCobranca
        ...(dadosPagador || {}),
      });
      if (r.error) throw r.error;
      let cob = r.cobranca;
      const jaGerada = met === 'pix' ? !!cob.mpQrCode : met === 'boleto' ? !!cob.mpBoletoUrl : !!cob.mpLinkUrl;
      setReaberta(!forcarNova && r.jaExistia && jaGerada);

      if (!jaGerada) {
        if (met === 'boleto' && !dadosPagador) {
          // Boleto registrado exige pagador (lei do boleto). Primeiro tenta o
          // cadastro do cliente; o que faltar, ela completa aqui — e a
          // cobrança guarda (aí vale completar o cadastro depois).
          const pre = await window.tmDb.pagadorDoCadastro(titulo.cli || titulo.cliente_nome || '');
          setPagador({
            pagadorNome: cob.pagadorNome || pre.pagadorNome || titulo.cli || titulo.cliente_nome || '',
            pagadorDoc: cob.pagadorDoc || pre.pagadorDoc || '',
            pagadorEmail: pre.pagadorEmail || '', pagadorCep: pre.pagadorCep || '',
            pagadorEndereco: pre.pagadorEndereco || '', pagadorNumero: pre.pagadorNumero || '',
            pagadorBairro: pre.pagadorBairro || '', pagadorCidade: pre.pagadorCidade || '',
            pagadorUf: pre.pagadorUf || '',
          });
          setCobranca(cob); setFase('pagador');
          return;
        }
        if (metodo === 'pix') await window.mpApi.gerarPix(cob.id);
        else if (metodo === 'boleto') await window.mpApi.gerarBoleto(cob.id, (titulo.vencimento || '').slice(0, 10) || null);
        else await window.mpApi.gerarLink(cob.id);
        const rec = await window.tmDb.loadCobranca(cob.id);
        if (rec.error) throw rec.error;
        cob = rec.cobranca;
      }
      setCobranca(cob); setFase('pronto');
      onMudou && onMudou();
    } catch (e) {
      setErro(e.message || String(e));
      // erro na geração do boleto volta pro form do pagador (corrigir e tentar)
      if (met === 'boleto' && dadosPagador) { setFase('pagador'); return; }
      setFase('erro');
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [titulo.id, metodoAtivo, cobranca]);

  React.useEffect(() => { gerar(false); }, []);   // eslint-disable-line react-hooks/exhaustive-deps

  // Se ela deixar o modal aberto enquanto o cliente paga, a confirmação chega
  // sozinha: a cada 8s relemos a cobrança; o webhook é quem muda o status.
  React.useEffect(() => {
    if (fase !== 'pronto' || !cobranca || cobranca.status !== 'pendente') return;
    const t = setInterval(async () => {
      const r = await window.tmDb.loadCobranca(cobranca.id);
      if (!r.error && r.cobranca.status !== 'pendente') {
        setCobranca(r.cobranca);
        onMudou && onMudou();
      }
    }, 8000);
    return () => clearInterval(t);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [fase, cobranca && cobranca.id, cobranca && cobranca.status]);

  const trocarPorNova = async () => { setTrocando(true); await gerar(true); setTrocando(false); };

  const ehPix = metodoAtivo === 'pix';
  const ehBoleto = metodoAtivo === 'boleto';
  const NOME_METODO = { pix: 'Pix', boleto: 'boleto', link: 'link de pagamento' };
  // troca a partir do modal da pendente: gerar() detecta a pendente atual e
  // cai na confirmação da fase 'trocar' — cancelar -> criar, sempre nessa ordem
  const trocarMetodo = (novo) => { setMetodoAtivo(novo); setReaberta(false); gerar(false, null, novo); };
  const confirmarTroca = async () => {
    setTrocando(true); setErro('');
    try {
      await window.mpApi.cancelar(troca.id);   // se falhar, NAO cria a nova
      onMudou && onMudou();
      setTroca(null);
      await gerar(false, null, metodoAtivo, true);
    } catch (e) {
      setErro('A cobrança atual não foi cancelada — nada foi criado. ' + (e.message || ''));
      setFase('trocar');
    }
    setTrocando(false);
  };
  const tituloModal = ehPix ? 'Cobrar via Pix' : ehBoleto ? 'Boleto bancário' : 'Link de pagamento';
  const ref = titulo.ref || titulo.referencia || '—';
  const setPg = (campo) => (e) => setPagador(p => ({ ...p, [campo]: e.target.value }));

  return (
    <MpModalCentral onClose={onClose} largura={480}
      eyebrow={`Título ${ref}`} titulo={tituloModal}
      subtitulo={`${titulo.cli || titulo.cliente_nome || ''} · R$ ${brl(titulo.valor)}`}
      footer={<>
        <Button variant="secondary" onClick={onClose}>Fechar</Button>
        {fase === 'pagador' && (
          <Button variant="primary" icon="barcode" onClick={() => gerar(false, pagador)}>Gerar boleto</Button>
        )}
      </>}>

      {fase === 'criando' && (
        <div className="mp-carregando"><Icon name="loader-2" size={18} /> Gerando cobrança no Mercado Pago…</div>
      )}

      {fase === 'erro' && (
        <div className="bal-aviso danger">
          <Icon name="alert-circle" size={15} />
          <div>
            <b>Não foi possível gerar a cobrança.</b>
            <div style={{ marginTop: 4 }}>{erro}</div>
            <div style={{ marginTop: 8 }}>
              <Button variant="secondary" size="sm" icon="rotate-ccw" onClick={() => gerar(false)}>Tentar de novo</Button>
            </div>
          </div>
        </div>
      )}

      {/* TROCA DE MÉTODO: já existe cobrança pendente de outro método deste
          título. Nunca duas pendentes — a troca é cancelar → criar, nessa ordem. */}
      {fase === 'trocar' && troca && (
        <>
          {erro && <div className="bal-aviso danger"><Icon name="alert-circle" size={15} /><span>{erro}</span></div>}
          <div className="bal-aviso warning">
            <Icon name="alert-triangle" size={15} />
            <div>
              Este título já tem <b>{NOME_METODO[troca.metodo] || troca.metodo}</b> pendente
              {troca.metodo === 'boleto' && troca.expiraEm ? ` (vence ${mpFmtValidade(troca.expiraEm).slice(0, 10)})` : ''}.
              <div style={{ marginTop: 4 }}>
                Gerar {NOME_METODO[metodoAtivo]} <b>cancela a cobrança atual</b> no Mercado Pago —
                o cliente não consegue mais pagar por ela. Uma cobrança ativa por título, sempre.
              </div>
              <div style={{ marginTop: 8, display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                <Button variant="primary" size="sm" icon="rotate-ccw" disabled={trocando} onClick={confirmarTroca}>
                  {trocando ? 'Trocando…' : `Cancelar e gerar ${NOME_METODO[metodoAtivo]}`}
                </Button>
                <Button variant="secondary" size="sm" disabled={trocando}
                  onClick={() => { setTroca(null); setMetodoAtivo(troca.metodo); gerar(false, null, troca.metodo, true); }}>
                  Manter {NOME_METODO[troca.metodo]}
                </Button>
              </div>
            </div>
          </div>
        </>
      )}

      {/* BOLETO: os dados do pagador vêm primeiro (exigência do boleto registrado) */}
      {fase === 'pagador' && pagador && (
        <>
          <div className="bal-nota" style={{ marginBottom: 10 }}>
            Boleto registrado exige CPF/CNPJ e endereço do pagador — é regra do boleto.
            O que veio do cadastro já está preenchido; complete o resto (e depois vale
            completar o cadastro do cliente).
          </div>
          {erro && <div className="bal-aviso danger"><Icon name="alert-circle" size={15} /><span>{erro}</span></div>}
          <div className="field-grid-2">
            <Field label="Nome / Razão social">
              <input className="input" value={pagador.pagadorNome} onChange={setPg('pagadorNome')} />
            </Field>
            <Field label="CPF ou CNPJ">
              <input className="input" value={pagador.pagadorDoc} onChange={setPg('pagadorDoc')} placeholder="Só números" />
            </Field>
          </div>
          <Field label="E-mail (opcional)">
            <input className="input" value={pagador.pagadorEmail} onChange={setPg('pagadorEmail')} />
          </Field>
          <div className="field-grid-2">
            <Field label="CEP"><input className="input" value={pagador.pagadorCep} onChange={setPg('pagadorCep')} /></Field>
            <Field label="Número"><input className="input" value={pagador.pagadorNumero} onChange={setPg('pagadorNumero')} placeholder="S/N se não tiver" /></Field>
          </div>
          <Field label="Endereço (rua)">
            <input className="input" value={pagador.pagadorEndereco} onChange={setPg('pagadorEndereco')} />
          </Field>
          <div className="field-grid-2">
            <Field label="Bairro"><input className="input" value={pagador.pagadorBairro} onChange={setPg('pagadorBairro')} /></Field>
            <Field label="Cidade"><input className="input" value={pagador.pagadorCidade} onChange={setPg('pagadorCidade')} /></Field>
          </div>
          <Field label="UF">
            <input className="input" style={{ maxWidth: 80 }} maxLength={2} value={pagador.pagadorUf} onChange={setPg('pagadorUf')} placeholder="MT" />
          </Field>
        </>
      )}

      {/* PAGO com o modal aberto: a confirmação toma o lugar do QR */}
      {fase === 'pronto' && cobranca && cobranca.status === 'pago' && (
        <div className="mp-pago-box">
          <Icon name="check-circle-2" size={34} />
          <div className="mp-pago-titulo">Pagamento recebido!</div>
          <MpDesdobramento cobranca={cobranca} />
          <div className="bal-nota" style={{ textAlign: 'center' }}>
            O título já foi baixado e a taxa lançada — nada pra fazer na mão.
          </div>
        </div>
      )}

      {fase === 'pronto' && cobranca && cobranca.status !== 'pago' && (
        <>
          {reaberta && (
            <div className="bal-aviso info">
              <Icon name="info" size={15} />
              <div>
                Já havia uma cobrança {ehPix ? 'Pix' : ehBoleto ? 'de boleto' : 'por link'} <b>pendente</b> deste título —
                reabri a existente em vez de criar outra.
                <div style={{ marginTop: 6 }}>
                  <Button variant="ghost" size="sm" icon="rotate-ccw" disabled={trocando} onClick={trocarPorNova}>
                    {trocando ? 'Gerando…' : 'Cancelar esta e gerar nova'}
                  </Button>
                </div>
              </div>
            </div>
          )}

          {ehPix ? (
            <>
              {cobranca.mpQrCodeBase64
                ? <div className="mp-qr-box">
                    <img alt="QR Code Pix" src={`data:image/png;base64,${cobranca.mpQrCodeBase64}`} />
                  </div>
                : <div className="bal-nota">O MP não mandou a imagem do QR — use o copia-e-cola abaixo.</div>}

              <div className="mp-valor-linha">
                <span>R$ {brl(cobranca.valor)}</span>
                {cobranca.expiraEm && <span className="muted">vale até {mpFmtValidade(cobranca.expiraEm)}</span>}
              </div>

              <Field label="Pix copia e cola">
                <textarea className="input mp-copia-cola" readOnly value={cobranca.mpQrCode || ''} rows={4}
                  onFocus={e => e.target.select()} />
              </Field>
              <div className="mp-acoes">
                <MpBotaoCopiar texto={cobranca.mpQrCode || ''} rotulo="Copiar código" />
                <MpBotaoCopiar variant="primary" icone="message-circle" rotulo="Copiar mensagem pro WhatsApp"
                  texto={mpMensagemWhats('pix', titulo, cobranca)} />
              </div>
            </>
          ) : ehBoleto ? (
            <>
              <div className="mp-valor-linha">
                <span>R$ {brl(cobranca.valor)}</span>
                {cobranca.expiraEm && <span className="muted">vence em {mpFmtValidade(cobranca.expiraEm).slice(0, 10)}</span>}
              </div>
              {cobranca.mpBoletoLinha && (
                <Field label="Linha digitável">
                  <textarea className="input mp-copia-cola" readOnly value={cobranca.mpBoletoLinha} rows={2}
                    onFocus={e => e.target.select()} />
                </Field>
              )}
              <div className="mp-acoes">
                <Button variant="secondary" size="sm" icon="external-link"
                  onClick={() => window.open(cobranca.mpBoletoUrl, '_blank')}>Abrir boleto (PDF)</Button>
                {cobranca.mpBoletoLinha && <MpBotaoCopiar texto={cobranca.mpBoletoLinha} rotulo="Copiar linha" />}
                <MpBotaoCopiar variant="primary" icone="message-circle" rotulo="Copiar mensagem pro WhatsApp"
                  texto={mpMensagemWhats('boleto', titulo, cobranca)} />
              </div>
              <div className="bal-nota">Boleto compensa em 1–2 dias úteis depois do pagamento — a baixa vem quando compensar.</div>
            </>
          ) : (
            <>
              <div className="mp-valor-linha"><span>R$ {brl(cobranca.valor)}</span></div>
              <Field label="Link de pagamento">
                <input className="input" readOnly value={cobranca.mpLinkUrl || ''} onFocus={e => e.target.select()} />
              </Field>
              <div className="mp-acoes">
                <MpBotaoCopiar texto={cobranca.mpLinkUrl || ''} rotulo="Copiar link" />
                <MpBotaoCopiar variant="primary" icone="message-circle" rotulo="Copiar mensagem pro WhatsApp"
                  texto={mpMensagemWhats('link', titulo, cobranca)} />
              </div>
              <div className="bal-nota">O cliente abre o link e escolhe como pagar na página do Mercado Pago.</div>
            </>
          )}

          {/* Trocar de método sem sair do modal — o cenário "boleto vencido,
              cliente quer pagar por Pix na hora" */}
          <div className="mp-trocar-linha">
            <span className="muted">Trocar pra:</span>
            {['pix', 'boleto', 'link'].filter(m => m !== metodoAtivo).map(m => (
              <Button key={m} variant="ghost" size="sm"
                icon={m === 'pix' ? 'qr-code' : m === 'boleto' ? 'barcode' : 'link'}
                onClick={() => trocarMetodo(m)}>
                {NOME_METODO[m]}
              </Button>
            ))}
          </div>

          <div className="bal-nota" style={{ marginTop: 10 }}>
            Quando o cliente pagar, o título baixa <b>sozinho</b>: Recebido pelo valor cheio na
            conta Mercado Pago, com a taxa lançada como despesa. Nada pra marcar na mão.
          </div>
        </>
      )}
    </MpModalCentral>
  );
}

// ── Nova cobrança — o fluxo que a Erica vai usar de verdade ──────────────────
// Feedback do primeiro uso real: "Lançar título" é um formulário genérico com
// campos de baixa manual, e o "Cobrar via Pix" escondido na linha só se
// descobre depois. Este form pergunta SÓ o que a cobrança precisa (cliente,
// valor, vencimento), cria o título — que nasce Em aberto por definição, sem
// status/valor recebido/data de pagamento na tela — e já abre o modal do
// Pix/link em seguida. O "Lançar título" continua existindo pro lançamento
// manual completo.
function NovaCobrancaForm({ clientes, onClose, onCriada }) {
  const hoje = new Date();
  const refPadrao = 'COB-' + hoje.toISOString().slice(2, 10).replace(/-/g, '') + '-' +
    String(hoje.getHours()).padStart(2, '0') + String(hoje.getMinutes()).padStart(2, '0');
  const [cliente, setCliente] = React.useState('');
  const [valor, setValor] = React.useState('');
  const [venc, setVenc] = React.useState(hoje.toISOString().slice(0, 10));
  const [referencia, setReferencia] = React.useState(refPadrao);
  const [erro, setErro] = React.useState('');
  const [salvando, setSalvando] = React.useState(null);   // 'pix' | 'link' enquanto grava
  // parcelamento no cartão da página pública: decisão de quem cobra,
  // pré-preenchido do padrão global (Configurações › Pagamentos)
  const [parcMax, setParcMax] = React.useState(1);
  const [parcSemJuros, setParcSemJuros] = React.useState(1);
  React.useEffect(() => {
    let vivo = true;
    window.tmDb.configPagamentos().then(g => {
      if (vivo) { setParcMax(g.parcelasMax); setParcSemJuros(g.parcelasSemJuros); }
    });
    return () => { vivo = false; };
  }, []);

  const sugestoes = React.useMemo(() => {
    const q = cliente.trim().toLowerCase();
    if (!q || q.length < 2) return [];
    return (clientes || []).filter(n => n.toLowerCase().includes(q) && n.toLowerCase() !== q).slice(0, 6);
  }, [cliente, clientes]);

  const gerar = async (metodo) => {
    const v = Number(String(valor).replace(',', '.'));
    if (!cliente.trim()) { setErro('Diga de quem é a cobrança.'); return; }
    if (!(v > 0)) { setErro('Valor precisa ser maior que zero.'); return; }
    setErro(''); setSalvando(metodo);
    const r = await window.tmDb.criarTituloCobranca({
      cliente_nome: cliente.trim(), valor: v, vencimento: venc,
      referencia: referencia.trim() || null,
      forma_pagamento: metodo === 'pix' ? 'Pix' : metodo === 'boleto' ? 'Boleto' : '',
    });
    setSalvando(null);
    if (r.error) { setErro(r.error.message || 'Não foi possível criar o título.'); return; }
    onCriada(r.titulo, metodo, { parcelasMax: parcMax, parcelasSemJuros: parcSemJuros });
  };

  return (
    <MpModalCentral onClose={onClose} largura={460}
      eyebrow="Contas a Receber" titulo="Nova cobrança"
      subtitulo="Cria o título e já gera o Pix ou o link. A baixa vem sozinha quando o cliente pagar."
      footer={<>
        <Button variant="secondary" onClick={onClose}>Cancelar</Button>
        <Button variant="secondary" icon="link" disabled={!!salvando} onClick={() => gerar('link')}>
          {salvando === 'link' ? 'Criando…' : 'Gerar link'}
        </Button>
        <Button variant="secondary" icon="barcode" disabled={!!salvando} onClick={() => gerar('boleto')}>
          {salvando === 'boleto' ? 'Criando…' : 'Gerar boleto'}
        </Button>
        <Button variant="primary" icon="qr-code" disabled={!!salvando} onClick={() => gerar('pix')}>
          {salvando === 'pix' ? 'Criando…' : 'Gerar Pix'}
        </Button>
      </>}>

      {erro && <div className="bal-aviso danger"><Icon name="alert-circle" size={15} /><span>{erro}</span></div>}

      <Field label="Cliente" value={cliente}
        onChange={v => setCliente(typeof v === 'string' ? v : v.target.value)}
        placeholder="Nome de quem vai pagar" />
      {sugestoes.length > 0 && (
        <div className="bal-sugestoes">
          {sugestoes.map(n => (
            <div key={n} className="bal-sugestao" onClick={() => setCliente(n)}>
              <Icon name="user" size={13} /><span className="bal-sug-nome">{n}</span>
            </div>
          ))}
        </div>
      )}

      <div className="field-grid-2">
        <Field label="Valor (R$)" value={valor}
          onChange={v => setValor(typeof v === 'string' ? v : v.target.value)}
          placeholder="0,00" />
        <Field label="Vencimento">
          <input className="input" type="date" value={venc} onChange={e => setVenc(e.target.value)} />
        </Field>
      </div>

      <Field label="Referência" value={referencia}
        onChange={v => setReferencia(typeof v === 'string' ? v : v.target.value)}
        hint="Aparece no título e na mensagem pro cliente." />

      <div className="field-grid-2">
        <Field label="Parcelamento no cartão">
          <select className="input" value={parcMax}
            onChange={e => { const m = Number(e.target.value); setParcMax(m); if (parcSemJuros > m) setParcSemJuros(m); }}>
            <option value={1}>À vista</option>
            {[2,3,4,5,6,7,8,9,10,11,12].map(n => <option key={n} value={n}>até {n}x</option>)}
          </select>
        </Field>
        {parcMax > 1 ? (
          <Field label="Sem juros até" hint="Acima disso, o cliente vê o custo.">
            <select className="input" value={parcSemJuros} onChange={e => setParcSemJuros(Number(e.target.value))}>
              {Array.from({ length: parcMax }, (_, i) => i + 1).map(n =>
                <option key={n} value={n}>{n === 1 ? 'só à vista' : n + 'x'}</option>)}
            </select>
          </Field>
        ) : null}
      </div>

      <div className="bal-nota">
        Sem campos de status ou baixa aqui de propósito: a cobrança nasce <b>Em aberto</b> e é
        o pagamento do cliente que baixa. Pra lançamento manual completo, use <b>Lançar título</b>.
      </div>
    </MpModalCentral>
  );
}

// ── Dados informados pelo CLIENTE no pagamento (etapas da página) ────────────
// Aparece no drawer do título quando pagador_origem = 'cliente' e há diferença
// pro cadastro. O diff é visível e o salvar é UM CLIQUE DA EQUIPE — nunca
// sobrescreve o CRM sozinho.
function MpDadosCliente({ cobranca, titulo }) {
  const [sug, setSug] = React.useState(null);
  const [msg, setMsg] = React.useState('');
  const [salvando, setSalvando] = React.useState(false);
  React.useEffect(() => {
    let vivo = true;
    if (!cobranca || cobranca.pagadorOrigem !== 'cliente') { setSug(null); return; }
    window.tmDb.sugestaoCadastroCliente(cobranca, titulo.cli || titulo.cliente_nome || '')
      .then(r => { if (vivo) setSug(r); }).catch(() => {});
    return () => { vivo = false; };
  }, [cobranca && cobranca.id]);   // eslint-disable-line react-hooks/exhaustive-deps

  if (!sug) return null;
  const salvar = async () => {
    setSalvando(true); setMsg('');
    const r = await window.tmDb.aplicarSugestaoCadastro(sug.clienteId, cobranca);
    setMsg(r.error ? r.error.message : `Salvo no cadastro (${r.campos} campos).`);
    setSalvando(false);
  };
  return (
    <div className="mp-pagamento-bloco">
      <div className="mp-pagamento-head">
        <Icon name="user-check" size={14} /> Dados informados pelo cliente no pagamento
      </div>
      <table className="mp-dif-tbl"><tbody>
        {sug.itens.filter(i => i.informado).map(i => (
          <tr key={i.campo} className={i.difere ? 'dif' : ''}>
            <td className="rot">{i.rotulo}</td>
            <td>{i.informado}{i.difere && i.cadastro
              ? <span className="antes"> (cadastro: {i.cadastro})</span>
              : i.difere ? <span className="antes"> (novo)</span> : null}</td>
          </tr>
        ))}
      </tbody></table>
      {sug.temDiferenca ? (
        sug.clienteId
          ? <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
              <Button variant="secondary" size="sm" icon="user-plus" disabled={salvando} onClick={salvar}>
                {salvando ? 'Salvando…' : 'Salvar no cadastro do cliente'}
              </Button>
              {msg && <span className="muted" style={{ fontSize: 12 }}>{msg}</span>}
            </div>
          : <div className="muted" style={{ fontSize: 12 }}>Cliente não encontrado no cadastro pelo nome — salve manualmente se quiser.</div>
      ) : (
        <div className="muted" style={{ fontSize: 12 }}>Tudo confere com o cadastro.</div>
      )}
    </div>
  );
}

// ── Excluir título — visível, mas com as regras certas ───────────────────────
// A ação mais destrutiva do Financeiro. Confirmação que MOSTRA o que morre
// (referência, cliente, valor) — não um confirm() genérico. Cobrança MP
// pendente é cancelada ANTES de excluir (nunca cobrança viva apontando pra
// título morto — o webhook cairia em "pagamento sem título" e viraria dinheiro
// órfão); se o cancelamento falhar, NADA é excluído. Recebido/pago não chega
// aqui — a lixeira da linha nem habilita.
function ExcluirTituloModal({ titulo, onClose, onExcluido }) {
  const [pendentes, setPendentes] = React.useState(null);   // null = carregando
  const [erro, setErro] = React.useState('');
  const [rodando, setRodando] = React.useState(false);

  React.useEffect(() => {
    let vivo = true;
    window.tmDb.cobrancasPendentesDoTitulo(titulo.id)
      .then(ps => { if (vivo) setPendentes(ps); })
      .catch(() => { if (vivo) setPendentes([]); });
    return () => { vivo = false; };
  }, [titulo.id]);

  const NOME = { pix: 'Pix', boleto: 'boleto', link: 'link de pagamento' };

  const excluir = async () => {
    setRodando(true); setErro('');
    try {
      // 1. cancela TODA cobrança pendente no MP — falhou, aborta sem excluir
      for (const c of (pendentes || [])) {
        await window.mpApi.cancelar(c.id);
      }
      // 2. só então o título morre
      const { error } = await window.tmSupabase.from('contas_receber').delete().eq('id', titulo.id);
      if (error) throw error;
      onExcluido();
    } catch (e) {
      setErro((pendentes || []).length
        ? `Não consegui cancelar a cobrança no Mercado Pago — o título NÃO foi excluído. ${e.message || ''}`
        : `Não foi possível excluir: ${e.message || e}`);
    }
    setRodando(false);
  };

  return (
    <MpModalCentral onClose={onClose} largura={460}
      eyebrow="Contas a Receber" titulo="Excluir título"
      subtitulo="Esta ação não pode ser desfeita."
      footer={<>
        <Button variant="secondary" onClick={onClose}>Cancelar</Button>
        <Button variant="danger" icon="trash-2" disabled={rodando || pendentes === null} onClick={excluir}>
          {rodando ? 'Excluindo…' : 'Excluir título'}
        </Button>
      </>}>

      {erro && <div className="bal-aviso danger"><Icon name="alert-circle" size={15} /><span>{erro}</span></div>}

      {/* o que exatamente vai morrer — clique consciente */}
      <div className="mp-excluir-resumo">
        <div><span className="muted">Referência</span><b>{titulo.ref || titulo.referencia || '—'}</b></div>
        <div><span className="muted">Cliente</span><b>{titulo.cli || titulo.cliente_nome || '—'}</b></div>
        <div><span className="muted">Valor</span><b>R$ {brl(titulo.valor)}</b></div>
      </div>

      {/* Recebido só chega aqui pela EDIÇÃO (a lixeira da linha bloqueia).
          Permitido — mas com a consequência dita na cara, não num confirm(). */}
      {titulo.status === 'Recebido' && (
        <div className="bal-aviso danger">
          <Icon name="alert-triangle" size={15} />
          <div><b>Este título está RECEBIDO.</b> O dinheiro entrou na conta e este registro
            é o espelho dele: excluir <b>descasa o extrato da conta bancária</b> — a conta
            passa a mostrar mais dinheiro do que o app explica. Exclua só se o lançamento
            foi um erro de verdade.</div>
        </div>
      )}

      {titulo.pedido_id && (
        <div className="bal-aviso warning">
          <Icon name="alert-triangle" size={15} />
          <div><b>Este título é parcela de um pedido.</b> Excluir desalinha o pedido do
            financeiro — o pedido continua mostrando a parcela que não existe mais aqui.
            Pode excluir, mas sabendo disso.</div>
        </div>
      )}

      {pendentes === null && <div className="bal-nota">Conferindo cobranças pendentes…</div>}
      {pendentes && pendentes.length > 0 && (
        <div className="bal-aviso warning">
          <Icon name="alert-triangle" size={15} />
          <div>Este título tem <b>{NOME[pendentes[0].metodo] || pendentes[0].metodo} pendente</b> no
            Mercado Pago. Excluir o título <b>cancela a cobrança junto</b> — o cliente não
            consegue mais pagar por ela.</div>
        </div>
      )}
    </MpModalCentral>
  );
}

// ── Card de configuração (Ajustes › Pagamentos) ──────────────────────────────
function MercadoPagoConfigContent() {
  const [estado, setEstado] = React.useState({ carregando: true });
  const testar = React.useCallback(async () => {
    setEstado({ carregando: true });
    try { setEstado({ carregando: false, ...(await window.mpApi.checkConfig()) }); }
    catch (e) { setEstado({ carregando: false, configured: false, conectado: false, message: e.message }); }
  }, []);
  React.useEffect(() => { testar(); }, [testar]);

  const st = estado.carregando ? { cor: 'var(--tm-fg-4)', txt: 'Verificando…' }
    : estado.conectado ? { cor: 'var(--tm-success)', txt: `Conectado — conta ${estado.conta}` }
    : estado.configured ? { cor: 'var(--tm-danger)', txt: `Token configurado mas com erro: ${estado.message}` }
    : { cor: 'var(--tm-warning)', txt: 'Não configurado' };

  return (
    <div className="canvas" style={{ maxWidth: 720 }}>
      <h2 style={{ fontSize: 18, fontFamily: 'var(--tm-font-display)', marginBottom: 4 }}>Pagamentos (Mercado Pago)</h2>
      <div className="muted" style={{ fontSize: 12.5, marginBottom: 16 }}>
        Pix e link de pagamento direto do Contas a Receber — com baixa automática quando o cliente paga.
      </div>
      <Card>
        <div style={{ padding: 18, display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{ width: 38, height: 38, borderRadius: 8, background: '#00B1EA22', color: '#00B1EA',
            display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon name="credit-card" size={16} />
          </div>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 13, fontWeight: 600 }}>Conta Mercado Pago</div>
            <div style={{ fontSize: 12, color: st.cor }}>{st.txt}</div>
          </div>
          <Button variant="secondary" size="sm" icon="refresh-cw" onClick={testar} disabled={estado.carregando}>
            Testar conexão
          </Button>
        </div>
        <div className="muted" style={{ padding: '0 18px 18px', fontSize: 12, lineHeight: 1.65 }}>
          As chaves ficam <b>fora do app</b>, nos Secrets do Supabase (Dashboard › Edge Functions › Secrets):
          <b> MP_ACCESS_TOKEN</b> (token de produção) e <b>MP_WEBHOOK_SECRET</b> (assinatura secreta do
          webhook). Depois de salvar, clique em Testar conexão.
        </div>
      </Card>
      <MpParcelasCard />
      <MpReprocessoCard />
    </div>
  );
}

// Padrão global de parcelamento — vale pra toda cobrança nova (editável por
// cobrança no form). configuracoes é linha única de colunas nomeadas.
function MpParcelasCard() {
  const [max, setMax] = React.useState(1);
  const [semJuros, setSemJuros] = React.useState(1);
  const [msg, setMsg] = React.useState('');
  const [salvando, setSalvando] = React.useState(false);
  React.useEffect(() => {
    window.tmDb.configPagamentos().then(g => { setMax(g.parcelasMax); setSemJuros(g.parcelasSemJuros); });
  }, []);
  const salvar = async () => {
    setSalvando(true); setMsg('');
    const r = await window.tmDb.salvarConfigPagamentos(max, semJuros);
    setMsg(r.error ? r.error.message : 'Padrão salvo — vale pras próximas cobranças.');
    setSalvando(false);
  };
  return (
    <Card>
      <div style={{ padding: 18 }}>
        <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 4 }}>Parcelamento no cartão (padrão)</div>
        <div className="muted" style={{ fontSize: 12, marginBottom: 12 }}>
          O padrão de toda cobrança nova — dá pra mudar cobrança a cobrança no "Nova cobrança".
          Acima do "sem juros", o cliente vê o custo de cada parcela antes de escolher.
        </div>
        <div style={{ display: 'flex', gap: 10, alignItems: 'flex-end', flexWrap: 'wrap' }}>
          <Field label="Parcelar até">
            <select className="input" value={max}
              onChange={e => { const m = Number(e.target.value); setMax(m); if (semJuros > m) setSemJuros(m); }}>
              <option value={1}>À vista</option>
              {[2,3,4,5,6,7,8,9,10,11,12].map(n => <option key={n} value={n}>{n}x</option>)}
            </select>
          </Field>
          {max > 1 && (
            <Field label="Sem juros até">
              <select className="input" value={semJuros} onChange={e => setSemJuros(Number(e.target.value))}>
                {Array.from({ length: max }, (_, i) => i + 1).map(n =>
                  <option key={n} value={n}>{n === 1 ? 'só à vista' : n + 'x'}</option>)}
              </select>
            </Field>
          )}
          <Button variant="primary" size="sm" icon="check" disabled={salvando} onClick={salvar}>
            {salvando ? 'Salvando…' : 'Salvar padrão'}
          </Button>
        </div>
        {msg && <div className="muted" style={{ fontSize: 12, marginTop: 8 }}>{msg}</div>}
        <div className="muted" style={{ fontSize: 11.5, marginTop: 10, lineHeight: 1.6 }}>
          ⚠️ O "sem juros" de verdade (TopMix absorve) se ativa no painel do Mercado Pago:
          <b> Seu negócio › Custos › Oferecer parcelamento sem juros</b>. Sem isso, o MP cobra
          juros do cliente em toda parcela — e a página mostra o custo real, sempre.
        </div>
      </div>
    </Card>
  );
}

// Se o webhook cair (ou rejeitar por bug), as notificações válidas ficam
// guardadas em cobranca_eventos. Este card reenvia cada uma pro caminho normal
// do webhook (assinada de novo) — idempotente: o que já baixou não dobra.
function MpReprocessoCard() {
  const [rodando, setRodando] = React.useState(false);
  const [resultado, setResultado] = React.useState(null);
  const rodar = async () => {
    setRodando(true); setResultado(null);
    try { setResultado(await window.mpApi.reprocessar()); }
    catch (e) { setResultado({ error: e.message }); }
    setRodando(false);
  };
  return (
    <Card>
      <div style={{ padding: 18, display: 'flex', alignItems: 'center', gap: 14 }}>
        <div style={{ width: 38, height: 38, borderRadius: 8, background: 'color-mix(in srgb, var(--tm-warning) 14%, transparent)',
          color: 'var(--tm-warning)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Icon name="rotate-ccw" size={16} />
        </div>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 13, fontWeight: 600 }}>Reprocessar avisos presos</div>
          <div className="muted" style={{ fontSize: 12 }}>
            Reenvia avisos de pagamento válidos que não chegaram a baixar título. Seguro repetir: nada baixa duas vezes.
          </div>
        </div>
        <Button variant="secondary" size="sm" icon="rotate-ccw" disabled={rodando} onClick={rodar}>
          {rodando ? 'Reprocessando…' : 'Reprocessar'}
        </Button>
      </div>
      {resultado && (
        <div style={{ padding: '0 18px 16px', fontSize: 12, lineHeight: 1.6 }}>
          {resultado.error && <span style={{ color: 'var(--tm-danger)' }}>{resultado.error}</span>}
          {resultado.message && <span className="muted">{resultado.message}</span>}
          {(resultado.reprocessados || []).map(r => (
            <div key={r.payment_id} style={{ borderTop: '1px solid var(--tm-line-1)', padding: '6px 0' }}>
              <span className="ref-mono">{r.payment_id}</span>{' — '}
              <span style={{ color: r.processado ? 'var(--tm-success)' : 'var(--tm-warning)' }}>
                {r.desfecho || (r.entregue ? 'entregue' : 'falhou')}
              </span>
            </div>
          ))}
        </div>
      )}
    </Card>
  );
}

Object.assign(window, {
  CobrancaMpModal, MpChip, mpChipDe, mpMensagemWhats, MpBotaoCopiar, MercadoPagoConfigContent,
  NovaCobrancaForm, MpDesdobramento, mpDesdobramentoDe, ExcluirTituloModal, MpModalCentral,
  MpDadosCliente,
});
