// Reembolso → Calendário de Reembolso (spec 2026-07-30).
// Compara duas janelas — dia único ou período canônico — por produto, funil de
// marketing (B3/B4), etapa do funil e motivo. Escopo buygoods.
//
// PREFIXO `rc` em TODOS os identificadores de topo (escopo Babel compartilhado).
// Os gráficos vivem em RefundCharts.jsx (prefixo `rcc`), que carrega ANTES deste.
//
// SEM mock: comparação inventada é dado falso (mesmo critério do Teste A/B e do
// Leads). Offline mostra card honesto; com dado velho na tela, notice âmbar.

const RC_BLANK_A = { period: '7d', customRange: null };
const RC_BLANK_B = { period: 'ontem', customRange: null };

// Barra DIVERGENTE ancorada no zero: Δ é dado de polaridade (piorou/melhorou) e pede
// duas matizes com neutro no meio, não um número solto. Vermelho à direita = refund
// subiu; verde à esquerda = caiu.
const RcDeltaBar = ({ delta, max }) => {
  const w = Math.min(100, (Math.abs(delta) / (max || 1)) * 100);
  const sobe = delta > 0;
  return (
    <div style={rcx.dbWrap} title={`${sobe ? '+' : ''}${delta.toFixed(2)} pp`}>
      <div style={rcx.dbLado}>
        {!sobe && delta !== 0 && (
          <div style={{ ...rcx.dbFill, width: w + '%', marginLeft: 'auto',
            background: 'var(--positive)', borderRadius: '3px 0 0 3px' }} />
        )}
      </div>
      <div style={rcx.dbZero} />
      <div style={rcx.dbLado}>
        {sobe && (
          <div style={{ ...rcx.dbFill, width: w + '%',
            background: 'var(--negative)', borderRadius: '0 3px 3px 0' }} />
        )}
      </div>
    </div>
  );
};

const rcDeltaTexto = (d) =>
  (d > 0 ? '+' : d < 0 ? '−' : '') + Math.abs(d).toFixed(2).replace('.', ',');

const rcQuebra = (item, detalhe) => (detalhe === 'etapa' ? item.porEtapa : item.porFunil) || [];

// Uma linha da tabela (produto ou sub-linha de funil/etapa).
const RcLinha = ({ r, max, sub, aberto, onToggle }) => (
  <tr style={{ ...(sub ? rcx.trSub : {}), ...(r.conf.ruido ? rcx.trRuido : {}) }}
    onClick={onToggle}
    onMouseEnter={e => { e.currentTarget.style.background = 'var(--fenix-blue-100)'; }}
    onMouseLeave={e => { e.currentTarget.style.background = sub ? 'var(--gray-50)' : 'transparent'; }}>
    <td style={{ ...rcx.tdNome, ...(sub ? rcx.tdNomeSub : { cursor: 'pointer' }) }}>
      {!sub && (
        <Icon name="chevronDown" size={14} color="var(--fg-3)"
          style={{ transform: aberto ? 'none' : 'rotate(-90deg)', transition: 'transform .18s',
            marginRight: 7, verticalAlign: '-2px' }} />
      )}
      {r.label}
    </td>
    <td style={rcx.tdNum} className="fenix-num">{PCT(r.taxaA)}</td>
    <td style={rcx.tdDelta}>
      <div style={rcx.deltaCel}>
        <RcDeltaBar delta={r.deltaPp} max={max} />
        <span style={{ ...rcx.deltaNum,
          color: r.deltaPp > 0 ? 'var(--negative)'
               : r.deltaPp < 0 ? 'var(--positive)' : 'var(--fg-4)' }}
          className="fenix-num">{rcDeltaTexto(r.deltaPp)}</span>
      </div>
    </td>
    <td style={{ ...rcx.tdNum, fontWeight: 700, color: refundHealth(r.taxaB).color }}
      className="fenix-num">{PCT(r.taxaB)}</td>
    <td style={rcx.tdNum} className="fenix-num">
      {NUM(r.refundsA)}{' '}
      <span style={{ color: r.refundsB > r.refundsA ? 'var(--negative)'
           : r.refundsB < r.refundsA ? 'var(--positive)' : 'var(--fg-4)' }}>
        → {NUM(r.refundsB)}</span>
    </td>
    <td style={{ ...rcx.tdNum, color: 'var(--fg-3)' }} className="fenix-num">
      {NUM(r.vendasA)} → {NUM(r.vendasB)}</td>
    {/* Taxa de cancelamento PARALELA (rodada 2): cancel ÷ (vendas+cancel) — não entra
        na métrica Reemb+CGBK da página, só é exibida ao lado dela. */}
    <td style={{ ...rcx.tdNum, color: 'var(--fg-3)' }} className="fenix-num"
      title="Taxa de cancelamento: cancelamentos ÷ (vendas + cancelamentos) — métrica paralela; não entra no Reemb+CGBK">
      {PCT(r.taxaCancelA)} → {PCT(r.taxaCancelB)}</td>
    <td style={rcx.tdConf}>
      {r.conf.ruido
        ? <span style={rcx.chipRuido}
            title="Base curta demais ou diferença dentro do ruído a 95% — não dá para concluir.">ruído</span>
        : <span style={rcx.chipOk} title={r.conf.pValue != null
            ? `Significativo a 95% (p=${r.conf.pValue.toFixed(4)})` : 'Significativo a 95%'}>✓</span>}
    </td>
  </tr>
);

