// Afiliados → DRE Afiliados (spec 2026-07-24-dre-afiliados-design): demonstrativo de
// resultado por competência (coorte date_created), por afiliado ou consolidado ("Todos"),
// com cascata de produto. SEM seletor de Reembolso — fixo em `pedido` (nota fixa abaixo do
// filtro). UI espelha o Funnel Sales Tracker (ProductFunnel.jsx): card com borderCollapse,
// números fenix-num mono tabulares, subtotais com fundo cinza e negrito, deduções em
// var(--negative), bloco final destacado em var(--positive-bg)/var(--negative-bg), ROAS em
// linha navy. TODAS as contas vêm prontas do backend (inclusive `pct`) — aqui é só formatação.
// Identificadores top-level com prefixo `dre` (escopo Babel compartilhado entre .jsx — grep
// antes de adicionar nomes novos).

const dreFmtPct = (v) => (v == null ? '—' : PCT(v));

// Zero renderiza "0" apagado (spec: linhas de plataforma/custo com valor 0).
const dreMoney = (v) => (v === 0 ? <span style={dreS.dim}>0</span> : USD(v));

// Deduções (chargeback/reembolso): sempre ABS, sempre "− " em vermelho — nunca voltam.
const dreDeductionValue = (v) => (
  v > 0
    ? <span style={{ color: 'var(--negative)' }}>{'− ' + USD(v)}</span>
    : <span style={dreS.dim}>0</span>
);

// Projeção pode devolver receita (realizado acima da média dos 2 meses anteriores) — nesse
// caso é positiva na tela (var(--positive), prefixo "+"); do contrário é dedução (var(--negative)).
const dreProjecaoValue = (v) => (
  v > 0 ? <span style={{ color: 'var(--negative)' }}>{'− ' + USD(v)}</span>
  : v < 0 ? <span style={{ color: 'var(--positive)' }}>{'+ ' + USD(Math.abs(v))}</span>
  : <span style={dreS.dim}>0</span>
);

const dreRecTitle = (r) => `Atribuído ${USD(r.atribuido)} + rateio (não atribuído) ${USD(r.rateio)}`;

// Uma linha da tabela — função (não componente JSX) chamada dentro de um array, com key.
// opts: { bg, bold, sub (nota sob o rótulo), title (tooltip), rl (sublinha "% RL"), color
// (cor só do valor), rowColor (cor da linha inteira — usada pela linha final ROAS) }.
const dreRow = (key, label, valueNode, pctNode, opts = {}) => {
  const labelColor = opts.rowColor || (opts.bold ? 'var(--fg-1)' : 'var(--fg-2)');
  const valueColor = opts.rowColor || opts.color || (opts.bold ? 'var(--fg-1)' : 'var(--fg-2)');
  const pctColor = opts.rowColor || 'var(--fg-3)';
  return (
    <tr key={key} style={opts.bg ? { background: opts.bg } : undefined} title={opts.title}>
      <td style={{ ...dreS.tdLabel, color: labelColor, fontWeight: opts.bold ? 700 : 500 }}>
        {label}
        {opts.sub && <div style={dreS.subLabel}>{opts.sub}</div>}
      </td>
      <td className="fenix-num" style={{ ...dreS.tdNum, color: valueColor, fontWeight: opts.bold ? 700 : 500 }}>
        {valueNode}
      </td>
      <td className="fenix-num" style={{ ...dreS.tdNum, color: pctColor, fontWeight: opts.bold ? 700 : 500 }}>
        {pctNode}
        {opts.rl != null && <div style={dreS.rlSub}>% RL {dreFmtPct(opts.rl)}</div>}
      </td>
    </tr>
  );
};

