/* global React, Icon, Card, PageHead, EmptyState, brl, calcPeriod,
          canalLabel, clienteTipoLabel, CANAIS_VENDA, CLIENTE_TIPOS */

// ============================================================
// Financeiro › Faturamento por canal
// ============================================================
// Responde "quanto entrou, de quem e por onde" em DUAS dimensões independentes,
// porque um campo só não responde "quanto o distribuidor comprou pelo WhatsApp".
//
// 🔴 FATURAMENTO É `pedidos.total`, STATUS `Atendido` — NUNCA `contas_receber`.
// Cada pedido gera um título com `pedido_id`; somar os dois duplica. É o que o
// DRE (`Relatorios_Sections.jsx:1124`) e o painel de Marketplace
// (`Marketplace.jsx:930`) já fazem, e é por isso que os três batem.
//
// 🔴 E NÃO EXISTE LINHA "receita sem pedido" AQUI, DE PROPÓSITO.
// A primeira versão do desenho pedia essa linha, supondo que fossem vendas que
// perderam o vínculo. O diagnóstico mostrou que NÃO são: dos R$ 129 mil em
// títulos sem `pedido_id`, ~R$ 46 mil não são venda nenhuma — aporte de sócio,
// devolução de pix, transferência entre empresas, reserva interna. Mostrar isso
// como receita chamaria um aporte de faturamento.
// A correção de fundo é categoria em `contas_receber` (venda / investimento /
// devolução / transferência interna), que Contas a PAGAR já tem e a receber não.
// ⚠️ E não é passado que se resolve sozinho: só setembro tem 19 títulos e
// R$ 17.666 em dez dias. O hábito continua — quem pegar a próxima rodada não
// deve tratar isso como histórico.

const FC_PERIODOS = [
  { id: 'mes',  label: 'Este mês' },
  { id: '90d',  label: 'Últimos 90 dias' },
  { id: 'ano',  label: 'Este ano' },
  { id: 'todo', label: 'Tudo' },
];

// Barra proporcional: a leitura de relance antes do número.
function FCBarra({ pct, cor }) {
  return (
    <div style={{ height: 6, borderRadius: 3, background: 'var(--tm-bg-3)', overflow: 'hidden', marginTop: 5 }}>
      <div style={{ height: '100%', borderRadius: 3, width: Math.max(0, Math.min(100, pct)) + '%', background: cor }} />
    </div>
  );
}

function FCTabela({ titulo, ajuda, linhas, total, cor }) {
  return (
    <Card title={titulo} action={<span className="muted" style={{ fontSize: 11 }}>{ajuda}</span>}>
      {linhas.length === 0 ? (
        <div style={{ padding: '28px 0', textAlign: 'center', color: 'var(--tm-fg-3)', fontSize: 12.5 }}>
          Nenhum pedido atendido no período.
        </div>
      ) : (
        <table className="tbl" style={{ fontSize: 13 }}>
          <thead><tr>
            <th>{titulo}</th>
            <th className="num right" style={{ width: 90 }}>Pedidos</th>
            <th className="num right" style={{ width: 130 }}>Faturamento</th>
            <th className="num right" style={{ width: 70 }}>%</th>
          </tr></thead>
          <tbody>
            {linhas.map((l) => (
              <tr key={l.id}>
                <td style={{ color: l.vazio ? 'var(--tm-fg-4)' : 'var(--tm-fg-1)' }}>
                  {l.label}
                  <FCBarra pct={total > 0 ? (l.valor / total) * 100 : 0} cor={l.vazio ? 'var(--tm-fg-4)' : cor} />
                </td>
                <td className="num right">{l.qtd}</td>
                <td className="num right">R$ {brl(l.valor)}</td>
                <td className="num right muted">{total > 0 ? ((l.valor / total) * 100).toFixed(1).replace('.', ',') : '0,0'}%</td>
              </tr>
            ))}
            <tr>
              <td style={{ fontWeight: 700, borderTop: '1px solid var(--tm-line-2)' }}>Total</td>
              <td className="num right" style={{ fontWeight: 700, borderTop: '1px solid var(--tm-line-2)' }}>
                {linhas.reduce((a, l) => a + l.qtd, 0)}</td>
              <td className="num right" style={{ fontWeight: 700, borderTop: '1px solid var(--tm-line-2)' }}>R$ {brl(total)}</td>
              <td className="num right" style={{ fontWeight: 700, borderTop: '1px solid var(--tm-line-2)' }}>100%</td>
            </tr>
          </tbody>
        </table>
      )}
    </Card>
  );
}

