// Componentes de gráfico da página de afiliado (spec 2026-06-30 / 2026-07-09):
//  - AffiliateTrend: série temporal de receita (visual do RevenueTrend); tooltip qtd + $
//  - TopProductsFunnel: top produtos + destrinchamento de funil no hover
// React 18 via Babel; helpers globais: useWidth, USD, USDk, NUM. Tokens var(--...).

// label de bucket: ISO -> MM-DD; mock-i -> D(i+1)
const _bucketLabel = (b, i) =>
  (typeof b === 'string' && b.startsWith('mock')) ? 'D' + (i + 1) : String(b).slice(5, 10);

const COL_SALES  = '#FD7119';
const COL_REFUND = '#D8453B';
const COL_CGBK   = '#8A5BD6';

// Série temporal do afiliado (spec 2026-07-09): mesmo visual do RevenueTrend da página principal
// (área/linha de receita $). Tooltip mostra Data + Pedidos/Refund/Chargeback em quantidade E $.
// trend: [{bucket, sales, revenue, refunds, refundAmount, chargebacks, chargebackAmount}]
const AffiliateTrend = ({ trend }) => {
  const [ref, w] = useWidth();
  const [hover, setHover] = React.useState(null);
  const pts = trend || [];
  if (pts.length === 0) return <div style={src.empty}>— sem dados no período</div>;

  const rev = pts.map(t => t.revenue || 0);
  const H = 244, padL = 64, padR = 22, padT = 18, padB = 34;
  const cw = Math.max(w, 320);
  const innerW = cw - padL - padR, innerH = H - padT - padB;
  const revMax = Math.max(...rev, 1) * 1.15;
  const x = i => padL + (pts.length <= 1 ? 0 : innerW * i / (pts.length - 1));
  const y = v => padT + innerH * (1 - v / revMax);
  const baseY = padT + innerH;
  const line = pts.map((t, i) => (i ? 'L' : 'M') + x(i).toFixed(1) + ',' + y(rev[i]).toFixed(1)).join(' ');
  const area = `M ${padL} ${baseY} ` +
    rev.map((v, i) => 'L' + x(i).toFixed(1) + ',' + y(v).toFixed(1)).join(' ') +
    ` L ${x(rev.length - 1).toFixed(1)} ${baseY} Z`;
  const ticks = 4;
  const fr = Array.from({ length: ticks + 1 }, (_, i) => i / ticks);
  const lblStep = Math.max(1, Math.ceil(pts.length / 8));

  return (
    <div style={{ position: 'relative' }}>
      <div ref={ref} style={{ width: '100%' }}>
        <svg width={cw} height={H} style={{ display: 'block' }} onMouseLeave={() => setHover(null)}>
          <defs>
            <linearGradient id="affTrendFill" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={COL_SALES} stopOpacity="0.22" />
              <stop offset="100%" stopColor={COL_SALES} stopOpacity="0" />
            </linearGradient>
          </defs>
          {fr.map((f, i) => {
            const yy = padT + innerH * (1 - f);
            return (
              <g key={i}>
                <line x1={padL} y1={yy} x2={cw - padR} y2={yy} stroke="#EDEFF3" strokeWidth="1" strokeDasharray={i === 0 ? '0' : '3 4'} />
                <text x={padL - 10} y={yy + 4} textAnchor="end" fontFamily="var(--font-num)"
                  fontSize="10.5" fill="#9AA3B5">{USDk(f * revMax)}</text>
              </g>
            );
          })}
          <path d={area} fill="url(#affTrendFill)" />
          <path d={line} fill="none" stroke={COL_SALES} strokeWidth="2.6" strokeLinejoin="round" strokeLinecap="round" />
          {hover != null && (
            <line x1={x(hover)} y1={padT} x2={x(hover)} y2={baseY} stroke={COL_SALES} strokeWidth="1" strokeDasharray="3 3" opacity="0.5" />
          )}
          {pts.map((t, i) => (
            <g key={i} onMouseEnter={() => setHover(i)} style={{ cursor: 'pointer' }}>
              <rect x={x(i) - innerW / pts.length / 2} y={padT} width={Math.max(6, innerW / pts.length)}
                height={innerH} fill="transparent" />
              <circle cx={x(i)} cy={y(rev[i])} r={hover === i ? 5 : 3} fill="#fff" stroke={COL_SALES} strokeWidth="2.5" />
            </g>
          ))}
          {pts.map((t, i) => (i % lblStep === 0 &&
            <text key={i} x={x(i)} y={H - 10} textAnchor="middle" fontFamily="var(--font-num)"
              fontSize="10.5" fill="#9AA3B5">{_bucketLabel(t.bucket, i)}</text>
          ))}
        </svg>
      </div>
      {hover != null && pts[hover] && (() => {
        const t = pts[hover];
        const left = Math.min(Math.max(x(hover) - 105, 8), Math.max(cw - 218, 8));
        const row = (color, label, qty, amt) => (
          <div style={src.tipRow}><span style={{ ...src.dot, background: color }} />{label}
            <b className="fenix-num" style={src.tipVal}>{NUM(qty)} · {USD(amt)}</b></div>
        );
        // Taxa de refund do dia (mesma fórmula do RefundRateOverTime: refunds/(vendas+refunds)).
        const denom = (t.sales || 0) + (t.refunds || 0);
        const refundRate = denom ? (t.refunds || 0) / denom * 100 : 0;
        return (
          <div style={{ ...src.tip, width: 212, left, top: y(rev[hover]) + 14 }}>
            <div style={src.tipTitle}>{_bucketLabel(t.bucket, hover)}</div>
            {row(COL_SALES, 'Pedidos', t.sales || 0, t.revenue || 0)}
            {row(COL_REFUND, 'Refund', t.refunds || 0, t.refundAmount || 0)}
            {row(COL_CGBK, 'Chargeback', t.chargebacks || 0, t.chargebackAmount || 0)}
            <div style={{ ...src.tipRow, marginTop: 4, paddingTop: 6, borderTop: '1px solid rgba(255,255,255,.12)' }}>
              Taxa de refund<b className="fenix-num" style={src.tipVal}>{PCT(refundRate)}</b>
            </div>
          </div>
        );
      })()}
    </div>
  );
};