const DreAfiliadosView = ({ rosterAll = [], families = [] }) => {
  const [period, setPeriod] = React.useState('30d');
  const [customRange, setCustomRange] = React.useState(null);
  const [affiliate, setAffiliate] = React.useState('todos');
  const [product, setProduct] = React.useState('todos');
  const [funnel, setFunnel] = React.useState('todos');
  const [data, setData] = React.useState(null);
  const [demo, setDemo] = React.useState(false);
  const fullLoading = useFullLoading();
  const withLoad = (fn) => (...a) => { fullLoading.mark(); fn(...a); };

  const handleProductChange = (p) => { withLoad(setProduct)(p); setFunnel('todos'); };

  React.useEffect(() => {
    const began = fullLoading.begin();
    let cancelled = false;
    fetchDreAPI({ period, affiliate, product, funnel, start: customRange?.start, end: customRange?.end })
      .then(d => { if (cancelled) return; setData(d); setDemo(false); })
      .catch(() => { if (cancelled) return; setData(buildDreMock(period, affiliate, product, funnel)); setDemo(true); })
      .finally(() => { fullLoading.end(began); });
    return () => { cancelled = true; };
  }, [period, customRange, affiliate, product, funnel]);

  // Cascata de produto — mesmo padrão do FilterBar (families = /product-families).
  const sortedFamilies = React.useMemo(() => [...families].sort((a, b) => a.name.localeCompare(b.name)), [families]);
  const variants = product !== 'todos' ? (families.find(f => f.name === product)?.variants || []) : [];

  // Dropdown de afiliado — `rosterAll` é o roster do /affiliates SEM os filtros globais de
  // plataforma/tráfego (a DRE esconde o FilterBar; usar `rows` filtrado faria o dropdown
  // sumir com afiliados se outra aba tivesse deixado Plataforma/Tráfego setados). "Todos"
  // primeiro = DRE consolidada. Ordem preservada (revenue-desc herdada do endpoint/mock) —
  // deliberado, não reordena por nome.
  const affiliateOptions = React.useMemo(() => {
    const seen = new Set();
    const opts = [{ key: 'todos', label: 'Todos' }];
    rosterAll.forEach(r => {
      if (r.name && r.name !== 'Não atribuído' && !seen.has(r.name)) { seen.add(r.name); opts.push({ key: r.name, label: r.name }); }
    });
    return opts;
  }, [rosterAll]);

  return (
    <div style={{ position: 'relative' }}>
      <div style={dreS.header}>
        <div>
          <div style={dreS.eye}>Afiliados</div>
          <h1 style={dreS.title}>DRE Afiliados</h1>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <PeriodSelector period={period} setPeriod={withLoad(setPeriod)} customRange={customRange} setCustomRange={withLoad(setCustomRange)} />
          <Dropdown icon="users" label="Afiliado" value={affiliate} onChange={withLoad(setAffiliate)} options={affiliateOptions} />
          <Dropdown icon="cart" label="Produto" value={product} onChange={handleProductChange} options={[
            { key: 'todos', label: 'Todos' },
            ...sortedFamilies.map(f => ({ key: f.name, label: f.name })),
          ]} />
          {product !== 'todos' && (
            <Dropdown icon="layers" label="Funil" value={funnel} onChange={withLoad(setFunnel)} options={[
              { key: 'todos', label: 'Todas variações' },
              ...variants.map(v => ({
                key: v,
                label: v.slice(product.length).replace(/^\s*[|\-]\s*/, '').trim() || v,
              })),
            ]} />
          )}
        </div>
      </div>

      <div style={dreS.note}>
        Competência pela data do pedido — refunds/chargebacks entram no mês da venda.
        {demo && <span style={dreS.demoChip}>Dados de demonstração — API offline</span>}
      </div>

      {!data ? (
        <div style={{ padding: 40, color: 'var(--fg-3)' }}>Carregando DRE…</div>
      ) : (
        <div style={dreS.card}>
          <div style={dreS.cardHead}>
            <div style={dreS.eyebrow}>DRE · {affiliate === 'todos' ? 'Consolidada' : affiliate}</div>
            <div style={{ font: 'var(--text-h3)', color: 'var(--fg-1)', marginTop: 4 }}>Demonstrativo de resultado</div>
          </div>
          <div style={{ overflowX: 'auto' }}>
            <table style={dreS.table}>
              <thead><tr>
                <th style={{ ...dreS.th, textAlign: 'left' }}>Linha</th>
                <th style={dreS.th}>Valor</th>
                <th style={dreS.th}>% RB</th>
              </tr></thead>
              <tbody>
                {dreRow('qtd', 'Qtd de Venda', NUM(data.qtdVendas), '—')}
                {dreRow('aov', 'AOV médio', USD(data.aov), '—')}

                {dreRow('buygoods', 'Buygoods', dreMoney(data.plataformas.buygoods), dreFmtPct(data.pct.plataformas.buygoods))}
                {dreRow('tauk', 'Tauk', dreMoney(data.recuperacao.tauk.total), dreFmtPct(data.pct.recuperacao.tauk.total),
                  { title: dreRecTitle(data.recuperacao.tauk) })}
                {dreRow('salesbound', 'SalesBound', dreMoney(data.recuperacao.salesbound.total), dreFmtPct(data.pct.recuperacao.salesbound.total),
                  { title: dreRecTitle(data.recuperacao.salesbound) })}
                {dreRow('logicall', 'Logicall', dreMoney(data.recuperacao.logicall.total), dreFmtPct(data.pct.recuperacao.logicall.total),
                  { title: dreRecTitle(data.recuperacao.logicall) })}
                {dreRow('digistore24', 'Digistore', dreMoney(data.plataformas.digistore24), dreFmtPct(data.pct.plataformas.digistore24))}
                {dreRow('clickbank', 'Clickbank', dreMoney(data.plataformas.clickbank), dreFmtPct(data.pct.plataformas.clickbank))}
                {dreRow('pagamerican', 'PagAmerican', dreMoney(data.plataformas.pagamerican), dreFmtPct(data.pct.plataformas.pagamerican))}

                {dreRow('receitaBrutaReal', 'RECEITA BRUTA REAL', USD(data.receitaBrutaReal), dreFmtPct(data.pct.receitaBrutaReal),
                  { bg: 'var(--gray-100)', bold: true })}

                {dreRow('imposto', 'Imposto sobre Receita', dreMoney(data.imposto), dreFmtPct(data.pct.imposto))}
                {dreRow('chargeback', `(−) Chargeback (${NUM(data.chargeback.eventos)} evento${data.chargeback.eventos === 1 ? '' : 's'})`,
                  dreDeductionValue(data.chargeback.valor), dreFmtPct(data.pct.chargeback))}
                {dreRow('reembolso', `(−) Reembolso (${NUM(data.reembolso.n)})`,
                  dreDeductionValue(data.reembolso.valor), dreFmtPct(data.pct.reembolso))}
                {dreRow('projecao', '(−) Projeção Chargeback/Refund',
                  data.projecao.disponivel ? dreProjecaoValue(data.projecao.valor) : <span style={dreS.dim}>—</span>,
                  data.projecao.disponivel ? dreFmtPct(data.pct.projecao) : '—',
                  { title: `Média dos 2 meses anteriores ${dreFmtPct(data.projecao.mediaPct)} − Realizado no período ${dreFmtPct(data.projecao.realizadoPct)}` })}

                {dreRow('receitaLiquida', 'RECEITA LÍQUIDA', USD(data.receitaLiquida), dreFmtPct(data.pct.receitaLiquida),
                  { bg: 'var(--gray-100)', bold: true })}

                {dreRow('custoProduto', 'Custos com produto', USD(data.custos.produto), dreFmtPct(data.pct.custos.produto),
                  { sub: `${dreFmtPct(data.regras.custoProdutoPct)} × RB Real` })}
                {dreRow('contingencia', 'Contingência', USD(data.custos.contingencia), dreFmtPct(data.pct.custos.contingencia),
                  { sub: `${dreFmtPct(data.regras.contingenciaPct)} × RB Real` })}
                {dreRow('taxasGateway', 'Taxas de Gateway', USD(data.custos.taxasGateway), dreFmtPct(data.pct.custos.taxasGateway))}
                {dreRow('taxasMarketplace', 'Taxas Marketplace/tributos', USD(data.custos.taxasMarketplace), dreFmtPct(data.pct.custos.taxasMarketplace))}
                {dreRow('refuntech', 'Refuntech / Gestão de Chargeback', dreMoney(data.custos.refuntech), dreFmtPct(data.pct.custos.refuntech))}

                {dreRow('custosVariaveis', 'CUSTOS VARIÁVEIS', USD(data.custos.total), dreFmtPct(data.pct.custos.total.rb),
                  { bg: 'var(--gray-100)', bold: true, rl: data.pct.custos.total.rl })}

                {dreRow('mc1', 'MARGEM CONTRIBUIÇÃO 1', USD(data.margemContribuicao1), dreFmtPct(data.pct.margemContribuicao1.rb),
                  { bg: 'var(--gray-100)', bold: true, rl: data.pct.margemContribuicao1.rl })}

                {dreRow('comissaoAfiliados', 'Comissão Afiliados', USD(data.marketing.comissaoAfiliados), dreFmtPct(data.pct.marketing.comissaoAfiliados))}
                {dreRow('comissaoRecuperacao', 'Comissão Recuperação/Parceiros', dreMoney(data.marketing.comissaoRecuperacao), dreFmtPct(data.pct.marketing.comissaoRecuperacao))}
                {dreRow('comissaoParceiros', 'Comissão Parceiros/Estratégicos', dreMoney(data.marketing.comissaoParceiros), dreFmtPct(data.pct.marketing.comissaoParceiros))}

                {dreRow('marketingVendas', 'MARKETING E VENDAS', USD(data.marketing.total), dreFmtPct(data.pct.marketing.total.rb),
                  { bg: 'var(--gray-100)', bold: true, rl: data.pct.marketing.total.rl })}

                {dreRow('mc2', 'MARGEM CONTRIBUIÇÃO 2', USD(data.margemContribuicao2), dreFmtPct(data.pct.margemContribuicao2.rb),
                  { bg: 'var(--gray-100)', bold: true, rl: data.pct.margemContribuicao2.rl,
                    color: data.margemContribuicao2 < 0 ? 'var(--negative)' : undefined })}

                {dreRow('margemSemProjecao', 'Margem (sem projeção)', USD(data.margemSemProjecao), dreFmtPct(data.pct.margemSemProjecao.rb),
                  { bg: data.margemSemProjecao >= 0 ? 'var(--positive-bg)' : 'var(--negative-bg)', bold: true,
                    rl: data.pct.margemSemProjecao.rl,
                    color: data.margemSemProjecao >= 0 ? 'var(--positive)' : 'var(--negative)' })}

                {dreRow('roas', 'ROAS',
                  // "×" no fim (não "$"/"%") — ROAS é um múltiplo, não dinheiro nem percentual;
                  // sem o sufixo, "1,68" na coluna Valor lê como moeda truncada.
                  data.roas != null ? data.roas.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + '×' : '—', '—',
                  { bg: 'var(--fenix-navy)', bold: true, rowColor: '#F6E9E0' })}
              </tbody>
            </table>
          </div>
        </div>
      )}
      <FullLoadingOverlay show={fullLoading.show && !!data} conn="connecting" />
    </div>
  );
};

