// KpiDrawer — barra lateral ao clicar em KPI card. Segue padrão do AffiliateDrawer.
// Cada KPI tem um `kind` que roteia o conteúdo (spec 2026-07-03 — todas clicáveis).

// Limite inferior de Wilson (90%) — espelho do backend. Ranqueia "muita venda E muito refund":
// 1 venda/100% → ~0 (sem prova); 500 vendas/25% → alto. n=0 → 0.
function wilsonLB(k, n, z = 1.6449) {
  if (!n || n <= 0) return 0;
  const p = Math.min(Math.max(k / n, 0), 1);
  const d = 1 + z * z / n;
  const center = (p + z * z / (2 * n)) / d;
  const half = z * Math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)) / d;
  return Math.max(center - half, 0);
}

// Linhas da composição do faturamento (card "Total Receita Canal").
const _compLines = (b) => !b ? [] : [
  { label:'Direto · Front-end',   value:b.directFrontend.revenue, orders:b.directFrontend.orders,
    refA:b.directFrontend.refundAmount, refC:b.directFrontend.refundCount, color:'var(--fenix-orange-600)' },
  { label:'Direto · Back-end',    value:b.directBackend.revenue,  orders:b.directBackend.orders,
    refA:b.directBackend.refundAmount,  refC:b.directBackend.refundCount,  color:'#FB923C' },
  { label:'Logicall (líquido)',   value:b.logicall.net,               orders:b.logicall.orders,
    refA:b.logicall.refundAmount,           refC:b.logicall.refundCount,           color:'#D8453B' },
  ...(b.tauk ? [{ label:'Tauk (líquido)', value:b.tauk.net, orders:b.tauk.orders,
    refA:b.tauk.refundAmount, refC:b.tauk.refundCount, color:'#B03A30' }] : []),
  { label:'Salesbound (líquido)', value:b.salesbound.net,         orders:b.salesbound.orders,
    refA:b.salesbound.refundAmount,     refC:b.salesbound.refundCount,     color:'#7C3AED' },
];

// Seção genérica de linhas (label / sub / valor) no estilo da composição.
const KDLines = ({ eye, lines, note }) => (
  <div style={kd.compCard}>
    <div style={kd.compEye}>{eye}</div>
    {lines.map((l, i) => (
      <div key={i} style={kd.compRow}>
        {l.color && <span style={{ ...kd.compDot, background: l.color }} />}
        <div style={kd.compMain}>
          <div style={kd.compLabel}>{l.label}</div>
          {l.sub && <div style={kd.compSub}>{l.sub}</div>}
        </div>
        <span style={{ ...kd.compVal, ...(l.fg ? { color: l.fg } : {}) }} className="fenix-num">{l.value}</span>
      </div>
    ))}
    {note && <div style={kd.compNote}>{note}</div>}
  </div>
);

// Blocos do drawer de AOV por checkout (specs 2026-07-10 + 2026-07-24): (receita FE +
// receita BE) ÷ ordens FE — os chamadores devem passar os campos *_aov, JÁ líquidos da
// taxa buygoods no backend (queries.REV_AOV); feRev/beRev "crus" do payload são BRUTOS.
const KDAovBlocks = ({ feRev, feOrders, beRev, beOrders }) => {
  const feT = feOrders ? feRev / feOrders : 0;
  const upsPer = feOrders ? beRev / feOrders : 0;
  const beT = beOrders ? beRev / beOrders : 0;
  const take = feOrders ? (beOrders / feOrders) * 100 : 0;
  return (
    <>
      <KDLines eye="AOV = por checkout" lines={[
        { label: 'Ticket Front-end', value: USD(feT) },
        { label: 'Upsells por checkout', value: USD(upsPer) },
        { label: 'AOV por checkout', value: USD(feT + upsPer) },
      ]} note="(receita FE + receita BE) ÷ ordens FE." />
      <KDLines eye="Detalhe do back-end" lines={[
        { label: 'Ticket BE (quem levou)', value: beOrders ? USD(beT) : '—' },
        { label: 'Take-rate de upsell', sub: NUM(beOrders) + ' upsells em ' + NUM(feOrders) + ' checkouts',
          value: PCT(take) },
      ]} />
    </>
  );
};