function FaturamentoCanal() {
  const [periodo, setPeriodo] = React.useState('90d');
  const [dados, setDados]     = React.useState(null);   // null = carregando
  const [erro, setErro]       = React.useState('');

  // 🔴 Dependência = a CHAVE do período, nunca o Date. `calcPeriod` devolve
  // `key`, que muda quando a pessoa troca o período e uma vez por dia — não a
  // cada render. Depender de `end.getTime()` custou 143,6 milhões de
  // requisições neste projeto (CLAUDE.md § 7).
  const per = calcPeriod(periodo === 'todo' ? 'ano' : periodo);
  const chave = periodo === 'todo' ? 'todo' : per.key;

  React.useEffect(() => {
    let vivo = true;
    if (!window.tmSupabase) return undefined;
    setDados(null); setErro('');
    let q = window.tmSupabase.from('pedidos')
      .select('id, total, canal, cliente_tipo, cliente_nome, marketplace_loja_id, data_venda, created_at')
      .eq('status', 'Atendido');
    if (periodo !== 'todo') {
      const ini = calcPeriod(periodo).start.toISOString().slice(0, 10);
      const fim = calcPeriod(periodo).end.toISOString().slice(0, 10);
      q = q.gte('data_venda', ini).lte('data_venda', fim);
    }
    Promise.all([q, window.tmSupabase.from('marketplace_lojas').select('id, nome')])
      .then(([ped, lojas]) => {
        if (!vivo) return;
        if (ped.error) { setErro(ped.error.message || String(ped.error)); setDados([]); return; }
        const nomeLoja = {};
        (lojas.data || []).forEach(l => { nomeLoja[l.id] = l.nome; });
        setDados((ped.data || []).map(p => ({ ...p, _loja: nomeLoja[p.marketplace_loja_id] || null })));
      })
      .catch(e => { if (vivo) { setErro(String((e && e.message) || e)); setDados([]); } });
    return () => { vivo = false; };
  }, [chave, periodo]);

  const m = React.useMemo(() => {
    const ps = dados || [];
    const total = ps.reduce((a, p) => a + (Number(p.total) || 0), 0);

    // ── QUEM COMPRA ────────────────────────────────────────────
    // 🔴 Marketplace conta como CLIENTE FINAL, e isso é derivação, não chute:
    // quem compra numa loja de marketplace é consumidor final por natureza.
    // Não gravamos `cliente_tipo='cliente'` no banco porque não há CADASTRO —
    // `cliente_id` seria nulo e o par ficaria pela metade (o CHECK
    // `pedidos_cliente_par_completo` recusa id sem tipo e tipo sem id, de
    // propósito: id órfão não diz em que tabela procurar).
    // Sem esta regra os pedidos de marketplace caíam em "Não vinculado" —
    // conferi na tela — e aí aquele balde passava a significar DUAS coisas:
    // "marketplace, sem cadastro por natureza" e "B2B cujo nome não casou".
    // Misturar as duas esconde justamente o que ela precisa resolver na mão.
    const porTipo = {};
    CLIENTE_TIPOS.forEach(t => { porTipo[t.id] = { id: t.id, label: t.label, qtd: 0, valor: 0 }; });
    porTipo._nv = { id: '_nv', label: 'Não vinculado', qtd: 0, valor: 0, vazio: true };
    const tipoDe = (p) => (p.marketplace_loja_id ? 'cliente'
      : (p.cliente_tipo && porTipo[p.cliente_tipo] ? p.cliente_tipo : '_nv'));
    ps.forEach(p => {
      const k = tipoDe(p);
      porTipo[k].qtd += 1; porTipo[k].valor += Number(p.total) || 0;
    });

    // ── POR ONDE ENTROU ────────────────────────────────────────
    // Marketplace quebra por LOJA: "Marketplace" sozinho esconde a diferença
    // entre Shopee e Mercado Livre, que é o que ela olha.
    const porCanal = {};
    const somaCanal = (id, label, v, vazio) => {
      if (!porCanal[id]) porCanal[id] = { id, label, qtd: 0, valor: 0, vazio: !!vazio };
      porCanal[id].qtd += 1; porCanal[id].valor += v;
    };
    ps.forEach(p => {
      const v = Number(p.total) || 0;
      if (p.marketplace_loja_id) somaCanal('mkt|' + p.marketplace_loja_id, 'Marketplace · ' + (p._loja || 'loja sem nome'), v);
      else if (p.canal)          somaCanal(p.canal, canalLabel(p.canal) || p.canal, v);
      else                       somaCanal('_ni', 'Não informado', v, true);
    });

    // ── O CRUZAMENTO — a razão de serem duas dimensões ─────────
    const colunas = [];
    (CANAIS_VENDA || []).forEach(c => colunas.push({ id: c.id, label: c.label }));
    colunas.push({ id: '_ni', label: 'Não informado', vazio: true });
    const linhasCruz = [];
    CLIENTE_TIPOS.forEach(t => linhasCruz.push({ id: t.id, label: t.label }));
    linhasCruz.push({ id: '_nv', label: 'Não vinculado', vazio: true });

    const cruz = {};
    ps.forEach(p => {
      const lin = tipoDe(p);                       // mesma regra da tabela acima
      const col = p.marketplace_loja_id ? 'marketplace' : (p.canal || '_ni');
      cruz[lin + '::' + col] = (cruz[lin + '::' + col] || 0) + (Number(p.total) || 0);
    });

    const ord = (o) => Object.values(o).sort((a, b) => b.valor - a.valor);
    const canais = ord(porCanal).filter(l => l.qtd > 0);
    // 🔴 O card de destaque mostra a maior origem CONHECIDA. "Não informado"
    // pode ser a maior fatia — e num card em destaque isso vira a falta de dado
    // ocupando o lugar do resultado, o que parece defeito da tela.
    // A pendência não some: ela vira uma faixa própria, com o nome dela e o que
    // fazer. Dado que falta é TRABALHO A FAZER, não resposta.
    const maiorConhecida = canais.find(c => !c.vazio) || null;
    const semOrigem = canais.find(c => c.id === '_ni') || null;
    return {
      total, qtd: ps.length,
      tipos: ord(porTipo).filter(l => l.qtd > 0),
      canais, maiorConhecida, semOrigem,
      colunas, linhasCruz, cruz,
      ticket: ps.length ? total / ps.length : 0,
    };
  }, [dados]);

  return (
    <div className="canvas">
      <PageHead title="Faturamento por canal"
        sub="pedidos Atendidos · a mesma fonte do DRE (pedidos.total)" />

      <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap', margin: '0 0 18px' }}>
        {FC_PERIODOS.map(o => (
          <button key={o.id} className={'chip' + (periodo === o.id ? ' on' : '')}
            onClick={() => setPeriodo(o.id)}
            style={{
              background: periodo === o.id ? 'rgba(201,169,97,.12)' : 'var(--tm-bg-2)',
              border: '1px solid ' + (periodo === o.id ? 'var(--tm-brand-champagne)' : 'var(--tm-line-2)'),
              color: periodo === o.id ? 'var(--tm-brand-champagne)' : 'var(--tm-fg-2)',
              borderRadius: 7, padding: '7px 13px', fontSize: 12.5, cursor: 'pointer',
            }}>{o.label}</button>
        ))}
      </div>

      {erro && (
        <div style={{ display: 'flex', gap: 8, alignItems: 'flex-start', fontSize: 12.5,
                      color: 'var(--tm-danger)', marginBottom: 14 }}>
          <Icon name="alert-triangle" size={15} style={{ flexShrink: 0, marginTop: 1 }} />
          <span>Não consegui carregar os pedidos: {erro}</span>
        </div>
      )}

      {dados === null ? (
        <div style={{ padding: '48px 0', textAlign: 'center', color: 'var(--tm-fg-3)' }}>
          <Icon name="loader" size={20} style={{ opacity: .4 }} />
        </div>
      ) : m.qtd === 0 ? (
        <EmptyState icon="pie-chart" title="Nenhum pedido atendido no período"
          msg="Só entram pedidos com status Atendido — é a mesma regra do DRE." />
      ) : (<>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginBottom: 14 }}>
          <Card><div style={{ padding: '4px 2px' }}>
            <div className="muted" style={{ fontSize: 11, textTransform: 'uppercase', letterSpacing: '.07em' }}>Faturamento total</div>
            <div style={{ fontSize: 22, fontWeight: 700, color: 'var(--tm-brand-champagne)' }}>R$ {brl(m.total)}</div>
            <div className="muted" style={{ fontSize: 11.5 }}>{m.qtd} pedido(s) atendido(s)</div>
          </div></Card>
          <Card><div style={{ padding: '4px 2px' }}>
            <div className="muted" style={{ fontSize: 11, textTransform: 'uppercase', letterSpacing: '.07em' }}>Ticket médio</div>
            <div style={{ fontSize: 22, fontWeight: 700 }}>R$ {brl(m.ticket)}</div>
            <div className="muted" style={{ fontSize: 11.5 }}>varia muito por tipo — ver abaixo</div>
          </div></Card>
          <Card><div style={{ padding: '4px 2px' }}>
            <div className="muted" style={{ fontSize: 11, textTransform: 'uppercase', letterSpacing: '.07em' }}>Maior origem conhecida</div>
            <div style={{ fontSize: 22, fontWeight: 700 }}>{m.maiorConhecida ? m.maiorConhecida.label : 'nenhuma ainda'}</div>
            <div className="muted" style={{ fontSize: 11.5 }}>
              {m.maiorConhecida
                ? `R$ ${brl(m.maiorConhecida.valor)} · ${((m.maiorConhecida.valor / m.total) * 100).toFixed(1).replace('.', ',')}% do total`
                : 'nenhum pedido tem origem preenchida'}</div>
          </div></Card>
        </div>

        {m.semOrigem && (
          <div style={{ display: 'flex', gap: 9, alignItems: 'flex-start', marginBottom: 14,
                        background: 'var(--tm-bg-2)', border: '1px solid var(--tm-line-2)',
                        borderLeft: '3px solid var(--tm-warning)', borderRadius: 7,
                        padding: '11px 15px', fontSize: 12.5, color: 'var(--tm-fg-2)', lineHeight: 1.7 }}>
            <Icon name="alert-triangle" size={15} style={{ flexShrink: 0, marginTop: 2, color: 'var(--tm-warning)' }} />
            <span>
              <b>{m.semOrigem.qtd} pedido(s) ainda sem origem</b> — R$ {brl(m.semOrigem.valor)},
              {' '}{((m.semOrigem.valor / m.total) * 100).toFixed(1).replace('.', ',')}% do faturamento.
              <div style={{ marginTop: 3, color: 'var(--tm-fg-4)' }}>
                Não é erro de conta: é campo em branco. Abra o pedido e preencha
                <b> Por onde entrou</b> — a quebra abaixo fica completa sozinha à medida que você preenche.
              </div>
            </span>
          </div>
        )}

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14, marginBottom: 14 }}>
          <FCTabela titulo="Quem compra" ajuda="vem do cadastro, ninguém digita"
            linhas={m.tipos} total={m.total} cor="var(--tm-brand-champagne)" />
          <FCTabela titulo="Por onde entrou" ajuda="marketplace é automático; o resto vem do pedido"
            linhas={m.canais} total={m.total} cor="var(--tm-info)" />
        </div>

        <Card title="Cruzamento"
          action={<span className="muted" style={{ fontSize: 11 }}>é para isto que são duas dimensões</span>}>
          <div style={{ overflowX: 'auto' }}>
            <table className="tbl" style={{ fontSize: 12.5 }}>
              <thead><tr>
                <th style={{ minWidth: 130 }}></th>
                {m.colunas.map(c => <th key={c.id} className="num right">{c.label}</th>)}
                <th className="num right">Total</th>
              </tr></thead>
              <tbody>
                {m.linhasCruz.map(l => {
                  const tot = m.colunas.reduce((a, c) => a + (m.cruz[l.id + '::' + c.id] || 0), 0);
                  if (tot === 0) return null;
                  return (
                    <tr key={l.id}>
                      <td style={{ color: l.vazio ? 'var(--tm-fg-4)' : 'var(--tm-fg-2)' }}>{l.label}</td>
                      {m.colunas.map(c => {
                        const v = m.cruz[l.id + '::' + c.id] || 0;
                        return <td key={c.id} className="num right"
                          style={{ color: v ? 'var(--tm-fg-1)' : 'var(--tm-fg-4)' }}>{v ? 'R$ ' + brl(v) : '—'}</td>;
                      })}
                      <td className="num right" style={{ fontWeight: 700 }}>R$ {brl(tot)}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </Card>

        {/* 🔴 COM O QUE ISTO CONFERE, E COM O QUE NÃO CONFERE.
            Dizer isso na tela não é enfeite: se o número não bater com o vizinho
            e ninguém explicar por quê, ela para de confiar na tela — e com razão. */}
        <div style={{ marginTop: 14, display: 'flex', gap: 9, alignItems: 'flex-start',
                      background: 'var(--tm-bg-2)', border: '1px solid var(--tm-line-2)',
                      borderLeft: '3px solid var(--tm-info)', borderRadius: 7,
                      padding: '12px 15px', fontSize: 12.5, color: 'var(--tm-fg-2)', lineHeight: 1.7 }}>
          <Icon name="info" size={15} style={{ flexShrink: 0, marginTop: 2, color: 'var(--tm-info)' }} />
          <span>
            Este total <b>bate com a Receita Bruta do DRE</b> no mesmo período — os dois leem
            <b> pedidos.total</b> dos pedidos Atendidos.
            <div style={{ marginTop: 5, color: 'var(--tm-fg-4)' }}>
              Não bate com Contas a Receber, e isso é esperado: lá existe dinheiro que não é
              venda (aporte de sócio, devolução, transferência entre empresas) e venda que
              ainda não virou pedido. São perguntas diferentes.
            </div>
          </span>
        </div>
      </>)}
    </div>
  );
}

Object.assign(window, { FaturamentoCanal });