const dreS = {
  header: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap', marginBottom: 10 },
  eye: { font: '600 10px/1 var(--font-sans)', letterSpacing: '.08em', textTransform: 'uppercase', color: 'var(--fenix-orange)' },
  title: { font: '800 22px/1.1 var(--font-display)', color: 'var(--fg-1)', margin: '5px 0 0' },
  note: { font: '600 10.5px/1.4 var(--font-sans)', color: 'var(--fg-3)', background: 'var(--gray-100)',
    borderRadius: 6, padding: '6px 10px', margin: '0 0 16px', display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' },
  demoChip: { font: '600 11px/1 var(--font-sans)', padding: '4px 9px', borderRadius: 'var(--r-pill)',
    background: 'var(--warning-bg)', color: 'var(--warning)' },
  card: { background: '#fff', border: '1px solid var(--border-1)', borderRadius: 'var(--r-lg)', boxShadow: 'var(--shadow-sm)', overflow: 'hidden' },
  cardHead: { padding: '16px 20px', borderBottom: '1px solid var(--border-1)' },
  eyebrow: { font: '600 10px/1 var(--font-sans)', letterSpacing: '.05em', textTransform: 'uppercase', color: 'var(--fg-3)' },
  table: { width: '100%', borderCollapse: 'collapse', minWidth: 520 },
  // padding/fontSize levemente menores que S.mth/S.mtd do ProductFunnel — deliberado: a DRE
  // tem ~29 linhas (vs. ~10 da matriz de funil) e precisa caber sem scroll excessivo; mesma
  // família/paleta/borderCollapse, densidade vertical só um pouco maior.
  th: { font: '600 10px/1 var(--font-sans)', letterSpacing: '.04em', textTransform: 'uppercase', color: 'var(--fg-3)',
    padding: '11px 14px', borderBottom: '1px solid var(--border-2)', textAlign: 'right', whiteSpace: 'nowrap' },
  tdLabel: { padding: '10px 14px', borderBottom: '1px solid var(--border-1)', textAlign: 'left',
    font: '500 12.5px/1.3 var(--font-sans)' },
  tdNum: { padding: '10px 14px', borderBottom: '1px solid var(--border-1)', textAlign: 'right', whiteSpace: 'nowrap',
    fontFamily: 'var(--font-mono)', fontSize: 12.5, lineHeight: 1.3, fontVariantNumeric: 'tabular-nums' },
  subLabel: { font: '500 10.5px/1.3 var(--font-sans)', color: 'var(--fg-3)', marginTop: 2 },
  rlSub: { font: '600 10px/1.3 var(--font-mono)', color: 'var(--fg-3)', marginTop: 3 },
  dim: { color: 'var(--fg-4)' },
};

window.DreAfiliadosView = DreAfiliadosView;