// Conteúdo do drawer por kind (spec 2026-07-03).
const KDContent = ({ k }) => {
  const d = k.data || {};
  const c = d.composition;
  if (k.kind === 'vendas') {
    const line = (label, v, sub, color) => ({ label, value: v != null ? NUM(v) : '—', sub, color });
    return <KDLines eye="Detalhe das vendas" lines={c ? [
      line('Vendas FE (front-end)', c.directFrontend.orders, USDk(c.directFrontend.revenue), 'var(--fenix-orange-600)'),
      line('Vendas BE (upsells)', c.directBackend.orders, USDk(c.directBackend.revenue), '#FB923C'),
      line('Vendas Logicall', c.logicall.orders, USDk(c.logicall.net) + ' líquido', '#D8453B'),
      ...(c.tauk ? [line('Vendas Tauk', c.tauk.orders, USDk(c.tauk.net) + ' líquido', '#B03A30')] : []),
      line('Vendas Salesbound', c.salesbound.orders, USDk(c.salesbound.net) + ' líquido', '#7C3AED'),
      line('Total de reembolsos', c.directFrontend.refundCount + c.directBackend.refundCount,
        USDk(c.directFrontend.refundAmount + c.directBackend.refundAmount) + ' devolvidos', 'var(--negative)'),
    ] : [{ label: 'Sem composição no período', value: '—' }]}
      note="FE/BE e reembolsos do canal direto (por coorte de venda); Logicall/Salesbound pela atribuição por email." />;
  }
  if (k.kind === 'refund-wilson') {
    // Quanto voltou em $ (canal direto): refunds + chargebacks SOMADOS, com breakout explícito.
    const ret = c && c.returned;
    const totalAmt = c ? c.directFrontend.refundAmount + c.directBackend.refundAmount : 0;
    const totalCnt = c ? c.directFrontend.refundCount + c.directBackend.refundCount : 0;
    const refMoney = c ? [
      ...(ret ? [
        { label: 'Refunds', sub: NUM(ret.refundCount) + ' pedidos', value: USD(ret.refundAmount), color: 'var(--fenix-orange-600)' },
        { label: 'Chargebacks', sub: NUM(ret.chargebackCount) + ' pedidos', value: USD(ret.chargebackAmount), color: '#7C3AED' },
      ] : []),
      { label: 'Total devolvido', sub: NUM(totalCnt) + ' pedidos · refunds + chargebacks somados',
        value: USD(totalAmt), fg: 'var(--negative)' },
      ...(ret && (ret.partialAmount || 0) > 0 ? [{
        label: 'Parcial devolvido (real, ' + NUM(ret.partialCount || 0) + ' pedidos)',
        value: USD(ret.partialAmount), fg: 'var(--negative)' }] : []),
    ] : [{ label: 'Sem composição no período', value: '—' }];
    // "piores" = taxa mínima comprovada pelo volume (Wilson LB) — muita venda E muito refund.
    const prods = ((d.products && d.products.rows) || []).filter(p => p.mapped)
      .map(p => ({ name: p.name, sales: p.orders, refs: p.refunds.count, amt: p.refunds.amount || 0,
        rate: p.orders + p.refunds.count > 0 ? p.refunds.count / (p.orders + p.refunds.count) * 100 : 0,
        lb: wilsonLB(p.refunds.count, p.orders + p.refunds.count) }))
      .filter(p => p.refs > 0).sort((a, b) => b.lb - a.lb).slice(0, 5);
    const affs = (d.rows || []).filter(a => a.name !== 'Não atribuído' && a.directRefunds)
      .map(a => ({ name: a.name, sales: a.orders || 0, refs: a.directRefunds.refunds || 0,
        amt: a.directRefunds.amountReturned || 0,
        rate: (a.orders || 0) + (a.directRefunds.refunds || 0) > 0
          ? (a.directRefunds.refunds || 0) / ((a.orders || 0) + (a.directRefunds.refunds || 0)) * 100 : 0,
        lb: wilsonLB(a.directRefunds.refunds || 0, (a.orders || 0) + (a.directRefunds.refunds || 0)) }))
      .filter(a => a.refs > 0).sort((a, b) => b.lb - a.lb).slice(0, 5);
    const toLines = (xs) => xs.length ? xs.map(x => ({ label: x.name,
      sub: `${NUM(x.sales)} vendas · ${NUM(x.refs)} refunds · ${USDk(x.amt)} devolvidos`,
      value: PCT(x.rate), fg: refundHealth(x.rate).color })) : [{ label: 'Sem dados no período', value: '—' }];
    return (
      <>
        <KDLines eye="Quanto voltou em $ (canal direto)" lines={refMoney}
          note="O total SOMA refunds + chargebacks (e cancelamentos, quando houver) do canal direto no período." />
        <KDLines eye="Top 5 produtos puxando o refund" lines={toLines(prods)} />
        <KDLines eye="Top 5 afiliados puxando o refund" lines={toLines(affs)}
          note="Ranqueado pela taxa mínima comprovada pelo volume (Wilson) — muita venda E muito refund; 1 venda/100% fica no fim." />
      </>
    );
  }
  if (k.kind === 'rg-refund') {
    // Composição do caixa devolvido — Reembolso Geral e Calendário de Reembolso (spec
    // 2026-08). Dois modos: Reembolso Geral manda d.refundAmount/cgbkAmount JÁ separados
    // (payload de hoje); o Calendário só tem a métrica combinada (régua própria daquela
    // página, reemb+cgbk somados) — manda d.combinedAmount/combinedCount, e aqui vira UMA
    // linha "Reemb+CGBK" em vez de forçar o split (que esconderia o chargeback num
    // "Chargebacks (0 eventos)" enganoso). cancelAmount e partialAmount ainda não vêm do
    // backend em nenhum dos dois (2026-08) — linhas condicionais evitam linha zerada.
    const combinado = d.combinedAmount != null;
    const rgLines = combinado ? [
      { label: 'Reemb+CGBK (' + NUM(d.combinedCount || 0) + ' pedidos)',
        value: USD(d.combinedAmount || 0), color: 'var(--negative)' },
    ] : [
      { label: 'Reembolso integral (' + NUM(d.refundCount || 0) + ' pedidos)',
        value: USD(d.refundAmount || 0), color: 'var(--fenix-orange-600)' },
      { label: 'Chargebacks (' + NUM(d.cgbkCount || 0) + ' eventos)',
        value: USD(d.cgbkAmount || 0), color: '#7C3AED' },
    ];
    rgLines.push(
      ...((d.cancelAmount || 0) > 0 ? [{
        label: 'Cancelamentos (' + NUM(d.cancelCount || 0) + ' pedidos)',
        value: USD(d.cancelAmount), fg: 'var(--negative)' }] : []),
      ...((d.partialAmount || 0) > 0 ? [{
        label: 'Parcial devolvido (real, ' + NUM(d.partialCount || 0) + ' pedidos)',
        value: USD(d.partialAmount), fg: 'var(--negative)' }] : []),
    );
    const rgTotal = combinado
      ? (d.combinedAmount || 0) + (d.cancelAmount || 0) + (d.partialAmount || 0)
      : (d.refundAmount || 0) + (d.cgbkAmount || 0) + (d.cancelAmount || 0) + (d.partialAmount || 0);
    rgLines.push({ label: 'Total caixa devolvido', value: USD(rgTotal), fg: 'var(--negative)' });
    return <KDLines eye="Composição do caixa devolvido" lines={rgLines}
      note="Soma refunds + chargebacks (e cancelamentos/parciais, quando houver) no período. Escopo BuyGoods." />;
  }
  if (k.kind === 'receita-direta') {
    return (
      <>
        <KDLines eye="Front-end × Back-end" lines={c ? [
          { label: 'Front-end', sub: NUM(c.directFrontend.orders) + ' pedidos', value: USD(c.directFrontend.revenue), color: 'var(--fenix-orange-600)' },
          { label: 'Back-end (upsells)', sub: NUM(c.directBackend.orders) + ' pedidos', value: USD(c.directBackend.revenue), color: '#FB923C' },
        ] : [{ label: 'Sem composição no período', value: '—' }]}
          note="Só canal direto — Logicall/Salesbound ficam fora desta KPI." />
      </>
    );
  }
  if (k.kind === 'ativos') {
    const byPlat = {};
    (d.rows || []).forEach(a => { byPlat[a.platform] = (byPlat[a.platform] || 0) + 1; });
    const top = [...(d.rows || [])].sort((a, b) => b.total - a.total).slice(0, 5);
    return (
      <>
        <KDLines eye="Por plataforma" lines={Object.entries(byPlat).map(([p, n]) =>
          ({ label: (PLATFORM[p] || { label: p }).label, value: NUM(n), color: (PLATFORM[p] || {}).color }))} />
        <KDLines eye="Top 5 por receita" lines={top.map(a => ({ label: a.name, value: USDk(a.total) }))} />
      </>
    );
  }
  if (k.kind === 'aov') {
    // AOV por checkout (spec 2026-07-10).
    if (!c) return <KDLines eye="AOV = por checkout" lines={[{ label: 'Sem composição no período', value: '—' }]} />;
    return <KDAovBlocks feRev={c.directFrontend.revenueAov ?? 0} feOrders={c.directFrontend.orders}
                        beRev={c.directBackend.revenueAov ?? 0} beOrders={c.directBackend.orders} />;
  }
  if (k.kind === 'margem') {
    return <KDLines eye="Decomposição" lines={[
      { label: 'Receita do canal', value: USD(d.total || 0) },
      { label: 'CPA pago', value: '− ' + USD(d.cpaPaid || 0), fg: 'var(--negative)' },
      { label: 'Margem operacional', value: PCT(d.wMargin || 0) },
    ]} note="Líquido de CPA e custos operacionais (régua de custos por produto)." />;
  }
  if (k.kind === 'variacao') {
    return <KDLines eye="Comparação" lines={[
      { label: 'Receita do período', value: USD(d.total || 0) },
      { label: (d.periodCmp || {}).eye || 'Variação', sub: (d.periodCmp || {}).sub, value: SIGN(d.wDelta || 0),
        fg: (d.wDelta || 0) >= 0 ? 'var(--positive)' : 'var(--negative)' },
    ]} />;
  }

  // ===== Consolidado bruto genérico (spec 2026-07-24-consolidado-bruto-global) =====
  if (k.kind === 'receita-consolidada') {
    return <KDDeducoes grossTotal={d.grossTotal} refundAmountGross={d.refundAmountGross}
      refundCount={d.refundCount} chargebackAmountGross={d.chargebackAmountGross}
      chargebackCount={d.chargebackCount} validOrders={d.validOrders}
      partialAmount={d.partialAmount} partialCount={d.partialCount} />;
  }

  // Gorduras (Logicall/Salesbound/Tauk) agregadas — fora do consolidado (bloco "Recuperação").
  if (k.kind === 'recuperacao') {
    const rec = d.rec || {};
    return <KDDeducoes grossTotal={rec.gross} refundAmountGross={rec.refundAmount}
      refundCount={rec.refundCount} chargebackAmountGross={rec.chargebackAmount}
      chargebackCount={rec.chargebackCount}
      note="Gorduras (Logicall · Salesbound · Tauk) — brutas, com deduções até o líquido. Fora do consolidado." />;
  }

  // ===== KPIs da página de afiliado (spec 2026-07-09) — leem de k.data.detail =====
  if (k.kind && k.kind.indexOf('aff-') === 0) {
    const detail = d.detail || {};
    const m = detail.metrics || {};
    const rf = detail.refunds || {};
    const fh = detail.financialHealth || {};
    if (k.kind === 'aff-revenue') {
      return (
        <>
          <KDDeducoes grossTotal={m.grossTotal} refundAmountGross={m.refundAmountGross}
            refundCount={m.refundCount} chargebackAmountGross={m.chargebackAmountGross}
            chargebackCount={m.chargebackCount}
            partialAmount={m.partialAmount} partialCount={m.partialCount} />
          <KDLines eye="Front-end × Back-end" lines={[
            { label: 'Front-end', sub: NUM(m.feOrders || 0) + ' pedidos', value: USD(m.feRev || 0), color: 'var(--fenix-orange-600)' },
            { label: 'Back-end (upsells)', sub: NUM(m.beOrders || 0) + ' pedidos', value: USD(m.beRev || 0), color: '#FB923C' },
          ]} note="Receita direta de vendas válidas, separada por etapa de funil (flag de upsell)." />
        </>
      );
    }
    if (k.kind === 'aff-aov') {
      return <KDAovBlocks feRev={m.feRevAov ?? 0} feOrders={m.feOrders || 0}
                          beRev={m.beRevAov ?? 0} beOrders={m.beOrders || 0} />;
    }
    if (k.kind === 'aff-orders') {
      const delta = (m.orders || 0) - (m.ordersPrev || 0);
      return <KDLines eye="Pedidos por etapa" lines={[
        { label: 'Front-end', sub: USDk(m.feRev || 0), value: NUM(m.feOrders || 0), color: 'var(--fenix-orange-600)' },
        { label: 'Back-end (upsells)', sub: USDk(m.beRev || 0), value: NUM(m.beOrders || 0), color: '#FB923C' },
        { label: 'Variação vs. período anterior', value: (delta >= 0 ? '+' : '') + NUM(delta),
          fg: delta >= 0 ? 'var(--positive)' : 'var(--negative)' },
      ]} />;
    }
    if (k.kind === 'aff-refund') {
      if (!rf.available || !rf.direct) {
        return <KDLines eye="Sem captura de refund" lines={[
          { label: 'Plataforma não captura refund/chargeback', value: '—' }]}
          note="PagAmerican e afins não expõem status de estorno — não é 0%, é indisponível." />;
      }
      const prods = (detail.refundsByFunnel || []).filter(r => (r.amount || 0) > 0)
        .sort((a, b) => (b.amount || 0) - (a.amount || 0)).slice(0, 5)
        .map(r => ({ label: r.product, sub: r.refunds != null ? NUM(r.refunds) + ' refunds' : undefined,
          value: USD(r.amount || 0), fg: 'var(--negative)' }));
      return (
        <>
          <KDLines eye="Bruto devolvido" lines={[
            { label: 'Refunds', sub: NUM(rf.direct.refunds || 0) + ' pedidos', value: USD(fh.refundAmount || 0), color: 'var(--fenix-orange-600)' },
            { label: 'Chargebacks', sub: NUM(fh.chargebackCount || 0) + ' pedidos', value: USD(fh.chargebackAmount || 0), color: '#7C3AED' },
            { label: 'Total devolvido', value: USD(fh.amountReturned || 0), fg: 'var(--negative)' },
            ...((fh.partialAmount || 0) > 0 ? [{
              label: 'Parcial devolvido (real, ' + NUM(fh.partialCount || 0) + ' pedidos)',
              value: USD(fh.partialAmount), fg: 'var(--negative)' }] : []),
          ]} />
          <KDLines eye="De qual produto veio (top 5 por $)"
            lines={prods.length ? prods : [{ label: 'Sem reembolsos no período', value: '—' }]} />
        </>
      );
    }
    if (k.kind === 'aff-active') {
      const act = detail.activity || {};
      const fmt = s => s ? new Date(s).toLocaleDateString('pt-BR', { day: '2-digit', month: 'short', year: 'numeric' }) : '—';
      return <KDLines eye="Histórico do afiliado" lines={[
        { label: 'Primeira venda', value: fmt(act.firstSale) },
        { label: 'Última venda', value: fmt(act.lastSale) },
        { label: 'Total de pedidos (histórico)', value: NUM(act.lifetimeOrders || 0) },
      ]} note="Histórico completo (todas as vendas Completed), independente do período selecionado." />;
    }
    if (k.kind === 'aff-stage-refund') {
      const st = d.stage || {};
      const lines = (st.byProduct && st.byProduct.length)
        ? st.byProduct.map(x => ({ label: x.product, sub: NUM(x.refunds || 0) + ' refunds',
            value: USD(x.refundAmount || 0), fg: 'var(--negative)' }))
        : [{ label: 'Sem produtos com estorno nesta etapa', value: '—' }];
      return <KDLines eye="Produtos da etapa" lines={lines}
        note="Produtos que geraram reembolso nesta etapa do funil (top 8 por $)." />;
    }
  }

  // ===== KPIs / drawers da tela de produto (spec 2026-07-09) =====
  if (k.kind && k.kind.indexOf('prod-') === 0) {
    const detail = d.detail || {};
    const m = detail.metrics || {};
    // breakdown [{<nameKey>, refunds, refundAmount}] -> linhas de KDLines
    const bk = (list, nameKey) => (list && list.length)
      ? list.map(x => ({ label: x[nameKey], sub: NUM(x.refunds || 0) + ' refunds', value: USD(x.refundAmount || 0), fg: 'var(--negative)' }))
      : [{ label: 'Sem estorno no período', value: '—' }];

    if (k.kind === 'prod-revenue') {
      return (
        <>
          <KDDeducoes grossTotal={m.grossTotal} refundAmountGross={m.refundAmountGross}
            refundCount={m.refundCount} chargebackAmountGross={m.chargebackAmountGross}
            chargebackCount={m.chargebackCount} validOrders={m.validOrders}
            partialAmount={m.partialAmount} partialCount={m.partialCount} />
          <KDLines eye="Front-end × Back-end" lines={[
            { label: 'Front-end', sub: NUM(m.feOrders || 0) + ' pedidos', value: USD(m.feRev || 0), color: 'var(--fenix-orange-600)' },
            { label: 'Back-end (upsells)', sub: NUM(m.beOrders || 0) + ' pedidos', value: USD(m.beRev || 0), color: '#FB923C' },
          ]} note="Funil completo (inclui upsells de outros produtos atribuídos a este funil)." />
        </>
      );
    }
    if (k.kind === 'prod-orders') {
      const delta = (m.orders || 0) - (m.ordersPrev || 0);
      return <KDLines eye="Pedidos por etapa" lines={[
        { label: 'Front-end', sub: USDk(m.feRev || 0), value: NUM(m.feOrders || 0), color: 'var(--fenix-orange-600)' },
        { label: 'Back-end (upsells)', sub: USDk(m.beRev || 0), value: NUM(m.beOrders || 0), color: '#FB923C' },
        { label: 'Variação vs. período anterior', value: (delta >= 0 ? '+' : '') + NUM(delta), fg: delta >= 0 ? 'var(--positive)' : 'var(--negative)' },
      ]} />;
    }
    if (k.kind === 'prod-aov') {
      return <KDAovBlocks feRev={m.feRevAov ?? 0} feOrders={m.feOrders || 0}
                          beRev={m.beRevAov ?? 0} beOrders={m.beOrders || 0} />;
    }
    if (k.kind === 'prod-operating' || k.kind === 'prod-margin') {
      return <KDLines eye="Decomposição" lines={[
        { label: 'Receita', value: USD(m.revenue || 0) },
        { label: 'Custos operacionais', value: '− ' + USD((m.revenue || 0) - (m.operating || 0)), fg: 'var(--negative)' },
        { label: 'Lucro operacional', value: USD(m.operating || 0) },
        { label: 'Margem', value: PCT(m.margin || 0) },
      ]} note="Líquido de COGS, frete, taxas e provisão de refund (régua de custos por produto)." />;
    }
    if (k.kind === 'prod-refund') {
      const stages = (detail.refundByStage || []).slice().sort((a, b) => b.rate - a.rate).slice(0, 5)
        .map(s => ({ label: s.label, sub: NUM(s.units) + ' vendas', value: PCT(s.rate), fg: refundHealth(s.rate).color }));
      const prodMap = {};
      (detail.refundByStage || []).forEach(s => (s.byProduct || []).forEach(p => {
        const e = prodMap[p.product] || (prodMap[p.product] = { refunds: 0, amt: 0 });
        e.refunds += p.refunds || 0; e.amt += p.refundAmount || 0;
      }));
      const topProds = Object.entries(prodMap).sort((a, b) => b[1].amt - a[1].amt).slice(0, 5)
        .map(([name, v]) => ({ label: name, sub: NUM(v.refunds) + ' refunds', value: USD(v.amt), fg: 'var(--negative)' }));
      return (
        <>
          <KDLines eye="Bruto devolvido" lines={[
            { label: 'Refunds', sub: NUM(m.refunds || 0) + ' pedidos', value: USD(m.refundAmount || 0), color: 'var(--fenix-orange-600)' },
            { label: 'Chargebacks', sub: NUM(m.chargebacks || 0) + ' pedidos', value: USD(m.chargebackAmount || 0), color: '#7C3AED' },
            { label: 'Total devolvido', value: USD(m.amountReturned || 0), fg: 'var(--negative)' },
            ...((m.partialAmount || 0) > 0 ? [{
              label: 'Parcial devolvido (real, ' + NUM(m.partialCount || 0) + ' pedidos)',
              value: USD(m.partialAmount), fg: 'var(--negative)' }] : []),
          ]} note="Chargebacks inclui cancelamentos no valor (contagem separada)." />
          <KDLines eye="Top etapas por taxa" lines={stages.length ? stages : [{ label: 'Sem estorno', value: '—' }]} />
          <KDLines eye="Top produtos por $ de refund" lines={topProds.length ? topProds : [{ label: 'Sem estorno', value: '—' }]} />
        </>
      );
    }
    if (k.kind === 'prod-stage-refund') {
      const st = d.stage || {};
      return (
        <>
          <KDLines eye="Produtos/upsells da etapa" lines={bk(st.byProduct, 'product')} />
          <KDLines eye="Afiliados puxando o refund" lines={bk(st.byAffiliate, 'name')} />
        </>
      );
    }
    if (k.kind === 'prod-cohort-refund') {
      const w = d.window || {};
      return (
        <>
          <KDLines eye="Por upsell/produto" lines={bk(w.byProduct, 'product')} />
          <KDLines eye="Afiliados" lines={bk(w.byAffiliate, 'name')} />
          <KDLines eye="Por etapa (FE/BE)" lines={bk(w.byStage, 'label')} />
        </>
      );
    }
  }

  // ===== Gordura Logicall (produto/nicho) — separada do direto (migração 2026-07-10) =====
  if (k.kind === 'logicall-gordura') {
    const prods = d.products || [];
    return <KDLines eye="Produtos Logicall (líquido)"
      lines={prods.length
        ? prods.map(p => ({ label: p.name, sub: NUM(p.orders || 0) + ' vendas', value: USDk(p.net || 0), color: '#D8453B' }))
        : [{ label: 'Sem gordura Logicall no período', value: '—' }]}
      note="Gordura Logicall líquida (bruto − refunds − chargebacks), SEPARADA do faturamento direto. Atribuição por email/rateio até a de-para logicall_agentes ser populada; fração 'minha parte' a definir." />;
  }

  // ===== Aba Nichos: produtos do nicho ranqueados pela métrica clicada (spec 2026-07-09) =====
  if (k.kind === 'niche-metric') {
    const niche = d.niche || {};
    const metric = d.metric || 'faturamento';
    const CFG = {
      faturamento:    { get: p => p.faturamento || 0, fmt: USDk },
      pedidos:        { get: p => p.pedidos || 0,     fmt: NUM },
      aov:            { get: p => p.aov || 0,         fmt: USD },
      refundRate:     { get: p => p.refundRate || 0,  fmt: PCT, health: true },
      chargebacks:    { get: p => p.chargebacks || 0, fmt: NUM },
      cpaPaid:        { get: p => p.cpaPaid || 0,     fmt: USDk },
      amountReturned: { get: p => p.refunds || 0,     fmt: NUM, devolvido: true },
    };
    const cfg = CFG[metric] || CFG.faturamento;
    const prods = (niche.produtos || []).filter(p => (p.pedidos || 0) > 0 || (p.refunds || 0) > 0);
    const ranked = [...prods].sort((a, b) => cfg.get(b) - cfg.get(a));
    const rows = ranked.length
      ? ranked.map(p => ({
          label: p.name,
          sub: cfg.devolvido ? PCT(p.refundRate || 0) + ' refund · ' + NUM(p.refunds || 0) + ' pedidos'
             : `${NUM(p.pedidos || 0)} pedidos · AOV ${USD(p.aov || 0)}`,
          value: cfg.fmt(cfg.get(p)),
          fg: cfg.health ? refundHealth(p.refundRate || 0).color : undefined,
        }))
      : [{ label: 'Sem vendas no período', value: '—' }];

    if (metric === 'faturamento') {
      const champ = ranked[0];
      const worst = ranked.length ? ranked.reduce((a, b) => (b.refundRate || 0) > (a.refundRate || 0) ? b : a) : null;
      const rh = refundHealth(niche.refundRate || 0);
      return (
        <>
          <KDDeducoes grossTotal={niche.grossTotal} refundAmountGross={niche.refundAmountGross}
            refundCount={niche.refundCount} chargebackAmountGross={niche.chargebackAmountGross}
            chargebackCount={niche.chargebackCount} validOrders={niche.validOrders}
            partialAmount={niche.partialAmount} partialCount={niche.partialCount} />
          <KDLines eye="Insights do nicho" lines={[
            { label: 'Saúde do refund', value: rh.label, fg: rh.color },
            ...(champ ? [{ label: 'Produto campeão', sub: champ.name, value: USDk(champ.faturamento || 0) }] : []),
            ...(worst ? [{ label: 'Maior refund', sub: worst.name, value: PCT(worst.refundRate || 0), fg: refundHealth(worst.refundRate || 0).color }] : []),
          ]} />
          <KDLines eye="Produtos por faturamento" lines={rows} />
        </>
      );
    }
    if (cfg.devolvido) {
      return (
        <>
          <KDLines eye="Total devolvido do nicho" lines={[
            { label: 'Devolvido (refund + chargeback)', value: USDk(niche.amountReturned || 0), fg: 'var(--negative)' },
            ...((niche.partialAmount || 0) > 0 ? [{
              label: 'Parcial devolvido (real, ' + NUM(niche.partialCount || 0) + ' pedidos)',
              value: USDk(niche.partialAmount), fg: 'var(--negative)' }] : []),
          ]} note="Sem valor $ por produto — os produtos abaixo saem ranqueados por nº de refunds." />
          <KDLines eye="Produtos por refunds (qtd)" lines={rows} />
        </>
      );
    }
    if (metric === 'aov') {
      // A conta do nicho acima do ranking (spec 2026-07-10).
      return (
        <>
          <KDAovBlocks feRev={niche.feRevAov ?? 0} feOrders={niche.feOrders || 0}
                       beRev={niche.beRevAov ?? 0} beOrders={niche.beOrders || 0} />
          <KDLines eye="Produtos por AOV" lines={rows} />
        </>
      );
    }
    return <KDLines eye={'Produtos · ' + (k.eye || 'métrica')} lines={rows} />;
  }
  return null;
};

