// Reembolso → Reembolso Geral (spec 2026-07-31). Página self-contained: KPIs + tabela por
// produto, tendência diária, quebra por funil, cohort mensal × aging e margem por afiliado.
// Escopo BuyGoods. Taxa canônica DOCX 5.1 (refunds + chargebacks + CANCELAMENTOS) — difere
// de propósito do Calendário de Reembolso, que usa Reemb+CGBK.
//
// PREFIXO `rg`/`Rg`/`RG_` em TODOS os identificadores de topo (escopo Babel compartilhado).
// SEM mock: número inventado de refund é dado falso. Offline mostra card honesto com retry
// automático; com dado velho na tela, notice âmbar.

const RG_MESES_PT = ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'];

// Etapas do funil na ordem de leitura. As chaves são as do payload (fe/up/down).
const RG_ETAPAS = [
  { key: 'fe',   label: 'Front End', color: 'var(--fenix-navy)' },
  { key: 'up',   label: 'Upsell',    color: 'var(--fenix-orange)' },
  { key: 'down', label: 'Downsell',  color: 'var(--fenix-blue)' },
];

// pctValor/pctQtd/pctRefund/taxaQtd voltam null quando não há venda na base — "—", nunca 0%.
const rgPct = (v) => (v == null ? '—' : PCT(v));

// Semáforo na própria fonte das taxas — rodada 2: >20 vermelho, >14 laranja e o
// resto VERDE (pedido do usuário: toda taxa da tabela é verde/amarela/vermelha).
const rgCorTaxa = (v) => (
  v == null ? 'var(--fg-4)'
  : v > 20 ? 'var(--negative)'
  : v > 14 ? 'var(--warning)'
  : 'var(--positive)'
);

// Hover padrão de linha de tabela: indigo wash da marca (--fenix-blue-100) — vivo,
// mas semanticamente livre: não colide com verde/âmbar/vermelho das células nem com
// o laranja-100, que é cor de item SELECIONADO nos dropdowns.
const rgRowHover = {
  onMouseEnter: (e) => { e.currentTarget.style.background = 'var(--fenix-blue-100)'; },
  onMouseLeave: (e) => { e.currentTarget.style.background = 'transparent'; },
};

const rgMes = (m) => {
  const [y, mo] = String(m).split('-');
  return `${RG_MESES_PT[Number(mo) - 1] || mo}/${String(y).slice(2)}`;
};

// 'YYYY-MM-DD' puro é lido como UTC e volta um dia no fuso -03 — o T12:00:00 é OBRIGATÓRIO.
const rgDia = (iso) => {
  const d = new Date(iso + 'T12:00:00');
  const wd = d.toLocaleDateString('pt-BR', { weekday: 'short' }).replace('.', '');
  return `${wd} ${d.toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' })}`;
};
const rgDdMm = (iso) => new Date(iso + 'T12:00:00')
  .toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' });

// Célula de dinheiro devolvido: vermelha quando saiu dinheiro, travessão quando não houve
// evento (n === 0). Zero com evento é informação; zero sem evento é ruído.
const rgDev = (usd, n) => (n === 0 ? '—' : USD(usd));

const rgChipEtapa = (etapa) => (
  String(etapa).startsWith('Upsell')    ? { color: 'var(--negative)', background: 'var(--negative-bg)' }
  : String(etapa).startsWith('Front End') ? { color: 'var(--positive)', background: 'var(--positive-bg)' }
  : { color: 'var(--fg-2)', background: 'var(--gray-100)' }
);

// Cabeçalho ordenável. `k` ausente = coluna não ordenável (Status).
const RgTh = ({ k, label, align = 'right', sortKey, sortDir, onSort }) => (
  <th style={{ ...rgx.th, textAlign: align, ...(k ? rgx.thSort : {}) }}
    onClick={k ? () => onSort(k) : undefined}>
    {label}{k && sortKey === k ? (sortDir < 0 ? ' ▾' : ' ▴') : ''}
  </th>
);