// Cores da cascata do funil: front laranja, upsells em laranja claro, downsell em cinza-azulado.
const _stepColor = (role, idx) => {
  if (role === 'downsell') return '#9AA3B5';
  const ramp = ['#FD7119', '#FB9A52', '#FFC08F', '#FFE0C4'];
  return ramp[Math.min(idx, ramp.length - 1)];
};

// products: [{name, revenue, units, funnel:[{role, step, units, pct}]}]
// Donut de receita à esquerda; o funil aparece à direita SÓ ao clicar num produto (spec 2026-07-16).
const TopProductsFunnel = ({ products }) => {
  const items = products || [];
  const [selected, setSelected] = React.useState(null);
  if (items.length === 0) return <div style={src.empty}>— sem vendas no período</div>;
  const total = items.reduce((s, p) => s + (p.revenue || 0), 0);
  const segments = items.map(p => ({ label: p.name, value: p.revenue || 0, meta: p }));

  const renderDetail = () => {
    if (!selected) return null;
    const p = selected;
    return (
      <div style={tpf.detail}>
        <div style={tpf.eyebrow}>Estrutura de funil</div>
        <div style={tpf.detailName}>{p.name}</div>
        <div style={tpf.detailSub}>
          <span className="fenix-num">{(p.units || 0).toLocaleString('pt-BR')}</span> vendas · <span className="fenix-num">{USD(p.revenue || 0)}</span>
        </div>
        <div style={tpf.steps}>
          {(p.funnel || []).map((s, j) => (
            <div key={s.step + j}>
              <div style={tpf.stepTop}>
                <span style={tpf.stepLabel}>{s.step}</span>
                <span style={tpf.stepMeta}>
                  <span className="fenix-num" style={tpf.stepUnits}>{(s.units || 0).toLocaleString('pt-BR')} un.</span>
                  <span className="fenix-num" style={tpf.stepPct}>{Math.round(s.pct || 0)}%</span>
                </span>
              </div>
              <div style={tpf.stepTrack}>
                <div style={{ width: Math.min(100, s.pct || 0) + '%', height: '100%', borderRadius: 5,
                  background: _stepColor(s.role, j), transition: 'width .25s var(--ease)' }} />
              </div>
            </div>
          ))}
        </div>
      </div>
    );
  };

  return (
    <HoverDonut
      segments={segments}
      centerValue={USDk(total)}
      centerLabel="receita"
      legendValue={a => USD(a.value)}
      onSlice={a => setSelected(a.meta || null)}
      aside={selected ? renderDetail : undefined}
    />
  );
};