const KpiDrawer = ({ kpi, onClose, refundBy='pedido' }) => {
  const open = !!kpi;
  const k = kpi || {};
  const compLines = _compLines(k.breakdown);
  return (
    <>
      <div onClick={onClose}
        style={{...kd.scrim, opacity:open?1:0, pointerEvents:open?'auto':'none'}}/>
      <aside style={{...kd.panel, transform:open?'translateX(0)':'translateX(104%)'}}>
        {kpi && (
          <>
            <div style={kd.head}>
              <button style={kd.close} onClick={onClose}><Icon name="x" size={18} color="var(--fg-2)"/></button>
              <div style={kd.idRow}>
                <div style={{...kd.iconWrap, background:k.tint, color:k.fg}}>
                  <Icon name={k.icon} size={24} color={k.fg}/>
                </div>
                <div>
                  <div style={kd.eyebrow}>Indicador</div>
                  <div style={kd.title}>{k.eye}</div>
                </div>
              </div>
            </div>

            <div style={kd.body}>
              <RefundByNote refundBy={refundBy}/>
              <div style={kd.totalCard}>
                <span style={kd.totalEye}>{k.eye}</span>
                <div style={{...kd.totalVal, ...(k.mono?{font:'800 28px/1 var(--font-mono)'}:{})}} className="fenix-num">
                  {k.big && k.pos !== undefined &&
                    <Icon name={k.pos?'arrowUp':'arrowDown'} size={26} color="#F6E9E0" style={{marginRight:4, verticalAlign:'-4px'}}/>
                  }
                  {k.val}
                </div>
                {k.sub && <div style={kd.totalSub}>{k.sub}</div>}
              </div>

              {k.kind && <KDContent k={k} />}

              {compLines.length > 0 && (
                <div style={kd.compCard}>
                  <div style={kd.compEye}>Composição do faturamento</div>
                  {compLines.map((l,i)=>(
                    <div key={i} style={kd.compRow}>
                      <span style={{...kd.compDot, background:l.color}}/>
                      <div style={kd.compMain}>
                        <div style={kd.compLabel}>{l.label}</div>
                        <div style={kd.compSub}>
                          {l.orders>0 ? `${l.orders.toLocaleString('pt-BR')} pedidos` : '—'}
                          {l.refA>0 && ` · refund ${USD(l.refA)} (${l.refC})`}
                        </div>
                      </div>
                      <span style={kd.compVal} className="fenix-num">{USD(l.value)}</span>
                    </div>
                  ))}
                  <div style={kd.compTotalRow}>
                    <span style={kd.compTotalK}>Faturamento total (líq. refunds)</span>
                    <span style={kd.compTotalV} className="fenix-num">{USD(k.breakdown.total)}</span>
                  </div>
                  <div style={kd.compNote}>
                    Difere do total do card, que conta Salesbound pela sua parte (×0,45); Logicall entra pelo líquido cheio.
                  </div>
                </div>
              )}

              {k.health && (
                <div style={kd.healthCard}>
                  <span style={kd.metaK}>Status</span>
                  <div style={{...kd.healthChip, color:k.health.color, background:k.health.bg}}>
                    <span style={{...kd.healthDot, background:k.health.color}}/>
                    {k.health.label}
                  </div>
                  <div style={kd.healthNote}>{k.healthNote || 'Meta ≥ 5% · líquido de CPA e custos'}</div>
                </div>
              )}
            </div>
          </>
        )}
      </aside>
    </>
  );
};

