// Tráfego interno → Fonte de tráfego (spec 2026-09-30-trafego-interno-design §12.5/§12.6).
// Um item só no submenu (nav 'trafego-fonte'); a fonte (canal) é um filtro: "Todas" usa
// /trafego/canal/todas. Mesmo molde e mesmas peças da Visão geral (TrafegoVisao.jsx:
// TfCabecalho, TfFiltros, TfCards, TfFaixa, TfSerie, TfDonut, TfCascata, TfFunil, TfTabela).
// Filtros extras: fonte, conta (source) e comprador; as opções de conta/comprador vêm do
// payload (sem os próprios filtros, trocar um não esvazia o outro). Tabelas em abas com busca;
// fonte + aba + busca ficam no hash (#trafego-fonte?fonte=taboola&aba=criativos&q=abc). SEM mock.

const TF_ABAS = [
  { key: 'criativos',   label: 'Criativos',   campo: 'porCriativo',  rotulo: 'Criativo',  busca: 'Buscar nome, id ou campanha' },
  { key: 'campanhas',   label: 'Campanhas',   campo: 'porCampanha',  rotulo: 'Campanha',  busca: 'Buscar campanha' },
  { key: 'produtos',    label: 'Produtos',    campo: 'porProduto',   rotulo: 'Produto',   busca: 'Buscar produto' },
  { key: 'contas',      label: 'Contas',      campo: 'porSource',    rotulo: 'Conta',     busca: 'Buscar conta' },
  { key: 'compradores', label: 'Compradores', campo: 'porComprador', rotulo: 'Comprador', busca: 'Buscar comprador' },
];