const src = {
  empty: { font: 'var(--text-body-sm)', color: 'var(--fg-3)', padding: '32px 0', textAlign: 'center' },
  dot: { width: 9, height: 9, borderRadius: '50%', flex: 'none', display: 'inline-block' },
  tip: { position: 'absolute', width: 168, background: 'var(--fenix-navy)', borderRadius: 'var(--r-md)',
    padding: '10px 12px', boxShadow: 'var(--shadow-lg)', zIndex: 20, pointerEvents: 'none' },
  tipTitle: { font: '700 12px/1 var(--font-mono)', color: '#FFA866', marginBottom: 7 },
  tipRow: { display: 'flex', alignItems: 'center', gap: 7, padding: '3px 0', font: '500 11.5px/1 var(--font-sans)', color: '#C3D0E2' },
  tipVal: { marginLeft: 'auto', color: '#F6E9E0', font: '600 11.5px/1 var(--font-mono)' },
};

const tpf = {
  detail: { background: 'var(--bg-sunken)', borderRadius: 'var(--r-md)', padding: '14px 16px', display: 'flex', flexDirection: 'column' },
  eyebrow: { font: 'var(--text-label)', letterSpacing: '.05em', textTransform: 'uppercase', color: 'var(--fg-3)' },
  detailName: { font: '800 16px/1.15 var(--font-sans)', color: 'var(--fg-1)', marginTop: 6 },
  detailSub: { font: '600 11.5px/1.3 var(--font-mono)', color: 'var(--fg-3)', margin: '4px 0 12px' },
  steps: { display: 'flex', flexDirection: 'column', gap: 10 },
  stepTop: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 5, gap: 10 },
  stepLabel: { font: '600 12px/1.2 var(--font-sans)', color: 'var(--fg-1)' },
  stepMeta: { display: 'flex', alignItems: 'center', gap: 8, whiteSpace: 'nowrap' },
  stepUnits: { font: '700 11px/1 var(--font-mono)', color: 'var(--fg-1)' },
  stepPct: { font: '600 10.5px/1 var(--font-mono)', color: 'var(--fg-3)', minWidth: 32, textAlign: 'right' },
  stepTrack: { height: 7, background: '#fff', borderRadius: 5, overflow: 'hidden', border: '1px solid var(--border-2)' },
};

// Refund por etapa (por afiliado) — donut; fatia = nº de reembolsos da etapa, cor por saúde da
// taxa. Clique abre o KpiDrawer com os produtos daquela etapa (spec 2026-07-16).
const AffiliateRefundByStage = ({ stages, onKpiSelect }) => {
  const items = (stages || []).filter(s => (s.refunds || 0) > 0);
  if (!items.length) return <div style={src.empty}>— sem reembolsos por etapa no período</div>;
  const total = items.reduce((a, s) => a + (s.refunds || 0), 0);
  const segments = items.map(s => ({ label: s.label, value: s.refunds, color: refundHealth(s.rate).color, meta: s }));
  return (
    <HoverDonut
      segments={segments}
      centerValue={NUM(total)}
      centerLabel="reembolsos"
      legendValue={a => PCT(a.meta ? a.meta.rate : 0)}
      caption={a => `${a.label} · ${NUM(a.value)} reembolsos · taxa ${PCT(a.meta ? a.meta.rate : 0)}`}
      onSlice={a => a.meta && onKpiSelect && onKpiSelect({
        eye: 'Refund · ' + a.meta.label, val: NUM(a.meta.refunds), sub: 'taxa ' + PCT(a.meta.rate),
        icon: 'refresh', tint: 'var(--negative-bg)', fg: 'var(--negative)',
        kind: 'aff-stage-refund', data: { stage: a.meta },
      })}
      hint="clique numa fatia para ver os produtos"
    />
  );
};

// Vendas front-end por pote (bottles) — por afiliado. Igual ao donut do AOV Editor (spec 2026-07-16).
const AffiliatePotes = ({ potes }) => {
  const items = (potes || []).filter(p => (p.feOrders || 0) > 0);
  if (!items.length) return <div style={src.empty}>— sem vendas front-end no período</div>;
  const total = items.reduce((a, p) => a + (p.feOrders || 0), 0);
  return (
    <HoverDonut
      segments={items.map(p => ({ label: p.label, value: p.feOrders }))}
      centerValue={NUM(total)}
      centerLabel="vendas FE"
      legendValue={a => `${NUM(a.value)} · ${PCT(a.pctIn)}`}
      caption={a => `${a.label} · ${NUM(a.value)} vendas (${PCT(a.pctIn)})`}
      hint="% das vendas de front-end por pote"
    />
  );
};

Object.assign(window, { AffiliateTrend, TopProductsFunnel, AffiliateRefundByStage, AffiliatePotes });