const kd = {
  scrim:{ position:'absolute', inset:0, background:'rgba(1,27,54,.45)', backdropFilter:'blur(2px)', transition:'opacity .25s', zIndex:30 },
  panel:{ position:'absolute', top:0, right:0, bottom:0, width:380, maxWidth:'92%', background:'#fff',
    boxShadow:'var(--shadow-lg)', zIndex:31, transition:'transform .3s var(--ease)', display:'flex', flexDirection:'column', overflow:'hidden' },
  head:{ padding:'22px 24px 18px', borderBottom:'1px solid var(--border-1)', position:'relative' },
  close:{ position:'absolute', top:18, right:18, width:34, height:34, borderRadius:'var(--r-sm)', border:0, background:'var(--gray-100)', cursor:'pointer', display:'flex', alignItems:'center', justifyContent:'center' },
  idRow:{ display:'flex', alignItems:'center', gap:13 },
  iconWrap:{ width:48, height:48, borderRadius:'var(--r-md)', display:'flex', alignItems:'center', justifyContent:'center', flex:'none' },
  eyebrow:{ font:'var(--text-label)', letterSpacing:'.06em', textTransform:'uppercase', color:'var(--fg-3)', marginBottom:4 },
  title:{ font:'800 17px/1.15 var(--font-display)', color:'var(--fg-1)', letterSpacing:'-.01em' },
  body:{ padding:'20px 24px', overflowY:'auto', flex:1 },
  totalCard:{ background:'var(--fenix-navy)', borderRadius:'var(--r-lg)', padding:'20px 22px', marginBottom:14 },
  totalEye:{ font:'var(--text-label)', letterSpacing:'.06em', textTransform:'uppercase', color:'#FFA866' },
  totalVal:{ font:'800 38px/1 var(--font-num)', color:'#F6E9E0', letterSpacing:'-.015em', margin:'10px 0 10px', fontVariantNumeric:'tabular-nums' },
  totalSub:{ font:'500 12px/1.3 var(--font-sans)', color:'rgba(246,233,224,.6)', marginTop:4 },
  compCard:{ background:'var(--bg-sunken)', borderRadius:'var(--r-md)', padding:'16px 18px', marginBottom:14, display:'flex', flexDirection:'column', gap:2 },
  compEye:{ font:'var(--text-caption)', color:'var(--fg-3)', textTransform:'uppercase', letterSpacing:'.05em', marginBottom:10 },
  compRow:{ display:'flex', alignItems:'flex-start', gap:10, padding:'9px 0', borderBottom:'1px solid var(--border-1)' },
  compDot:{ width:9, height:9, borderRadius:'50%', flex:'none', marginTop:4 },
  compMain:{ flex:1, minWidth:0 },
  compLabel:{ font:'600 13px/1.2 var(--font-sans)', color:'var(--fg-1)' },
  compSub:{ font:'500 11px/1.3 var(--font-sans)', color:'var(--fg-3)', marginTop:3 },
  compVal:{ font:'700 13px/1 var(--font-mono)', color:'var(--fg-1)', whiteSpace:'nowrap', marginTop:2 },
  compTotalRow:{ display:'flex', alignItems:'baseline', justifyContent:'space-between', gap:10, paddingTop:11, marginTop:4 },
  compTotalK:{ font:'700 12px/1.2 var(--font-sans)', letterSpacing:'.02em', color:'var(--fg-2)' },
  compTotalV:{ font:'800 16px/1 var(--font-mono)', color:'var(--fenix-orange-600)' },
  compNote:{ font:'var(--text-caption)', color:'var(--fg-3)', marginTop:8, lineHeight:1.4 },

  healthCard:{ background:'var(--bg-sunken)', borderRadius:'var(--r-md)', padding:'16px 18px', display:'flex', flexDirection:'column', gap:10 },
  metaK:{ font:'var(--text-caption)', color:'var(--fg-3)', textTransform:'uppercase', letterSpacing:'.05em' },
  healthChip:{ display:'inline-flex', alignSelf:'flex-start', alignItems:'center', gap:7, font:'700 13px/1 var(--font-sans)', padding:'7px 12px', borderRadius:'var(--r-pill)' },
  healthDot:{ width:8, height:8, borderRadius:'50%', flex:'none' },
  healthNote:{ font:'var(--text-caption)', color:'var(--fg-3)' },
};

window.KpiDrawer = KpiDrawer;