// Lê fonte/aba/busca do hash (#trafego-fonte?…). Chave antiga #trafego-<canal> já chega
// reescrita pelo App (tfNavDoHash em data.jsx).
const tfFonteLeHash = () => {
  const m = String(location.hash || '').match(/^#trafego-fonte\?(.*)$/);
  const p = new URLSearchParams(m ? m[1] : '');
  const aba = TF_ABAS.some(a => a.key === p.get('aba')) ? p.get('aba') : 'criativos';
  return { fonte: p.get('fonte') || 'todas', aba, q: p.get('q') || '' };
};
const tfFonteGravaHash = ({ fonte, aba, q }) => {
  const p = new URLSearchParams();
  if (fonte && fonte !== 'todas') p.set('fonte', fonte);
  p.set('aba', aba);
  if (q) p.set('q', q);
  try { history.replaceState(null, '', '#trafego-fonte?' + p.toString()); } catch (_e) { /* sem history */ }
};

// Nome do criativo: nome do anúncio (ou "Anúncio" + id em mono) + linha discreta com a
// campanha. Texto completo (nome, campanha, id) no title da célula (tfCriativoTitulo).
const TfCriativoNome = ({ r }) => (
  <span style={{ display: 'flex', flexDirection: 'column', minWidth: 0, gap: 3 }}>
    <span style={tfx.ell}>{r.rtAd || <>Anúncio <span style={tfx.id}>{r.rtAdId || r.key}</span></>}</span>
    <span style={tfx.ellSub}>{r.campanha || 'sem campanha'}</span>
  </span>
);
const tfCriativoTitulo = (r) => [r.rtAd || `Anúncio ${r.rtAdId || r.key}`,
  r.campanha ? `Campanha: ${r.campanha}` : 'Sem campanha', r.rtAdId ? `id ${r.rtAdId}` : null].filter(Boolean).join('\n');

const TrafegoFonteView = () => {
  const inicial = React.useMemo(tfFonteLeHash, []);
  const [period, setPeriod] = React.useState('30d');
  const [customRange, setCustomRange] = React.useState(null);
  const [platform, setPlatform] = React.useState('todas');
  const [refundBy, setRefundBy] = React.useState('cancelamento');
  const [fonte, setFonte] = React.useState(inicial.fonte);
  const [source, setSource] = React.useState('todos');
  const [comprador, setComprador] = React.useState('todos');
  const [aba, setAba] = React.useState(inicial.aba);
  const [buscas, setBuscas] = React.useState({ [inicial.aba]: inicial.q });
  const [canais, setCanais] = React.useState(null);
  const [data, setData] = React.useState(null);
  const [err, setErr] = React.useState(false);
  const [loading, setLoading] = React.useState(true);
  const fullLoading = useFullLoading();
  const withLoad = (fn) => (...a) => { fullLoading.mark(); fn(...a); };
  const retry = useAutoRetry(err);
  const q = buscas[aba] || '';

  React.useEffect(() => { tfFonteGravaHash({ fonte, aba, q }); }, [fonte, aba, q]);
  // Clique no item do menu com a página aberta: o App limpa o hash; a página volta ao padrão
  // (Todas, Criativos, sem busca) em vez de ficar num filtro que o endereço não mostra mais.
  React.useEffect(() => {
    const onHash = () => {
      if (/^#?$/.test(location.hash)) {
        fullLoading.mark();
        setFonte('todas'); setSource('todos'); setComprador('todos'); setAba('criativos'); setBuscas({});
        tfFonteGravaHash({ fonte: 'todas', aba: 'criativos', q: '' });
      }
    };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);

  // Opções do filtro Fonte: canais com gasto/receita na janela; falhou → lista fixa.
  React.useEffect(() => {
    let vivo = true;
    fetchTrafegoCanais({ period, customRange, platform, refundBy })
      .then(rows => { if (vivo) { if (rows.length) window.TF_CANAIS_VIVOS = rows; setCanais(rows); } })
      .catch(() => { if (vivo) setCanais(null); });
    return () => { vivo = false; };
  }, [period, customRange, platform, refundBy]);

  React.useEffect(() => {
    const began = fullLoading.begin();
    let cancelled = false; setLoading(true);
    fetchTrafegoCanal(fonte, { period, customRange, platform, refundBy, source, comprador })
      .then(d => { if (!cancelled) { setData(d); setErr(false); } })
      .catch(() => { if (!cancelled) setErr(true); })
      .finally(() => { if (!cancelled) setLoading(false); fullLoading.end(began); });
    return () => { cancelled = true; };
  }, [fonte, period, customRange, platform, refundBy, source, comprador, retry]);

  // Conta/comprador escolhidos que somem das opções (ex.: troca de período) voltam para
  // "todos"; senão a tela filtraria por algo que o dropdown nem lista mais.
  React.useEffect(() => {
    const op = (data && data.opcoes) || null;
    if (!op) return;
    if (source !== 'todos' && !(op.sources || []).some(o => o.id === source)) withLoad(setSource)('todos');
    if (comprador !== 'todos' && !(op.compradores || []).includes(comprador)) withLoad(setComprador)('todos');
  }, [data]);

  if (err && !data) return (
    <>
      <LoadingScreen conn="offline" />
      <div style={tf.reconNota}>
        Custo do RedTrack × receita do banco por fonte. Se a API caiu, esta tela reconecta sozinha
        a cada 15 s.
      </div>
    </>
  );
  if (!data) return <LoadingScreen conn="connecting" />;

  // Fonte nova: a conta é da fonte anterior, então volta para "Todas".
  const trocaFonte = (f) => { fullLoading.mark(); setFonte(f); setSource('todos'); };
  const listaCanais = (canais && canais.length ? canais : TF_CANAIS_FALLBACK);
  const fonteOpts = [{ key: 'todas', label: 'Todas' },
    ...listaCanais.map(c => ({ key: c.canal, label: c.label, dot: TF_CANAL_COR[c.canal] || TF_OUTROS_COR }))];
  if (!fonteOpts.some(o => o.key === fonte)) fonteOpts.push({ key: fonte, label: tfCanalLabel(fonte), dot: TF_CANAL_COR[fonte] || TF_OUTROS_COR });
  const op = data.opcoes || {};
  const srcOpts = [{ key: 'todos', label: 'Todas' },
    ...(op.sources || []).map(o => ({ key: o.id, label: o.label || o.id || '(sem source)' }))];
  const compOpts = [{ key: 'todos', label: 'Todos' },
    ...(op.compradores || []).map(c => ({ key: c, label: c }))];
  const todas = fonte === 'todas';
  const filtrado = !todas || source !== 'todos' || comprador !== 'todos';
  const roasAlvo = data.meta ? data.meta.roasAlvo : null;
  const abaDef = TF_ABAS.find(a => a.key === aba) || TF_ABAS[0];
  const setQ = (v) => setBuscas(b => ({ ...b, [aba]: v }));
  const linhas = data[abaDef.campo] || [];

  return (
    <div style={{ position: 'relative' }}>
      <TfCabecalho titulo="Fonte de tráfego" data={data} err={err} escopo={<>
          <Dropdown icon="target" label="Fonte" value={fonte} onChange={trocaFonte} options={fonteOpts} />
          <SearchDropdown icon="globe" label="Conta" value={source} onChange={withLoad(setSource)} options={srcOpts} />
          <Dropdown icon="users" label="Comprador" value={comprador} onChange={withLoad(setComprador)} options={compOpts} />
        </>}>
        <TfFiltros period={period} setPeriod={withLoad(setPeriod)}
          customRange={customRange} setCustomRange={withLoad(setCustomRange)}
          platform={platform} setPlatform={withLoad(setPlatform)}
          refundBy={refundBy} setRefundBy={withLoad(setRefundBy)} />
      </TfCabecalho>

      <TfCards k={data.kpis || {}} ant={data.anterior} serie={data.serie || []} meta={data.meta}
        janelaAnterior={data.janelaAnterior} />
      <TfFaixa k={data.kpis || {}} ant={data.anterior} />

      <div style={tf.chartRow}>
        <div style={tf.chartMain}><TfSerie data={data} chKey={'tf-fonte-' + fonte} semMeta={filtrado} /></div>
        <div style={tf.chartSide}>
          {todas
            ? <TfDonut rows={data.porCanal || []} dimensao="canal" corDe={tfCorCanal} />
            : <TfDonut rows={data.porSource || []} dimensao="conta" corDe={tfCorPaleta} />}
        </div>
      </div>

      <div style={tf.duo}>
        <TfCascata etapas={data.cascata || []} />
        <TfFunil etapas={data.funil || []} />
      </div>

      <TfTabela key={abaDef.key} id="fonte-abas" rows={linhas} rotulo={abaDef.rotulo} loading={loading} roasAlvo={roasAlvo}
        q={q} setQ={setQ} placeholder={abaDef.busca}
        titulo={<div style={tfx.abas}><Segmented value={aba} onChange={setAba} options={TF_ABAS.map(a => ({ key: a.key, label: a.label }))} /></div>}
        campos={abaDef.key === 'criativos' ? (r) => [r.rtAd, r.rtAdId, r.campanha, r.label] : undefined}
        nome={abaDef.key === 'criativos' ? (r) => <TfCriativoNome r={r} /> : undefined}
        titleDe={abaDef.key === 'criativos' ? tfCriativoTitulo : undefined} />

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

const tfx = {
  abas: { maxWidth: '100%', overflowX: 'auto' },
  ell: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
  id: { font: '500 12px/1 var(--font-mono)', color: 'var(--fg-2)' },
  ellSub: { font: '500 11.5px/1.2 var(--font-sans)', color: 'var(--fg-3)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
};

window.TrafegoFonteView = TrafegoFonteView;