const RefundCalendarView = ({ onKpiSelect } = {}) => {
  const [regua, setRegua] = React.useState('pedido');
  const [ladoA, setLadoA] = React.useState(RC_BLANK_A);
  const [ladoB, setLadoB] = React.useState(RC_BLANK_B);
  const [products, setProducts] = React.useState([]);
  const [funnelTag, setFunnelTag] = React.useState('todos');
  // Um estado `detalhe` POR bloco — um estado compartilhado fazia o toggle de um
  // bloco trocar os outros (bug reportado 30/jul).
  const [detTab, setDetTab] = React.useState('funil');
  const [detFeUp, setDetFeUp] = React.useState('funil');
  const [detMot, setDetMot] = React.useState('funil');
  const [abertos, setAbertos] = React.useState(() => new Set());
  const [data, setData] = React.useState(null);
  const [err, setErr] = React.useState(false);
  const fullLoading = useFullLoading();
  const withLoad = (fn) => (...a) => { fullLoading.mark(); fn(...a); };
  const retry = useAutoRetry(err);   // falhou → tenta de novo a cada 15s, sozinho

  React.useEffect(() => {
    const began = fullLoading.begin();
    let cancelled = false;
    fetchRefundCalendarAPI({ regua, a: ladoA, b: ladoB, products, funnelTag })
      .then(d => { if (!cancelled) { setData(d); setErr(false); } })
      .catch(() => { if (!cancelled) setErr(true); })
      .finally(() => { if (!cancelled) fullLoading.end(began); });
    return () => { cancelled = true; };
  }, [regua, ladoA, ladoB, products, funnelTag, retry]);

  const toggle = (k) => setAbertos(prev => {
    const n = new Set(prev); if (n.has(k)) n.delete(k); else n.add(k); return n;
  });
  // Só a tabela do bloco 2 usa `abertos`; blocos 3/4 viraram donuts com clique.
  const todosAbertos = () => setAbertos(prev => {
    const chaves = data ? data.produtos.map(p => p.key) : [];
    return prev.size ? new Set() : new Set(chaves);
  });

  // 1º load falhou: LoadingScreen offline + retry automático (useAutoRetry acima) —
  // nunca um card estático sem retry (requisito ui-fenix, spec 2026-07-30-reconexao).
  if (err && !data) return (
    <>
      <LoadingScreen conn="offline" />
      <div style={rcx.reconNota}>
        Esta tela é uma comparação e não tem versão de demonstração — um Δ inventado
        é pior que tela vazia. Reconectando sozinho a cada 15s.
      </div>
    </>
  );
  if (!data) return <LoadingScreen conn="connecting" />;

  const L = data.lados;
  const maxDelta = data.produtos.reduce((m, p) => Math.max(m, Math.abs(p.deltaPp)), 1);
  const kp = data.kpis;
  // ATENÇÃO: os dois setters TÊM que ser funcionais. Ao escolher um período fixo, o
  // PeriodSelector chama setPeriod(k) e LOGO EM SEGUIDA setCustomRange(null), no
  // mesmo tick. Com `{...val}` (o objeto capturado no render), a segunda chamada
  // usaria o `val` velho e desfaria o período que a primeira acabou de setar.
  const lado = (k, set, val) => (
    <div style={rcx.ladoCard}>
      <span style={{ ...rcx.ladoTag, color: k === 'a' ? RCC_A : RCC_B }}>{L[k].label}</span>
      <PeriodSelector
        period={val.period}
        setPeriod={p => withLoad(set)(s => ({ ...s, period: p }))}
        customRange={val.customRange}
        setCustomRange={r => withLoad(set)(s => ({ ...s, customRange: r,
          period: r ? 'custom' : s.period }))} />
    </div>
  );

  return (
    <div style={{ position: 'relative' }}>
      <div style={rcx.header}>
        <div>
          <div style={rcx.eye}>Reembolso</div>
          <div style={rcx.title}>Calendário de Reembolso</div>
        </div>
        <div style={rcx.filtros}>
          <Dropdown icon="refresh" label="Régua" value={regua} onChange={withLoad(setRegua)}
            options={REFUND_BY_OPTIONS} />
          <MultiDropdown icon="cart" label="Produto" values={products}
            onChange={withLoad(setProducts)}
            options={(data.familias || []).map(f => ({ key: f, label: f }))} />
          <Dropdown icon="trending" label="Funil" value={funnelTag} onChange={withLoad(setFunnelTag)}
            options={[{ key: 'todos', label: 'Todos' },
                      ...(data.funis || []).map(t => ({ key: t, label: t.toUpperCase() }))]} />
          <button style={rcx.btn} onClick={todosAbertos}>
            {abertos.size ? 'Recolher tudo' : 'Expandir tudo'}
          </button>
        </div>
      </div>

      <div style={rcx.ladosRow}>
        {lado('a', setLadoA, ladoA)}
        <span style={rcx.seta}>→</span>
        {lado('b', setLadoB, ladoB)}
        <button style={rcx.espelhar} onClick={() => withLoad(setLadoB)({ ...ladoA })}
          title="Copia os filtros da primeira janela para a segunda">Espelhar →</button>
      </div>

      {err && (
        <div style={rcx.notice}><Icon name="alert" size={14} color="currentColor" />
          Falha ao atualizar — mostrando a última comparação carregada.</div>
      )}
      {(data.alertas || []).map((a, i) => (
        <div key={i} style={rcx.alerta}>
          <Icon name="alert" size={14} color="currentColor" />{a.texto}
        </div>
      ))}

      <div style={rcx.kpiRow}>
        <DotKpi hoverable eye={L.a.label} color={RCC_A} value={PCT(kp.taxaA)}
          health={refundHealth(kp.taxaA)} />
        <DotKpi hoverable eye={L.b.label} color={RCC_B} value={PCT(kp.taxaB)}
          health={refundHealth(kp.taxaB)} />
        <DotKpi hoverable eye="Δ" color={kp.deltaPp > 0 ? 'var(--negative)' : 'var(--positive)'}
          value={rcDeltaTexto(kp.deltaPp) + ' pp'}
          valColor={kp.deltaPp > 0 ? 'var(--negative)' : kp.deltaPp < 0 ? 'var(--positive)' : undefined}
          sub={kp.deltaPp > 0 ? 'piorou' : kp.deltaPp < 0 ? 'melhorou' : 'estável'} />
        <DotKpi hoverable eye={`Reemb+CGBK ${L.a.label} → ${L.b.label}`} color="var(--fg-3)"
          value={`${NUM(kp.refundsA)} → ${NUM(kp.refundsB)}`} sub="refunds + chargebacks · cancelamentos fora" />
        <DotKpi hoverable eye={`Valor ${L.a.label} → ${L.b.label}`} color="var(--fg-3)"
          value={`${USDk(kp.amountA)} → ${USDk(kp.amountB)}`} sub="devolvido no período (reemb+cgbk)"
          onClick={onKpiSelect ? () => onKpiSelect({ eye: `Valor devolvido ${L.a.label} → ${L.b.label}`,
            val: `${USDk(kp.amountA)} → ${USDk(kp.amountB)}`, sub: 'devolvido no período (reemb+cgbk) · janelas somadas',
            icon: 'refresh', tint: 'var(--negative-bg)', fg: 'var(--negative)', kind: 'rg-refund',
            data: { ...kp, combinedAmount: (kp.amountA || 0) + (kp.amountB || 0),
              combinedCount: (kp.refundsA || 0) + (kp.refundsB || 0) } }) : undefined} />
        {/* Taxa de cancelamento paralela (rodada 2) — não entra no Reemb+CGBK acima */}
        <DotKpi hoverable eye={`Cancelamento ${L.a.label} → ${L.b.label}`} color="var(--fg-3)"
          value={`${PCT(kp.taxaCancelA)} → ${PCT(kp.taxaCancelB)}`}
          sub={`Δ ${rcDeltaTexto(kp.deltaCancelPp)} pp · cancel ÷ (vendas+cancel)`}
          subColor={kp.deltaCancelPp > 0 ? 'var(--negative)'
                  : kp.deltaCancelPp < 0 ? 'var(--positive)' : undefined} />
      </div>

      <RccSerie serie={data.serie} lados={L} />

      <div style={rcx.tabelaCard}>
        <RccHead eye="Bloco 2" titulo="Comparativo por produto"
          detalhe={detTab} setDetalhe={setDetTab} />
        <table style={rcx.tabela}>
          <thead><tr>
            <th style={{ ...rcx.th, textAlign: 'left' }}>Produto</th>
            <th style={rcx.th}>{L.a.label}</th>
            <th style={{ ...rcx.th, textAlign: 'center' }}>Δ</th>
            <th style={rcx.th}>{L.b.label}</th>
            <th style={rcx.th}>Reemb+CGBK</th>
            <th style={rcx.th}>Vendas</th>
            <th style={rcx.th}>Cancel %</th>
            <th style={{ ...rcx.th, textAlign: 'center' }}>Conf.</th>
          </tr></thead>
          <tbody>
            {data.produtos.map(p => {
              const on = abertos.has(p.key);
              const linhas = [
                <RcLinha key={p.key} r={p} max={maxDelta} aberto={on}
                  onToggle={() => toggle(p.key)} />,
              ];
              if (on) {
                rcQuebra(p, detTab).forEach(q => linhas.push(
                  <RcLinha key={p.key + '·' + q.key} r={q} max={maxDelta} sub />
                ));
                if (rcQuebra(p, detTab).length === 0) linhas.push(
                  <tr key={p.key + '·vazio'} style={rcx.trSub}>
                    <td colSpan={8} style={rcx.subVazio}>Sem quebra por {detTab} nesta janela.</td>
                  </tr>
                );
              }
              return linhas;
            })}
            {data.produtos.length === 0 && (
              <tr><td colSpan={8} style={rcx.vazio}>Sem produto nas janelas escolhidas.</td></tr>
            )}
          </tbody>
        </table>
        <div style={rcx.nota}>
          Ordenado por <b>quanto mudou</b>, não por quem vende mais. <b>ruído</b> = menos
          de 10 na base de algum lado ou diferença dentro do ruído a 95% (teste z de duas
          proporções). Taxa = (refunds + chargebacks) ÷ (vendas + refunds + chargebacks) —
          cancelamentos ficam fora (decisão 30/jul). <b>Cancel %</b> é a métrica paralela:
          cancelamentos ÷ (vendas + cancelamentos), fora do Reemb+CGBK. Escopo buygoods.
        </div>
      </div>

      <RccFeUp produtos={data.produtos} lados={L} detalhe={detFeUp} setDetalhe={setDetFeUp} />
      <RccMotivos motivos={data.motivos} lados={L} kpis={kp} parceiros={data.parceiros}
        detalhe={detMot} setDetalhe={setDetMot} />

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

const rcx = {
  header: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16,
    marginBottom: 14, flexWrap: 'wrap' },
  eye: { font: 'var(--text-label)', letterSpacing: '.05em', textTransform: 'uppercase', color: 'var(--fg-3)' },
  title: { font: '800 22px/1.1 var(--font-sans)', color: 'var(--fg-1)', letterSpacing: '-.01em', marginTop: 4 },
  filtros: { display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' },
  btn: { border: '1px solid var(--border-2)', background: '#fff', color: 'var(--fg-2)',
    borderRadius: 'var(--r-md)', padding: '9px 13px', font: '600 12.5px/1 var(--font-sans)',
    cursor: 'pointer', whiteSpace: 'nowrap' },

  ladosRow: { display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14, flexWrap: 'wrap' },
  ladoCard: { display: 'flex', alignItems: 'center', gap: 10, background: '#fff',
    border: '1px solid var(--border-1)', borderRadius: 'var(--r-lg)', boxShadow: 'var(--shadow-sm)',
    padding: '10px 14px' },
  ladoTag: { font: '800 12px/1 var(--font-num)', letterSpacing: '.04em', whiteSpace: 'nowrap' },
  seta: { font: '700 16px/1 var(--font-sans)', color: 'var(--fg-4)' },
  espelhar: { border: '1px solid var(--border-2)', background: '#fff', color: 'var(--fg-2)',
    borderRadius: 'var(--r-md)', padding: '9px 13px', font: '600 12.5px/1 var(--font-sans)',
    cursor: 'pointer', whiteSpace: 'nowrap' },

  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 },
  alerta: { display: 'flex', alignItems: 'flex-start', gap: 7, font: '600 12px/1.5 var(--font-sans)',
    color: 'var(--warning)', background: 'var(--warning-bg)', border: '1px solid var(--warning)',
    padding: '11px 16px', borderRadius: 'var(--r-md)', marginBottom: 14 },

  // auto-fit: 6 cards viram 5+1 (ou 6) conforme a largura — nenhum valor clipa.
  kpiRow: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(210px, 1fr))',
    gap: 14, marginBottom: 16 },

  tabelaCard: { background: '#fff', border: '1px solid var(--border-1)', borderRadius: 'var(--r-lg)',
    boxShadow: 'var(--shadow-sm)', padding: '16px 20px 4px', marginBottom: 16 },
  tabela: { 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' },
  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' },
  tdNomeSub: { paddingLeft: 42, fontWeight: 500, color: 'var(--fg-2)' },
  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' },
  tdDelta: { padding: '10px 12px', borderBottom: '1px solid var(--border-1)', width: 160 },
  tdConf: { padding: '10px 12px', borderBottom: '1px solid var(--border-1)', textAlign: 'center' },
  trSub: { background: 'var(--gray-50)' },
  trRuido: { color: 'var(--fg-3)' },

  deltaCel: { display: 'flex', alignItems: 'center', gap: 8 },
  deltaNum: { font: '700 12px/1 var(--font-num)', width: 52, textAlign: 'right', flex: 'none',
    fontVariantNumeric: 'tabular-nums' },
  dbWrap: { flex: 1, display: 'flex', alignItems: 'center', height: 12, minWidth: 70 },
  dbLado: { flex: 1, display: 'flex', height: 8 },
  dbZero: { width: 1, alignSelf: 'stretch', background: 'var(--gray-300)', flex: 'none' },
  dbFill: { height: 8, transition: 'width .3s var(--ease)' },

  chipRuido: { font: '700 10px/1 var(--font-sans)', color: 'var(--fg-3)', background: 'var(--gray-100)',
    padding: '4px 8px', borderRadius: 'var(--r-pill)', cursor: 'help' },
  chipOk: { font: '700 12px/1 var(--font-sans)', color: 'var(--positive)', cursor: 'help' },

  subVazio: { padding: '12px 12px 12px 42px', borderBottom: '1px solid var(--border-1)',
    font: 'var(--text-body-sm)', color: 'var(--fg-4)' },
  vazio: { padding: '34px 12px', textAlign: 'center', font: 'var(--text-body-sm)', color: 'var(--fg-4)' },
  nota: { font: '500 11px/1.6 var(--font-sans)', color: 'var(--fg-4)', padding: '12px 2px' },
  reconNota: { textAlign: 'center', font: 'var(--text-body-sm)', color: 'var(--fg-4)',
    maxWidth: 520, margin: '-28px auto 0' },
};

window.RefundCalendarView = RefundCalendarView;