const RefundGeneralView = ({ onKpiSelect } = {}) => {
  const [period, setPeriod] = React.useState('30d');
  const [customRange, setCustomRange] = React.useState(null);
  const [products, setProducts] = React.useState([]);
  const [affiliate, setAffiliate] = React.useState('todos');
  const [funnelTag, setFunnelTag] = React.useState('todos');
  const [refundBy, setRefundBy] = React.useState('pedido');
  const [sortKey, setSortKey] = React.useState('vendasUsd');
  const [sortDir, setSortDir] = React.useState(-1);
  const [data, setData] = React.useState(null);
  const [err, setErr] = React.useState(false);
  const [tick, setTick] = React.useState(0);          // polling de 15 min
  const fullLoading = useFullLoading();
  const withLoad = (fn) => (...a) => { fullLoading.mark(); fn(...a); };
  const retry = useAutoRetry(err);                    // falhou → tenta de novo a cada 15s

  React.useEffect(() => {
    const began = fullLoading.begin();
    let cancelled = false;
    let timer = null;
    fetchRefundGeneralAPI({ period, customRange, products, affiliate, funnelTag, refundBy })
      .then(d => {
        if (!cancelled) {
          setData(d); setErr(false);
          timer = setTimeout(() => setTick(t => t + 1), 15 * 60 * 1000);
        }
      })
      .catch(() => { if (!cancelled) setErr(true); })
      .finally(() => { if (!cancelled) fullLoading.end(began); });
    return () => { cancelled = true; if (timer) clearTimeout(timer); };
  }, [period, customRange, products, affiliate, funnelTag, refundBy, retry, tick]);

  // 1º load falhou: LoadingScreen offline + retry automático — nunca um card estático sem
  // retry (requisito ui-fenix). LoadingScreen não tem prop `note`: a nota vai como irmã,
  // igual ao Calendário de Reembolso.
  if (!data && err) return (
    <>
      <LoadingScreen conn="offline" />
      <div style={rgx.reconNota}>
        Sem conexão com a API do Reembolso Geral — reconectando automaticamente a cada 15s.
        Esta tela não tem versão de demonstração: refund inventado é pior que tela vazia.
      </div>
    </>
  );
  if (!data) return <LoadingScreen conn="connecting" />;

  const k = data.kpis;
  const sortBy = (col) => (col === sortKey ? setSortDir(-sortDir) : (setSortKey(col), setSortDir(-1)));
  // Três vias (>, <, empate): um comparador que nunca devolve 0 é inconsistente e a ordem
  // dos empates fica à mercê do algoritmo de sort.
  const produtos = [...data.produtos].sort((a, b) => {
    const x = a[sortKey] ?? -1, y = b[sortKey] ?? -1;
    return sortDir * (x > y ? 1 : x < y ? -1 : 0);
  });

  const tend = data.tendencia || { granularity: 'day', pontos: [], total: null };
  const semana = tend.granularity === 'week';
  const rotuloBucket = (b) => (semana ? rgDdMm(b) : rgDia(b));

  // Share de cada etapa dentro das 3 etapas rastreadas (SMS ainda não tem tracking).
  const rgShare = (bloco, e) => {
    const tot = RG_ETAPAS.reduce((s, x) => s + ((bloco[x.key] && bloco[x.key].n) || 0), 0);
    return tot ? ((bloco[e].n / tot) * 100).toFixed(1).replace('.', ',') : '0,0';
  };

  const pfTot = (data.produtoFunil || []).reduce((t, p) => {
    RG_ETAPAS.forEach(e => { t[e.key].n += p[e.key].n; t[e.key].usd += p[e.key].usd; });
    return t;
  }, { fe: { n: 0, usd: 0 }, up: { n: 0, usd: 0 }, down: { n: 0, usd: 0 } });

  const meses = (data.cohort && data.cohort.meses) || [];
  const cohortProdutos = (data.cohort && data.cohort.produtos) || [];
  const aTot = data.agingTotal || { refunds: 0, usd: 0 };

  return (
    <div style={{ position: 'relative' }}>
      <div style={rgx.filterRow}>
        <PeriodSelector period={period} setPeriod={withLoad(setPeriod)}
          customRange={customRange} setCustomRange={withLoad(setCustomRange)} />
        <MultiDropdown icon="cart" label="Produto" values={products} onChange={withLoad(setProducts)}
          options={(data.familias || []).map(f => ({ key: f, label: f }))} />
        <SearchDropdown icon="users" label="Afiliado" value={affiliate} onChange={withLoad(setAffiliate)}
          options={[{ key: 'todos', label: 'Todos' },
                    ...(data.roster || []).map(a => ({ key: a, label: a }))]} />
        <Dropdown icon="trending" label="Funil" value={funnelTag} onChange={withLoad(setFunnelTag)}
          options={[{ key: 'todos', label: 'Todos' },
                    ...(data.funis || []).map(t => ({ key: t, label: t.toUpperCase() }))]} />
        <Dropdown icon="refresh" label="Reembolso" value={refundBy} onChange={withLoad(setRefundBy)}
          options={REFUND_BY_OPTIONS} />
      </div>

      {refundBy === 'cancelamento' && <RefundByNote refundBy={refundBy} />}

      {err && data && (
        <div style={rgx.notice}><Icon name="alert" size={14} color="currentColor" />
          Falha ao atualizar — mostrando os últimos dados. Tentando reconectar…</div>
      )}

      {/* ---------------- SETOR 1 — visão geral por produto ---------------- */}
      <SectionTitle n={1} first label="Reembolso Geral"
        sub="Vendas, devoluções e taxa por produto — escopo BuyGoods" />

      <div style={rgx.kpiRow5}>
        <DotKpi hoverable eye="Vendas Brutas" color="var(--fenix-navy)" value={USDk(k.grossSales)}
          sub={`${NUM(k.grossOrders)} pedidos · ${k.nProdutos} produtos`} />
        <DotKpi hoverable eye="Total Refunds" color="var(--negative)" value={USDk(k.refundAmount)}
          valColor="var(--negative)" sub={`${NUM(k.refundCount)} transações`}
          onClick={onKpiSelect ? () => onKpiSelect({ eye: 'Total Refunds', val: USDk(k.refundAmount),
            sub: `${NUM(k.refundCount)} transações`, icon: 'refresh', tint: 'var(--negative-bg)',
            fg: 'var(--negative)', kind: 'rg-refund', data: { ...k } }) : undefined} />
        <DotKpi hoverable eye="Chargebacks" color="var(--negative)" value={USDk(k.cgbkAmount)}
          valColor="var(--negative)" sub={`${NUM(k.cgbkCount)} transações`}
          onClick={onKpiSelect ? () => onKpiSelect({ eye: 'Chargebacks', val: USDk(k.cgbkAmount),
            sub: `${NUM(k.cgbkCount)} transações`, icon: 'alert', tint: 'var(--negative-bg)',
            fg: 'var(--negative)', kind: 'rg-refund', data: { ...k } }) : undefined} />
        <DotKpi hoverable eye="% Refund (R$)" color="var(--fg-3)" value={PCT(k.pctRefundValor)}
          health={refundHealth(k.taxa)} />
        {/* Net = vendas − refunds − cgbk − CANCELAMENTOS. Os dois cards do meio são
            ESTRITOS (refunds e cgbk), então o dinheiro dos cancelamentos não aparece em
            lugar nenhum da linha — o sub nomeia essa saída quando ela existe. */}
        <DotKpi hoverable eye="Net Revenue" color="var(--positive)" value={USDk(k.netRevenue)}
          valColor="var(--positive)"
          sub={k.cancelCount > 0
            ? `após refunds, cgbk e ${NUM(k.cancelCount)} cancelamentos`
            : 'após todas as saídas'} />
      </div>

      <div style={rgx.card}>
        <div style={rgx.cardEye}>Por produto · top 10 por receita</div>
        <div style={rgx.scroll}>
          <table style={rgx.table}>
            <thead><tr>
              <RgTh k="label" label="Produto" align="left" sortKey={sortKey} sortDir={sortDir} onSort={sortBy} />
              <RgTh k="vendas" label="Pedidos" sortKey={sortKey} sortDir={sortDir} onSort={sortBy} />
              <RgTh k="vendasUsd" label="Vendas ($)" sortKey={sortKey} sortDir={sortDir} onSort={sortBy} />
              {/* Devolvidos (largo) e não refunds (estrito): as colunas % ao lado são
                  calculadas sobre refunds+cgbk+cancel. Com a coluna estrita a tabela não
                  dividia — Memo Matrix dava 14,64% na conta do leitor e 16,16% impresso. */}
              <RgTh k="devolvidos" label="Devolvidos" sortKey={sortKey} sortDir={sortDir} onSort={sortBy} />
              <RgTh k="devolvidoUsd" label="Devolvido ($)" sortKey={sortKey} sortDir={sortDir} onSort={sortBy} />
              <RgTh k="pctValor" label="% Ref (R$)" sortKey={sortKey} sortDir={sortDir} onSort={sortBy} />
              <RgTh k="pctQtd" label="% Ref (Qtd)" sortKey={sortKey} sortDir={sortDir} onSort={sortBy} />
            </tr></thead>
            <tbody>
              {produtos.map(p => (
                <tr key={p.label} {...rgRowHover}>
                  <td style={{ ...rgx.tdNome, width: '18%' }}>{p.label}</td>
                  <td style={rgx.tdNum} className="fenix-num">{NUM(p.vendas)}</td>
                  <td style={rgx.tdNum} className="fenix-num">{USD(p.vendasUsd)}</td>
                  <td style={rgx.tdNum} className="fenix-num">{NUM(p.devolvidos)}</td>
                  <td style={{ ...rgx.tdNum, color: p.devolvidoUsd > 0 ? 'var(--negative)' : 'var(--fg-3)' }}
                    className="fenix-num">{USD(p.devolvidoUsd)}</td>
                  {/* semáforo na fonte das DUAS taxas: verde ≤14 · laranja >14 · vermelho >20 */}
                  <td style={{ ...rgx.tdNum, fontWeight: 700, color: rgCorTaxa(p.pctValor) }}
                    className="fenix-num">{rgPct(p.pctValor)}</td>
                  <td style={{ ...rgx.tdNum, fontWeight: 700, color: rgCorTaxa(p.pctQtd) }}
                    className="fenix-num">{rgPct(p.pctQtd)}</td>
                </tr>
              ))}
              {produtos.length === 0 && (
                <tr><td colSpan={7} style={rgx.vazio}>Sem produto no período escolhido.</td></tr>
              )}
            </tbody>
          </table>
        </div>
        <div style={rgx.legenda}>
          Devolvidos = refunds + chargebacks + cancelamentos (régua DOCX 5.1). Os KPIs
          "Total Refunds" e "Chargebacks" acima são estritos.
        </div>
      </div>

      {/* ---------------- SETOR 2 — tendência ---------------- */}
      <SectionTitle n={2} label="Tendência diária"
        sub="Vendas, devoluções e taxa dia a dia — a curva mostra a taxa; a tabela, os valores" />

      <RefundRateOverTime
        timeseries={(tend.pontos || []).map(p => ({ sales: p.vendas, refunds: p.refunds }))}
        style={{ marginBottom: 16 }} />

      <div style={rgx.card}>
        <div style={rgx.cardEye}>{semana ? 'Por semana' : 'Por dia'}</div>
        <div style={rgx.scroll}>
          <table style={rgx.table}>
            <thead><tr>
              <th style={{ ...rgx.th, textAlign: 'left' }}>{semana ? 'Semana' : 'Data'}</th>
              <th style={rgx.th}>Pedidos</th>
              <th style={rgx.th}>Vendas $</th>
              <th style={rgx.th}>Refunds</th>
              <th style={rgx.th}>Refund $</th>
              <th style={rgx.th}>Net $</th>
              <th style={rgx.th}>% Ref</th>
            </tr></thead>
            <tbody>
              {(tend.pontos || []).map(p => (
                <tr key={p.bucket} {...rgRowHover}>
                  <td style={rgx.tdNomeNum} className="fenix-num">{rotuloBucket(p.bucket)}</td>
                  <td style={rgx.tdNum} className="fenix-num">{NUM(p.vendas)}</td>
                  <td style={rgx.tdNum} className="fenix-num">{USD(p.vendasUsd)}</td>
                  <td style={rgx.tdNum} className="fenix-num">{NUM(p.refunds)}</td>
                  <td style={{ ...rgx.tdNum, color: p.refundUsd > 0 ? 'var(--negative)' : 'var(--fg-3)' }}
                    className="fenix-num">{USD(p.refundUsd)}</td>
                  <td style={{ ...rgx.tdNum, fontWeight: 700 }} className="fenix-num">{USD(p.netUsd)}</td>
                  {/* mesmo padrão da tabela Por Produto: semáforo na fonte, sem preenchimento */}
                  <td style={{ ...rgx.tdNum, fontWeight: 700, color: rgCorTaxa(p.taxa) }}
                    className="fenix-num">{PCT(p.taxa)}</td>
                </tr>
              ))}
              {tend.total && (
                <tr>
                  <td style={{ ...rgx.tdTot, textAlign: 'left' }}>TOTAL</td>
                  <td style={rgx.tdTot} className="fenix-num">{NUM(tend.total.vendas)}</td>
                  <td style={rgx.tdTot} className="fenix-num">{USD(tend.total.vendasUsd)}</td>
                  <td style={rgx.tdTot} className="fenix-num">{NUM(tend.total.refunds)}</td>
                  <td style={rgx.tdTot} className="fenix-num">{USD(tend.total.refundUsd)}</td>
                  <td style={rgx.tdTot} className="fenix-num">{USD(tend.total.netUsd)}</td>
                  <td style={rgx.tdTot} className="fenix-num">{PCT(tend.total.taxa)}</td>
                </tr>
              )}
              {(tend.pontos || []).length === 0 && (
                <tr><td colSpan={7} style={rgx.vazio}>Sem movimento no período escolhido.</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      {/* ---------------- SETOR 3 — funil ---------------- */}
      <SectionTitle n={3} label="Reembolso por Funil" sub="Front End · Upsell · Downsell · SMS" />

      <div style={rgx.kpiRow4}>
        {RG_ETAPAS.map(e => (
          <DotKpi hoverable key={'v' + e.key} eye={`${e.label} — Vendas`} color={e.color}
            value={USDk(data.funil.vendas[e.key].usd)}
            sub={`${NUM(data.funil.vendas[e.key].n)} pedidos · ${rgShare(data.funil.vendas, e.key)}%`} />
        ))}
        <DotKpi hoverable eye="SMS — Vendas" color="var(--gray-300)" value="—"
          sub="sem tracking ainda" subColor="var(--fg-4)" />
      </div>

      <div style={rgx.kpiRow4}>
        {RG_ETAPAS.map(e => (
          <DotKpi hoverable key={'r' + e.key} eye={`${e.label} — Refund`} color="var(--negative)"
            value={USDk(data.funil.refunds[e.key].usd)} valColor="var(--negative)"
            sub={`${NUM(data.funil.refunds[e.key].n)} refunds · ${rgShare(data.funil.refunds, e.key)}%`} />
        ))}
        <DotKpi hoverable eye="SMS — Refund" color="var(--gray-300)" value="—"
          sub="sem tracking ainda" subColor="var(--fg-4)" />
      </div>

      {/* --------- 3.1 — produto × funil e top SKUs --------- */}
      <div style={rgx.card}>
        <div style={rgx.cardEye}>Refunds por Produto × Funil</div>
        <div style={rgx.scroll}>
          <table style={rgx.table}>
            <thead><tr>
              <th style={{ ...rgx.th, textAlign: 'left' }}>Produto</th>
              <th style={rgx.th}>FE ($)</th>
              <th style={rgx.th}># FE</th>
              <th style={rgx.th}>Upsell ($)</th>
              <th style={rgx.th}># Ups</th>
              <th style={rgx.th}>Downsell ($)</th>
              <th style={rgx.th}># Dws</th>
              <th style={rgx.th}>SMS</th>
            </tr></thead>
            <tbody>
              {(data.produtoFunil || []).map(p => (
                <tr key={p.label} {...rgRowHover}>
                  <td style={rgx.tdNome}>{p.label}</td>
                  {RG_ETAPAS.map(e => [
                    <td key={e.key + '$'} style={{ ...rgx.tdNum,
                      color: p[e.key].usd > 0 ? 'var(--negative)' : 'var(--fg-4)' }}
                      className="fenix-num">{rgDev(p[e.key].usd, p[e.key].n)}</td>,
                    <td key={e.key + '#'} style={{ ...rgx.tdNum,
                      color: p[e.key].n ? 'var(--fg-1)' : 'var(--fg-4)' }}
                      className="fenix-num">{p[e.key].n ? NUM(p[e.key].n) : '—'}</td>,
                  ])}
                  <td style={{ ...rgx.tdNum, color: 'var(--fg-4)' }}>—</td>
                </tr>
              ))}
              {(data.produtoFunil || []).length > 0 && (
                <tr>
                  <td style={{ ...rgx.tdTot, textAlign: 'left' }}>TOTAL</td>
                  {RG_ETAPAS.map(e => [
                    <td key={e.key + '$'} style={rgx.tdTot} className="fenix-num">{USD(pfTot[e.key].usd)}</td>,
                    <td key={e.key + '#'} style={rgx.tdTot} className="fenix-num">{NUM(pfTot[e.key].n)}</td>,
                  ])}
                  <td style={rgx.tdTot}>—</td>
                </tr>
              )}
              {(data.produtoFunil || []).length === 0 && (
                <tr><td colSpan={8} style={rgx.vazio}>Sem devolução por etapa no período.</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      <div style={rgx.card}>
        <div style={rgx.cardEye}>Top SKUs por Volume de Refund</div>
        <div style={rgx.scroll}>
          <table style={rgx.table}>
            <thead><tr>
              <th style={{ ...rgx.th, textAlign: 'left' }}>Codename</th>
              <th style={{ ...rgx.th, textAlign: 'left' }}>Produto</th>
              <th style={rgx.th}>Vendas</th>
              <th style={rgx.th}># Refunds</th>
              <th style={rgx.th}>Valor ($)</th>
              <th style={{ ...rgx.th, textAlign: 'left' }}>Funil</th>
            </tr></thead>
            <tbody>
              {(data.topSkus || []).map((s, i) => (
                <tr key={s.codename + '·' + s.etapa + '·' + i} {...rgRowHover}>
                  <td style={rgx.tdMono}>{s.codename}</td>
                  <td style={rgx.tdNome}>{s.produto}</td>
                  <td style={rgx.tdNum} className="fenix-num">{NUM(s.vendas)}</td>
                  <td style={rgx.tdNum} className="fenix-num">{NUM(s.refunds)}</td>
                  <td style={{ ...rgx.tdNum, fontWeight: 700, color: 'var(--negative)' }}
                    className="fenix-num">{USD(s.usd)}</td>
                  <td style={rgx.tdChip}>
                    <span style={{ ...rgx.chip, ...rgChipEtapa(s.etapa) }}>{s.etapa}</span>
                  </td>
                </tr>
              ))}
              {(data.topSkus || []).length === 0 && (
                <tr><td colSpan={6} style={rgx.vazio}>Sem SKU com devolução no período.</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      {/* ---------------- SETOR 4 — cohort & aging ---------------- */}
      <SectionTitle n={4} label="Cohort Mensal & Aging"
        sub="Refunds processados na janela × mês da compra — esta seção não segue o filtro Refund (visão-caixa fixa)" />

      <div style={rgx.card}>
        <div style={rgx.cardEye}>Cohort mensal · top {cohortProdutos.length || 5} produtos</div>
        <div style={rgx.scroll}>
          <table style={rgx.table}>
            <thead><tr>
              <th style={{ ...rgx.th, textAlign: 'left' }}>Produto</th>
              {meses.map(m => [
                <th key={m + '$'} style={rgx.th}>{rgMes(m)} ($)</th>,
                <th key={m + '#'} style={rgx.th}>{rgMes(m)} Qtd</th>,
              ])}
            </tr></thead>
            <tbody>
              {cohortProdutos.map(p => (
                <tr key={p.label} {...rgRowHover}>
                  <td style={rgx.tdNome}>{p.label}</td>
                  {meses.map((m, i) => {
                    const c = p.porMes[i] || { n: 0, usd: 0 };
                    return [
                      <td key={m + '$'} style={{ ...rgx.tdNum,
                        color: c.usd > 0 ? 'var(--negative)' : 'var(--fg-4)' }}
                        className="fenix-num">{rgDev(c.usd, c.n)}</td>,
                      <td key={m + '#'} style={{ ...rgx.tdNum,
                        color: c.n ? 'var(--fg-1)' : 'var(--fg-4)' }}
                        className="fenix-num">{c.n ? NUM(c.n) : '—'}</td>,
                    ];
                  })}
                </tr>
              ))}
              {(cohortProdutos.length === 0 || meses.length === 0) && (
                <tr><td colSpan={Math.max(1 + meses.length * 2, 2)} style={rgx.vazio}>
                  Sem refund processado na janela.</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      <div style={rgx.card}>
        <div style={rgx.cardEye}>Aging — dias entre a compra e o refund</div>
        <div style={rgx.scroll}>
          <table style={rgx.table}>
            <thead><tr>
              <th style={{ ...rgx.th, textAlign: 'left' }}>Bucket</th>
              <th style={rgx.th}># Refunds</th>
              <th style={rgx.th}>Valor ($)</th>
              <th style={rgx.th}>% Qtd</th>
              <th style={rgx.th}>% Valor</th>
            </tr></thead>
            <tbody>
              {(data.aging || []).map(a => (
                <tr key={a.bucket} {...rgRowHover}>
                  <td style={rgx.tdNome}>{a.bucket}</td>
                  <td style={rgx.tdNum} className="fenix-num">{NUM(a.refunds)}</td>
                  <td style={{ ...rgx.tdNum, color: a.usd > 0 ? 'var(--negative)' : 'var(--fg-4)' }}
                    className="fenix-num">{USD(a.usd)}</td>
                  <td style={rgx.tdNum} className="fenix-num">{PCT(a.pctQtd)}</td>
                  <td style={rgx.tdNum} className="fenix-num">{PCT(a.pctValor)}</td>
                </tr>
              ))}
              <tr>
                <td style={{ ...rgx.tdTot, textAlign: 'left' }}>TOTAL</td>
                <td style={rgx.tdTot} className="fenix-num">{NUM(aTot.refunds)}</td>
                <td style={rgx.tdTot} className="fenix-num">{USD(aTot.usd)}</td>
                <td style={rgx.tdTot} className="fenix-num">{aTot.refunds ? PCT(100) : '—'}</td>
                <td style={rgx.tdTot} className="fenix-num">{aTot.refunds ? PCT(100) : '—'}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>

      {/* ---------------- SETOR 5 — afiliados ---------------- */}
      <SectionTitle n={5} label="Margem por Afiliado"
        sub="Margem = vendas do afiliado − devoluções no mesmo período · top 12 por volume" />

      <div style={rgx.card}>
        <div style={rgx.cardEye}>Top 12 afiliados por volume</div>
        <div style={rgx.scroll}>
          <table style={rgx.table}>
            <thead><tr>
              <th style={{ ...rgx.th, textAlign: 'left' }}>Afiliado</th>
              <th style={rgx.th}>Vendas ($)</th>
              <th style={rgx.th}>Devolvido ($)</th>
              <th style={rgx.th}>Margem ($)</th>
              <th style={rgx.th}>% Refund</th>
              <th style={rgx.th}>% Margem</th>
            </tr></thead>
            <tbody>
              {(data.afiliados || []).map(a => (
                <tr key={a.label} {...rgRowHover}>
                  <td style={rgx.tdNome}>{a.label}</td>
                  <td style={rgx.tdNum} className="fenix-num">{USD(a.vendasUsd)}</td>
                  <td style={{ ...rgx.tdNum, color: a.devolvidoUsd > 0 ? 'var(--negative)' : 'var(--fg-3)' }}
                    className="fenix-num">{USD(a.devolvidoUsd)}</td>
                  <td style={{ ...rgx.tdNum, fontWeight: 700,
                    color: a.margemUsd > 0 ? 'var(--positive)'
                         : a.margemUsd < 0 ? 'var(--negative)' : 'var(--fg-3)' }}
                    className="fenix-num">{USD(a.margemUsd)}</td>
                  <td style={{ ...rgx.tdNum,
                    color: a.pctRefund == null ? 'var(--fg-4)' : refundHealth(a.pctRefund).color }}
                    className="fenix-num">{rgPct(a.pctRefund)}</td>
                  {/* Régua única: % Margem é o complemento de % Refund, então herda a MESMA
                      cor de saúde. Inverter refundHealth aqui pintaria 95% de margem de
                      vermelho "Corte" — leitura oposta à verdade. */}
                  <td style={{ ...rgx.tdNum,
                    color: a.pctRefund == null ? 'var(--fg-4)' : refundHealth(a.pctRefund).color }}
                    className="fenix-num">{rgPct(a.pctMargem)}</td>
                </tr>
              ))}
              {(data.afiliados || []).length === 0 && (
                <tr><td colSpan={6} style={rgx.vazio}>Sem afiliado no período escolhido.</td></tr>
              )}
            </tbody>
          </table>
        </div>
        <div style={rgx.nota}>
          Afiliado sem vendas mostra apenas saída de períodos anteriores.
        </div>
      </div>

      <div style={{ fontSize: 12, color: 'var(--fg-4)', marginTop: 16 }}>
        Escopo BuyGoods · Taxa canônica DOCX 5.1 (inclui cancelamentos) — difere do
        Calendário de Reembolso, que usa Reemb+CGBK.
      </div>

      <FullLoadingOverlay show={fullLoading.show && !!data} conn="connecting" />
    </div>
  );
};

const rgx = {
  filterRow: { display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap', marginBottom: 12 },
  notice: { display: 'flex', alignItems: 'center', gap: 6, font: '600 12px/1.4 var(--font-sans)',
    color: 'var(--warning)', background: 'var(--warning-bg)', padding: '10px 16px',
    borderRadius: 'var(--r-md)', marginBottom: 12 },
  reconNota: { textAlign: 'center', font: 'var(--text-body-sm)', color: 'var(--fg-4)',
    maxWidth: 520, margin: '-28px auto 0' },

  kpiRow5: { display: 'grid', gridTemplateColumns: 'repeat(5,minmax(0,1fr))', gap: 12, marginBottom: 16 },
  kpiRow4: { display: 'grid', gridTemplateColumns: 'repeat(4,minmax(0,1fr))', gap: 12, marginBottom: 16 },

  card: { background: '#fff', border: '1px solid var(--border-1)', borderRadius: 'var(--r-lg)',
    boxShadow: 'var(--shadow-sm)', padding: '16px 20px 8px', marginBottom: 16 },
  cardEye: { font: 'var(--text-label)', letterSpacing: '.05em', textTransform: 'uppercase',
    color: 'var(--fg-3)', marginBottom: 10 },
  scroll: { overflowX: 'auto' },

  table: { width: '100%', borderCollapse: 'collapse' },
  th: { font: '700 10.5px/1 var(--font-sans)', letterSpacing: '.04em', textTransform: 'uppercase',
    color: 'var(--fg-3)', padding: '10px 12px', background: 'var(--bg-sunken)',
    borderTop: '1px solid var(--border-2)', borderBottom: '1px solid var(--border-2)',
    whiteSpace: 'nowrap', textAlign: 'right' },
  thSort: { cursor: 'pointer', userSelect: 'none' },

  tdNome: { padding: '10px 12px', borderBottom: '1px solid var(--border-1)',
    font: '700 12.5px/1.2 var(--font-sans)', color: 'var(--fg-1)', textAlign: 'left' },
  // longhands DEPOIS do shorthand `font:` — inline vence a classe .fenix-num
  tdNomeNum: { padding: '10px 12px', borderBottom: '1px solid var(--border-1)',
    font: '600 12.5px/1.2 var(--font-sans)', color: 'var(--fg-1)', textAlign: 'left',
    whiteSpace: 'nowrap', fontFamily: 'var(--font-num)', fontVariantNumeric: 'tabular-nums' },
  tdMono: { padding: '10px 12px', borderBottom: '1px solid var(--border-1)', textAlign: 'left',
    whiteSpace: 'nowrap', font: '600 12px/1.2 var(--font-sans)', color: 'var(--fenix-navy)',
    fontFamily: 'var(--font-mono, monospace)' },
  tdNum: { padding: '10px 12px', borderBottom: '1px solid var(--border-1)', textAlign: 'right',
    whiteSpace: 'nowrap', font: 'var(--text-body-sm)', color: 'var(--fg-1)',
    fontFamily: 'var(--font-num)', fontVariantNumeric: 'tabular-nums' },
  tdChip: { padding: '10px 12px', borderBottom: '1px solid var(--border-1)', textAlign: 'left' },
  tdTot: { padding: '11px 12px', textAlign: 'right', whiteSpace: 'nowrap',
    font: '700 12.5px/1.2 var(--font-sans)', color: '#fff', background: 'var(--fenix-navy)',
    fontFamily: 'var(--font-num)', fontVariantNumeric: 'tabular-nums' },

  chip: { display: 'inline-block', font: '700 10.5px/1 var(--font-sans)', padding: '5px 9px',
    borderRadius: 'var(--r-pill)', whiteSpace: 'nowrap' },

  vazio: { padding: '34px 12px', textAlign: 'center', font: 'var(--text-body-sm)', color: 'var(--fg-4)' },
  legenda: { fontSize: 12, lineHeight: 1.5, color: 'var(--fg-4)', padding: '12px 2px' },
  nota: { font: '500 11px/1.6 var(--font-sans)', color: 'var(--fg-4)', padding: '12px 2px' },
};

Object.assign(window, { RefundGeneralView });
