/* global React, Icon, Card, PageHead, Button, EmptyState, brl, fmtDate, ymdLocal,
          finAvisoTransferencia */

// ============================================================
// Financeiro › Despesas que são transferência
// ============================================================
// Duas linhas de "Outros" — R$ 9.909,61 para a conta PF — estavam lançadas como
// DESPESA. O DRE de caixa contou como gasto operacional e a conta de destino nunca
// recebeu nada. Esta tela desfaz isso UMA LINHA POR VEZ, com a Naii decidindo cada
// uma, porque o dado não sabe distinguir os dois casos que moram aqui:
//
//   · TRANSFERÊNCIA — o dinheiro só mudou de bolso. Vira `transferencias`, a despesa
//     sai, e o resultado do mês MELHORA no valor dela;
//   · DESPESA COM A CONTA ERRADA — a despesa é real (R$ 21.580 de "Neon Cosméticos
//     via cartão PF" são shampoo de verdade), só saiu de outra conta. Conserta-se o
//     `conta_id` e o resultado NÃO muda em nada.
//
// 🔴 É por isso que não existe botão "converter todas". Converter as dez do segundo
// grupo apagaria R$ 25.674,00 de custo real do DRE — exatamente o estrago que a
// medição de 17/09/2026 evitou quando a ideia era recusar em vez de avisar.
//
// A fila usa o MESMO `finAvisoTransferencia` do formulário (Financeiro_Forms.jsx):
// se a regra mudar lá, muda aqui junto.

// ─── Seleção e contas, em funções puras (a PROVA extrai estas) ───────────────

function rtTextoDaLinha(p) {
  return [p.fornecedor || p.forn, p.referencia || p.ref, p.observacoes].filter(Boolean).join(' | ');
}

// `bloqueados` = ids de contas_pagar apontados por FK (declaração de rendimento ou
// devolução). Apagar um desses falha no banco; a linha aparece, explicada e sem ação.
function rtCandidatos(pagRows, contas, bloqueados) {
  const bloq = bloqueados || {};
  const out = [];
  (pagRows || []).forEach(p => {
    if (!p || (p.categoria || p.cat) === 'Taxa de marketplace') return;
    const texto = rtTextoDaLinha(p);
    const citada = finAvisoTransferencia(texto, contas, p.conta_id);
    if (!citada) return;
    // Sem conta de origem não há transferência a montar: falta a metade que sai.
    const semOrigem = !p.conta_id;
    out.push({
      id: p.id, texto, citada, linha: p,
      valor: Number(p.valor) || 0,
      data: String(p.data_pagamento || '').slice(0, 10) || null,
      status: p.status || 'Em aberto',
      categoria: p.categoria || p.cat || '(sem categoria)',
      travada: !!bloq[p.id],
      semOrigem,
      podeConverter: !bloq[p.id] && !semOrigem && !!String(p.data_pagamento || '').slice(0, 10),
    });
  });
  return out.sort((a, b) => b.valor - a.valor);
}

// 🔴 O QUE MUDA NO DRE, e é diferente por ação — a tela promete isso antes do clique.
// Só o regime de CAIXA conta: despesa `Pago` com data de pagamento. Linha em aberto
// nunca entrou no resultado, então tirá-la não melhora nada.
function rtImpactoDre(cand, acao) {
  if (acao !== 'transferencia') return 0;             // conta errada não mexe no DRE
  if (!cand || cand.status !== 'Pago' || !cand.data) return 0;
  return cand.valor;
}

function rtMesDe(cand) {
  const d = cand && cand.data;
  return d ? d.slice(8, 10) + '/' + d.slice(5, 7) + '/' + d.slice(0, 4) : 'sem data';
}

// ─── A tela ──────────────────────────────────────────────────────────────────

function ReclassificarTransferencias({ onNav }) {
  const [pagRows, setPagRows] = React.useState(null);
  const [contas, setContas] = React.useState([]);
  const [bloqueados, setBloqueados] = React.useState({});
  const [erro, setErro] = React.useState('');
  const [feito, setFeito] = React.useState([]);          // relato do que gravou
  const [ocupado, setOcupado] = React.useState('');      // id em execução
  const [recarga, setRecarga] = React.useState(0);

  React.useEffect(() => {
    let vivo = true;
    if (!window.tmSupabase) { setPagRows([]); return undefined; }
    setErro('');
    (async () => {
      const sb = window.tmSupabase;
      const [cp, cb, cr, mr] = await Promise.all([
        sb.from('contas_pagar').select('*'),
        sb.from('contas_bancarias').select('*'),
        sb.from('contas_receber').select('id, devolucao_de_pagar_id'),
        sb.from('marketplace_rendimentos').select('id, conta_pagar_id'),
      ]);
      // 🔴 Erro de leitura NUNCA vira lista vazia: lista vazia aqui diz "não há nada a
      // consertar", que é a mentira mais cara que esta tela poderia contar.
      const falhou = [cp, cb, cr].map(r => r && r.error).find(Boolean);
      if (falhou) { if (vivo) { setErro(String(falhou.message || falhou)); setPagRows(null); } return; }
      if (!vivo) return;
      const bloq = {};
      (cr.data || []).forEach(r => { if (r.devolucao_de_pagar_id) bloq[r.devolucao_de_pagar_id] = 'devolução amarrada'; });
      // A tabela de rendimentos pode não existir; aí não há declaração a proteger.
      if (!mr.error) (mr.data || []).forEach(r => { if (r.conta_pagar_id) bloq[r.conta_pagar_id] = 'linha de declaração'; });
      setBloqueados(bloq);
      setContas((cb.data || []).filter(c => c.situacao !== 'Arquivada'));
      setPagRows(cp.data || []);
    })().catch(e => { if (vivo) { setErro(String((e && e.message) || e)); setPagRows(null); } });
    return () => { vivo = false; };
  }, [recarga]);

  const cands = React.useMemo(
    () => (pagRows ? rtCandidatos(pagRows, contas, bloqueados) : []),
    [pagRows, contas, bloqueados]);

  const totalDre = cands.reduce((a, c) => a + rtImpactoDre(c, 'transferencia'), 0);

  // ── Ação 1: virou transferência ────────────────────────────────────────────
  // ORDEM: a transferência PRIMEIRO, a despesa depois. Não é atomicidade — são duas
  // chamadas, e o banco não desfaz a primeira se a segunda falhar. A ordem é a segunda
  // linha de defesa: se o delete falhar, sobra uma transferência A MAIS (visível, com o
  // id da despesa escrito nela) em vez de uma despesa que sumiu sem virar nada.
  const converter = async (c) => {
    if (!window.tmSupabase || !c.podeConverter) return;
    setOcupado(c.id); setErro('');
    const sb = window.tmSupabase;
    const origem = contas.find(x => x.id === c.linha.conta_id) || {};
    // `ymdLocal`, nunca `toISOString().slice(0,10)`: aquele é o dia em UTC, e depois das
    // 21h em Brasília já é amanhã (CLAUDE.md § 7). Aqui só entra num texto, e é
    // exatamente assim que o padrão errado sobrevive à revisão e vira cópia.
    const hoje = ymdLocal(new Date());
    const descricao = 'Era despesa em Contas a Pagar: ' + c.texto
      + ' [reclassificada em ' + hoje + ' · origem contas_pagar ' + c.id + ']';
    const ins = await sb.from('transferencias').insert({
      conta_origem_id: c.linha.conta_id,
      conta_destino_id: c.citada.id,
      valor: c.valor,
      data: c.data,
      descricao,
      forma_pagamento: c.linha.forma_pagamento || null,
      empresa_origem_id: origem.empresa_id || null,
      empresa_destino_id: c.citada.empresa_id || null,
    });
    if (ins.error) {
      setOcupado('');
      setErro('Não gravei a transferência, e NADA foi apagado: ' + (ins.error.message || ins.error));
      return;
    }
    const del = await sb.from('contas_pagar').delete().eq('id', c.id);
    setOcupado('');
    if (del.error) {
      // O estado ruidoso, dito por inteiro: dá para consertar à mão porque a
      // transferência carrega o id da despesa que deveria ter saído.
      setErro('A transferência foi criada, mas a despesa NÃO saiu de Contas a Pagar ('
        + (del.error.message || del.error) + '). Agora o valor está contado duas vezes: '
        + 'apague a despesa "' + c.texto.slice(0, 60) + '" à mão, ou apague a transferência '
        + 'recém-criada para voltar ao estado anterior.');
      setRecarga(k => k + 1);
      return;
    }
    setFeito(f => f.concat([{ id: c.id, acao: 'transferencia', texto: c.texto, valor: c.valor, dre: rtImpactoDre(c, 'transferencia') }]));
    setRecarga(k => k + 1);
  };

  // ── Ação 2: é despesa, só a conta estava errada ────────────────────────────
  const corrigirConta = async (c) => {
    if (!window.tmSupabase) return;
    setOcupado(c.id); setErro('');
    const { error } = await window.tmSupabase.from('contas_pagar')
      .update({ conta_id: c.citada.id }).eq('id', c.id);
    setOcupado('');
    if (error) { setErro('Não consegui trocar a conta: ' + (error.message || error)); return; }
    setFeito(f => f.concat([{ id: c.id, acao: 'conta', texto: c.texto, valor: c.valor, dre: 0 }]));
    setRecarga(k => k + 1);
  };

  return (
    <div className="canvas">
      <PageHead title="Despesas que são transferência"
        sub="dinheiro que mudou de conta, lançado como gasto — uma linha por vez, você decide cada uma" />

      <div className="bal-aviso warning" style={{ marginBottom: 16 }}>
        <Icon name="alert-triangle" size={15} />
        <div>
          <b>Estas duas coisas parecem iguais na lista e não são.</b>
          <div style={{ marginTop: 4 }}>
            · <b>Transferência</b>: o dinheiro só mudou de conta. Vira lançamento de transferência,
            a despesa sai, e o <b>resultado do mês melhora</b> no valor dela — inclusive de mês já fechado.
          </div>
          <div style={{ marginTop: 4 }}>
            · <b>Despesa com a conta errada</b>: a compra é real, só saiu de outra conta. Troca só a conta,
            e o <b>resultado não muda em nada</b>.
          </div>
          <div style={{ marginTop: 6, color: 'var(--tm-fg-3)' }}>
            Não existe “aplicar em todas” de propósito: a maior parte desta lista é do segundo tipo, e
            convertê-las apagaria custo verdadeiro do DRE.
          </div>
        </div>
      </div>

      {erro ? (
        <div className="bal-aviso danger" style={{ marginBottom: 14 }}>
          <Icon name="alert-circle" size={15} /><span>{erro}</span>
        </div>
      ) : null}

      {feito.length > 0 ? (
        <div className="bal-aviso" style={{ marginBottom: 14 }}>
          <Icon name="check-circle" size={15} style={{ color: 'var(--tm-success)' }} />
          <div>
            <b>{feito.length} linha(s) resolvida(s) nesta sessão.</b>{' '}
            {feito.filter(f => f.acao === 'transferencia').length} viraram transferência
            (R$ {brl(feito.reduce((a, f) => a + f.dre, 0))} a mais no resultado dos meses envolvidos);{' '}
            {feito.filter(f => f.acao === 'conta').length} tiveram só a conta corrigida (sem efeito no resultado).
          </div>
        </div>
      ) : null}

      {pagRows === null && !erro ? (
        <div style={{ padding: '48px 0', textAlign: 'center', color: 'var(--tm-fg-3)' }}>
          <Icon name="loader" size={20} style={{ opacity: .4 }} />
        </div>
      ) : cands.length === 0 ? (
        <EmptyState icon="check-circle" title="Nenhuma despesa com cara de transferência"
          msg="Nenhum lançamento de Contas a Pagar cita outra conta sua junto com palavra de transferência." />
      ) : (
        <Card title={cands.length + ' despesa(s) a decidir'}
          action={<span className="muted" style={{ fontSize: 11 }}>
            se todas fossem transferência, o resultado melhoraria R$ {brl(totalDre)} — mas não são
          </span>}>
          <table className="tbl" style={{ fontSize: 12.5 }}>
            <thead><tr>
              <th scope="col">Despesa</th>
              <th scope="col" style={{ width: 150 }}>Sai de</th>
              <th scope="col" style={{ width: 170 }}>Cita a conta</th>
              <th scope="col" className="num right" style={{ width: 120 }}>Valor</th>
              <th scope="col" style={{ width: 100 }}>Pagamento</th>
              <th scope="col" style={{ width: 250 }}>O que é isto?</th>
            </tr></thead>
            <tbody>
              {cands.map(c => (
                <tr key={c.id}>
                  <th scope="row" style={{ fontWeight: 400 }}>
                    {c.texto.slice(0, 80)}
                    <div className="muted" style={{ fontSize: 10.5 }}>{c.categoria} · {c.status}</div>
                  </th>
                  <td className="muted">{(contas.find(x => x.id === c.linha.conta_id) || {}).nome || 'sem conta'}</td>
                  <td>{c.citada.nome}</td>
                  <td className="num right">R$ {brl(c.valor)}</td>
                  <td className="muted">{rtMesDe(c)}</td>
                  <td>
                    {c.travada ? (
                      <span className="muted">travada: {bloqueados[c.id]}</span>
                    ) : (<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                      <Button size="sm" variant="secondary" disabled={!c.podeConverter || ocupado === c.id}
                        title={c.semOrigem ? 'Sem conta de origem: não dá para montar a transferência'
                          : 'Vira transferência; o resultado do mês melhora R$ ' + brl(rtImpactoDre(c, 'transferencia'))}
                        onClick={() => converter(c)}>
                        {ocupado === c.id ? '…' : 'É transferência'}
                      </Button>
                      <Button size="sm" variant="ghost" disabled={ocupado === c.id}
                        title="A despesa é real; só a conta que pagou está errada. O resultado não muda."
                        onClick={() => corrigirConta(c)}>
                        Conta errada
                      </Button>
                    </div>)}
                    {c.podeConverter && !c.travada ? (
                      <div className="muted" style={{ fontSize: 10.5, marginTop: 3 }}>
                        transferência: +R$ {brl(rtImpactoDre(c, 'transferencia'))} no resultado de {rtMesDe(c)}
                        {' · '}conta errada: R$ 0,00
                      </div>
                    ) : null}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
          <p className="fc-nota">
            A transferência criada guarda o <b>id da despesa original</b> na descrição — o caminho de volta
            existe. As duas gravações são chamadas separadas: a transferência entra primeiro, a despesa sai
            depois; se a segunda falhar, sobra uma transferência a mais, visível e apagável, em vez de uma
            despesa que sumiu sem virar nada.
          </p>
        </Card>
      )}
    </div>
  );
}

Object.assign(window, {
  ReclassificarTransferencias,
  rtCandidatos, rtImpactoDre, rtTextoDaLinha,
});
