/* Análise de campanhas (Medição).
   Cabeçalho no mesmo modelo de Resultados: marca no header, filtros e menu no painel.
   O painel mostra paid media Meta no ar, objectivos versus resultados e as alterações sugeridas.
   A ficha da campanha mantém a leitura, as áreas e as ligações para corrigir. */

const AN_AREA = { setup: 'Setup', copy: 'Copy', criativo: 'Criativo' };
const AN_PRIO = { p0: 'Agora', p1: 'Seguinte', p2: 'Depois' };
const AN_LIGACAO = { criativo: 'Abrir criativo', publico: 'Abrir público', formulario: 'Abrir formulário', orcamento: 'Abrir orçamento' };
const AN_ETAPAS = new Set(['leads', 'qualificados', 'oportunidades', 'fechos', 'demos', 'testing_rolls', 'primeira_encomenda']);
const AN_NAV_KEY = 'mkt-analise-campanhas-nav';
const AN_PRIO_RANK = { p0: 0, p1: 1, p2: 2 };
const AN_LUZ_RANK = { vermelho: 0, amarelo: 1, verde: 2 };

function anParseHash() {
  const params = new URLSearchParams(String(window.location.hash || '').replace(/^#/, ''));
  return {
    camp: params.get('analise') || null,
    correr: params.get('correr') === '1',
    registo: params.get('registo') || null,
  };
}

function anWriteHash({ camp, correr, registo }, { replace } = {}) {
  const params = new URLSearchParams(String(window.location.hash || '').replace(/^#/, ''));
  params.set('screen', 'marketing');
  params.set('sub', 'analise-campanhas');
  if (camp) params.set('analise', camp); else params.delete('analise');
  if (correr) params.set('correr', '1'); else params.delete('correr');
  if (registo) params.set('registo', registo); else params.delete('registo');
  params.delete('camp');
  params.delete('canal');
  params.delete('tab');
  const next = params.toString();
  if (replace) {
    const url = `${window.location.pathname}${window.location.search}#${next}`;
    window.history.replaceState(null, '', url);
    return;
  }
  window.location.hash = next;
}

function anClearOwnHash() {
  const params = new URLSearchParams(String(window.location.hash || '').replace(/^#/, ''));
  if (!params.has('analise') && !params.has('correr') && !params.has('registo')) return;
  if (params.get('sub') === 'analise-campanhas') return;
  params.delete('analise');
  params.delete('correr');
  params.delete('registo');
  const next = params.toString();
  const url = `${window.location.pathname}${window.location.search}${next ? `#${next}` : ''}`;
  window.history.replaceState(null, '', url);
}

function anIrSetup(campId, tab) {
  const params = new URLSearchParams(String(window.location.hash || '').replace(/^#/, ''));
  params.set('screen', 'marketing');
  params.set('sub', 'publicacao');
  params.set('camp', campId);
  params.set('canal', 'meta_ads');
  if (tab) params.set('tab', tab); else params.delete('tab');
  params.delete('analise');
  params.delete('correr');
  params.delete('registo');
  window.location.hash = params.toString();
}

function anIrCriativo(campId) {
  if (window.mktNavToSub) window.mktNavToSub('conteudos');
  setTimeout(() => { if (window.mktProducaoOpenCampanha) window.mktProducaoOpenCampanha(campId); }, 200);
}

function anLigar(campId, ligacao) {
  if (ligacao === 'criativo') anIrCriativo(campId);
  else if (ligacao === 'publico') anIrSetup(campId, 'publicos');
  else if (ligacao === 'formulario') anIrSetup(campId, 'form');
  else if (ligacao === 'orcamento') anIrSetup(campId, 'orcamento');
}

async function anFetch(url) {
  const res = await fetch(url, { headers: { 'Content-Type': 'application/json' } });
  if (!res.ok) {
    let b = {};
    try { b = await res.json(); } catch {}
    throw new Error(b.error || `HTTP ${res.status}`);
  }
  return res.json();
}

function anQuando(iso) {
  if (!iso) return '';
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return '';
  return d.toLocaleString('pt-PT', { day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit' });
}

function anDia(iso) {
  if (!iso) return '';
  const d = new Date(`${String(iso).slice(0, 10)}T00:00:00`);
  if (Number.isNaN(d.getTime())) return '';
  return d.toLocaleDateString('pt-PT', { day: '2-digit', month: 'short' });
}

function anEur(v) {
  return window.resFmtEur ? window.resFmtEur(v) : (v == null ? '—' : `${Math.round(Number(v))} €`);
}

function anN(v) {
  return window.resFmtN ? window.resFmtN(v) : (v == null ? '—' : String(Math.round(Number(v))));
}

function anDedup(melhorias) {
  const out = [];
  const seen = new Set();
  for (const m of melhorias || []) {
    const dito = String(m?.o_que_mudar || '').toLowerCase();
    const key = /budget|orçamento|orcamento|desbloquear a entrega/.test(dito) ? 'budget' : dito.slice(0, 48);
    if (!key || seen.has(key)) continue;
    seen.add(key);
    out.push(m);
  }
  return out;
}

function anEtapa(ficha, key) {
  return (ficha?.etapas || []).find(e => e.key === key) || null;
}

function anEtapasVisiveis(ficha) {
  return (ficha?.etapas || []).filter(e => AN_ETAPAS.has(e.key) && (e.objectivo || e.real || e.key === 'leads' || e.key === 'qualificados'));
}

function anPior(lights) {
  const lista = (lights || []).filter(Boolean);
  lista.sort((a, b) => (AN_LUZ_RANK[a] ?? 9) - (AN_LUZ_RANK[b] ?? 9));
  return lista[0] || null;
}

function anPct(real, base) {
  const b = Number(base);
  if (!Number.isFinite(b) || b <= 0) return null;
  return Math.round((Number(real) || 0) / b * 100);
}

function anRitmoGasto(c) {
  if (!c?.investimento_eur || c.ritmo_pct == null) return null;
  return c.investimento_eur * c.ritmo_pct / 100;
}

function anSomaEtapa(campanhas, key) {
  let real = 0;
  let esperado = 0;
  let objectivo = 0;
  let temEsp = false;
  let temObj = false;
  const lights = [];
  for (const c of campanhas || []) {
    const e = anEtapa(c, key);
    if (!e) continue;
    real += Number(e.real) || 0;
    if (e.esperado != null) { temEsp = true; esperado += Number(e.esperado) || 0; }
    if (e.objectivo != null) { temObj = true; objectivo += Number(e.objectivo) || 0; }
    if (e.light) lights.push(e.light);
  }
  return {
    real,
    esperado: temEsp ? esperado : null,
    objectivo: temObj ? objectivo : null,
    light: anPior(lights),
  };
}

function anLoadNav() {
  try { return JSON.parse(sessionStorage.getItem(AN_NAV_KEY) || '{}'); } catch { return {}; }
}

function anCsv(rows) {
  const esc = (v) => {
    const s = v == null ? '' : String(v);
    return /[;"\n]/.test(s) ? `"${s.replaceAll('"', '""')}"` : s;
  };
  const header = ['Campanha', 'Marca', 'Estado', 'Janela', 'Ritmo %', 'Gasto', 'Orçamento', 'Leads', 'Leads esperados', 'Leads objectivo', 'MQL', 'MQL esperados', 'MQL objectivo', 'CPL', 'Semáforo', 'Leitura', 'Alterações'];
  const lines = [header.join(';')];
  for (const c of rows) {
    const leads = anEtapa(c, 'leads') || {};
    const mql = anEtapa(c, 'qualificados') || {};
    const alts = anDedup(c.melhorias).map(m => m.o_que_mudar).join(' | ');
    lines.push([
      c.titulo, c.marca_nome, c.no_ar ? 'no ar' : 'anterior',
      `${c.janela_inicio || ''} ${c.janela_fim || ''}`.trim(), c.ritmo_pct ?? '',
      c.spend_eur ?? '', c.investimento_eur ?? '',
      leads.real ?? '', leads.esperado ?? '', leads.objectivo ?? '',
      mql.real ?? '', mql.esperado ?? '', mql.objectivo ?? '',
      c.cpl_eur ?? '', c.light || '', c.leitura || '', alts,
    ].map(esc).join(';'));
  }
  const blob = new Blob(['\uFEFF' + lines.join('\n')], { type: 'text/csv;charset=utf-8' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = 'analise-campanhas.csv';
  a.click();
  setTimeout(() => URL.revokeObjectURL(a.href), 1000);
}

const AnPonto = ({ light }) => (
  <span style={{
    width: 8, height: 8, borderRadius: 99, flexShrink: 0, display: 'inline-block',
    background: (window.RES_LIGHT || {})[light] || 'var(--text-dim)',
  }} />
);

const AnComparar = ({ campanhas, modo, onAbrir }) => {
  const Bullet = window.AnBullet;
  const fmtN = window.anFmtN || anN;
  const fmtEur = window.anFmtEur || anEur;
  const tops = (campanhas || []).slice(0, 6);
  const resto = Math.max(0, (campanhas || []).length - tops.length);
  if (!tops.length) return window.AnVazio ? <window.AnVazio altura={120} texto="Sem campanhas neste filtro." /> : null;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      {tops.map(c => {
        const leads = anEtapa(c, 'leads');
        const mql = anEtapa(c, 'qualificados');
        const ritmo = anRitmoGasto(c);
        if (Bullet && modo === 'leads') {
          return (
            <Bullet key={c.campanha_id}
              label={c.titulo}
              real={Number(leads?.real) || 0}
              bpData={leads?.esperado}
              bpAno={leads?.objectivo}
              fmt={fmtN}
              altura={12}
              sub={[c.marca_nome, mql ? `${anN(mql.real)} MQL` : null].filter(Boolean).join(' · ')}
              nomes={{ real: 'Leads', marca: 'Esperado à data', fim: 'Objectivo', nota: '% do esperado à data' }}
              onClick={() => onAbrir(c)}
            />
          );
        }
        if (Bullet && modo === 'gasto') {
          return (
            <Bullet key={c.campanha_id}
              label={c.titulo}
              real={Number(c.spend_eur) || 0}
              bpData={ritmo}
              bpAno={c.investimento_eur}
              fmt={fmtEur}
              altura={12}
              sub={c.ritmo_pct != null ? `janela ${c.ritmo_pct}%` : c.marca_nome}
              nomes={{ real: 'Gasto', marca: 'Ritmo da janela', fim: 'Orçamento', nota: '% do ritmo' }}
              onClick={() => onAbrir(c)}
            />
          );
        }
        const real = modo === 'gasto' ? Number(c.spend_eur) || 0 : Number(leads?.real) || 0;
        const marca = modo === 'gasto' ? ritmo : leads?.esperado;
        const fim = modo === 'gasto' ? c.investimento_eur : leads?.objectivo;
        const pct = anPct(real, marca != null ? marca : fim);
        return (
          <button key={c.campanha_id} type="button" onClick={() => onAbrir(c)} style={{ textAlign: 'left', background: 'none', border: 0, padding: 0, cursor: 'pointer', width: '100%', color: 'inherit', fontFamily: 'inherit' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, fontSize: 12 }}>
              <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.titulo}</span>
              <span style={{ flexShrink: 0 }}>{modo === 'gasto' ? anEur(real) : anN(real)}{marca != null ? ` / ${modo === 'gasto' ? anEur(marca) : anN(marca)}` : ''}</span>
            </div>
            {window.resBar && window.resBar(pct, modo === 'leads' ? leads?.light : null)}
          </button>
        );
      })}
      {resto > 0 && <div style={{ fontSize: 11, color: 'var(--text-dim)' }}>e mais {resto} na lista de campanhas</div>}
    </div>
  );
};

const AnLista = ({ campanhas, onAbrir }) => (
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(min(100%, 420px), 1fr))', gap: 10 }}>
    {campanhas.map(c => {
      const leads = anEtapa(c, 'leads');
      const mql = anEtapa(c, 'qualificados');
      const alt = anDedup(c.melhorias)[0];
      const luz = (window.RES_LIGHT || {})[c.light];
      return (
        <div key={c.campanha_id} className="card" onClick={() => onAbrir(c)}
          style={{ textAlign: 'left', padding: '14px 16px', cursor: 'pointer', borderLeft: `3px solid ${luz || 'var(--border)'}` }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', gap: 16, alignItems: 'flex-start', flexWrap: 'wrap' }}>
            <div style={{ minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, fontWeight: 650, color: 'var(--text-muted)', fontFamily: 'var(--font-mono)', letterSpacing: '0.04em', textTransform: 'uppercase' }}>
                <AnPonto light={c.light} />
                {c.marca_nome || c.brand_name || 'Meta Ads'}
                {c.no_ar ? ' · no ar' : ' · anterior'}
              </div>
              <div className="font-display" style={{ fontSize: 16, fontWeight: 650, marginTop: 4 }}>{c.titulo}</div>
              <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>
                {anDia(c.janela_inicio) || '—'} → {anDia(c.janela_fim) || '—'}
                {c.ritmo_pct != null ? ` · janela ${c.ritmo_pct}%` : ''}
              </div>
            </div>
            <div style={{ display: 'flex', gap: 16, flexShrink: 0, textAlign: 'right' }}>
              <div>
                <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>GASTO</div>
                <div className="font-display" style={{ fontSize: 14, fontWeight: 650 }}>{anEur(c.spend_eur)}</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>de {anEur(c.investimento_eur)}</div>
              </div>
              <div>
                <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>LEADS</div>
                <div className="font-display" style={{ fontSize: 14, fontWeight: 650, color: (window.RES_LIGHT || {})[leads?.light] || 'inherit' }}>{anN(leads?.real)}</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>de {leads?.esperado != null ? anN(leads.esperado) : '—'}</div>
              </div>
              <div>
                <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>MQL</div>
                <div className="font-display" style={{ fontSize: 14, fontWeight: 650, color: (window.RES_LIGHT || {})[mql?.light] || 'inherit' }}>{anN(mql?.real)}</div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>de {mql?.esperado != null ? anN(mql.esperado) : '—'}</div>
              </div>
            </div>
          </div>
          {c.leitura && (
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginTop: 10, lineHeight: 1.4, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>
              {c.leitura}
            </div>
          )}
          {alt && (
            <div style={{ fontSize: 12.5, marginTop: 8, lineHeight: 1.4 }}>
              <span style={{ fontWeight: 700, fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.04em', color: alt.prioridade === 'p0' ? 'var(--danger)' : alt.prioridade === 'p1' ? 'var(--warning)' : 'var(--text-muted)' }}>
                {AN_PRIO[alt.prioridade] || alt.prioridade} · {AN_AREA[alt.area] || alt.area}
              </span>
              <span style={{ color: 'var(--text)' }}> {alt.o_que_mudar}</span>
            </div>
          )}
          <div style={{ display: 'flex', gap: 14, marginTop: 10 }}>
            <button type="button" onClick={(e) => { e.stopPropagation(); onAbrir(c); }} style={{ border: 0, background: 'none', color: 'var(--ai-500)', fontWeight: 650, fontSize: 12, cursor: 'pointer', padding: 0 }}>
              Ver análise →
            </button>
            <button type="button" onClick={(e) => { e.stopPropagation(); anWriteHash({ camp: c.campanha_id, correr: true }); }} style={{ border: 0, background: 'none', color: 'var(--ai-500)', fontWeight: 650, fontSize: 12, cursor: 'pointer', padding: 0 }}>
              {c.analise_id ? 'Actualizar análise' : 'Gerar análise'}
            </button>
          </div>
        </div>
      );
    })}
  </div>
);

const AnAlteracao = ({ m, onAbrir }) => (
  <div className="card" style={{ padding: '12px 14px' }}>
    <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginBottom: 6, flexWrap: 'wrap' }}>
      <span style={{ fontSize: 10, fontWeight: 700, fontFamily: 'var(--font-mono)', color: m.prioridade === 'p0' ? 'var(--danger)' : m.prioridade === 'p1' ? 'var(--warning)' : 'var(--text-muted)' }}>
        {AN_PRIO[m.prioridade] || m.prioridade}
      </span>
      <span style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', color: 'var(--ai-500)', fontFamily: 'var(--font-mono)' }}>{AN_AREA[m.area] || m.area}</span>
      <button type="button" onClick={() => onAbrir({ campanha_id: m.campanha_id })} style={{ marginLeft: 'auto', border: 0, background: 'none', color: 'var(--text-muted)', fontSize: 12, cursor: 'pointer', padding: 0, textAlign: 'right' }}>
        {m.titulo}
      </button>
    </div>
    <div style={{ fontSize: 14, fontWeight: 650, lineHeight: 1.35 }}>{m.o_que_mudar}</div>
    {m.porque && <div style={{ fontSize: 12.5, color: 'var(--text-muted)', marginTop: 4, lineHeight: 1.45 }}>{m.porque}</div>}
    <div style={{ display: 'flex', gap: 14, marginTop: 8 }}>
      <button type="button" onClick={() => onAbrir({ campanha_id: m.campanha_id })} style={{ border: 0, background: 'none', color: 'var(--ai-500)', fontWeight: 650, fontSize: 12, cursor: 'pointer', padding: 0 }}>
        Ver análise →
      </button>
      {m.ligacao && AN_LIGACAO[m.ligacao] && (
        <button type="button" onClick={() => anLigar(m.campanha_id, m.ligacao)} style={{ border: 0, background: 'none', color: 'var(--ai-500)', fontWeight: 650, fontSize: 12, cursor: 'pointer', padding: 0 }}>
          {AN_LIGACAO[m.ligacao]} →
        </button>
      )}
    </div>
  </div>
);

const AnPainel = ({ lista, erro, brand, isAll, onAbrir, isMobile }) => {
  const saved = anLoadNav();
  const [vista, setVista] = React.useState(['no_ar', 'anteriores', 'todas'].includes(saved.vista) ? saved.vista : 'no_ar');
  const [luz, setLuz] = React.useState(['', 'atencao', 'verde'].includes(saved.luz) ? saved.luz : '');
  const [busca, setBusca] = React.useState(false);
  React.useEffect(() => {
    try { sessionStorage.setItem(AN_NAV_KEY, JSON.stringify({ vista, luz })); } catch {}
  }, [vista, luz]);

  const daMarca = (lista || []).filter(c => isAll || brand === 'todas' || c.brand_slug === brand);
  const passaVista = (c) => (vista === 'todas' ? true : vista === 'no_ar' ? !!c.no_ar : !c.no_ar);
  const passaLuz = (c) => {
    if (!luz) return true;
    if (luz === 'atencao') return c.light === 'vermelho' || c.light === 'amarelo';
    return c.light === 'verde';
  };
  const visiveis = daMarca.filter(c => passaVista(c) && passaLuz(c));
  const baseEstado = daMarca.filter(passaLuz);
  const baseLuz = daMarca.filter(passaVista);
  const leadsAgg = anSomaEtapa(visiveis, 'leads');
  const mqlAgg = anSomaEtapa(visiveis, 'qualificados');
  const spend = visiveis.reduce((s, c) => s + (Number(c.spend_eur) || 0), 0);
  const inv = visiveis.reduce((s, c) => s + (Number(c.investimento_eur) || 0), 0);
  const ritmo = visiveis.reduce((s, c) => s + (anRitmoGasto(c) || 0), 0);
  const mudancas = visiveis.flatMap(c => anDedup(c.melhorias).map(m => ({
    ...m, campanha_id: c.campanha_id, titulo: c.titulo,
  }))).sort((a, b) => (AN_PRIO_RANK[a.prioridade] ?? 9) - (AN_PRIO_RANK[b.prioridade] ?? 9));
  const p0 = mudancas.filter(m => m.prioridade === 'p0').length;
  const semAnalise = visiveis.filter(c => !c.analise_id);
  const leadsPct = anPct(leadsAgg.real, leadsAgg.esperado != null ? leadsAgg.esperado : leadsAgg.objectivo);
  const gastoBase = ritmo > 0 ? ritmo : inv;
  const gastoPct = anPct(spend, gastoBase);
  const Kpi = window.ResKpi;
  const Filtro = window.ResFiltro;
  const MenuAccoes = window.ResMenuAccoes;
  const Icone = window.ResIcone;
  const Lupa = window.ResIconeLupa;
  const Busca = window.ResBusca;
  const Cartao = window.AnCartao;
  const Gauge = window.AnGauge;
  const filtrosActivos = [
    vista !== 'no_ar' && (vista === 'anteriores' ? 'Anteriores' : 'Todas'),
    luz === 'atencao' && 'A corrigir',
    luz === 'verde' && 'No caminho',
  ].filter(Boolean);
  const limpar = () => { setVista('no_ar'); setLuz(''); };
  const menuItens = [
    ...(filtrosActivos.length ? [{ id: 'limpar', label: 'Limpar filtros', sub: filtrosActivos.join(' · '), onClick: limpar }] : []),
    { id: 'csv', label: 'Exportar CSV', sub: 'Campanhas deste filtro', disabled: !visiveis.length, onClick: () => anCsv(visiveis) },
  ];
  const menu = MenuAccoes ? <MenuAccoes icone items={menuItens} onOpen={() => setBusca(false)} /> : (
    <button type="button" className="btn btn-sm" disabled={!visiveis.length} onClick={() => anCsv(visiveis)}>CSV</button>
  );
  const itensBusca = daMarca.map(c => ({
    id: c.campanha_id,
    tipo: c.no_ar ? 'No ar' : 'Anterior',
    titulo: c.titulo || '—',
    detalhe: [c.marca_nome, c.light, anDia(c.janela_inicio)].filter(Boolean).join(' · '),
    texto: c.leitura || '',
  }));
  const fecharBusca = React.useCallback(() => setBusca(false), []);
  const graficoCols = isMobile ? '1fr' : '1fr 1fr';

  const blocoGrafico = (titulo, sub, modo, gauge) => {
    const corpo = (
      <div style={{ display: 'grid', gridTemplateColumns: isMobile || !Gauge ? '1fr' : '150px 1fr', gap: 16, alignItems: 'center' }}>
        {Gauge && gauge}
        <AnComparar campanhas={visiveis} modo={modo} onAbrir={onAbrir} />
      </div>
    );
    if (Cartao) return <Cartao titulo={titulo} sub={sub}>{corpo}</Cartao>;
    return (
      <div className="card" style={{ padding: 16 }}>
        <div className="font-display" style={{ fontSize: 13.5, fontWeight: 650 }}>{titulo}</div>
        {sub && <div style={{ fontSize: 11, color: 'var(--text-muted)', margin: '2px 0 10px' }}>{sub}</div>}
        {corpo}
      </div>
    );
  };

  return (
    <>
      {busca && Busca && (
        <Busca itens={itensBusca} placeholder="Procurar campanhas" vazio="Nenhuma campanha nesta marca."
          onPick={(it) => onAbrir({ campanha_id: it.id })} onClose={fecharBusca} />
      )}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 8, marginBottom: 18 }}>
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
          {Filtro ? (
            <>
              <Filtro label="Estado" value={vista} marcado={vista !== 'no_ar'} onChange={setVista}
                options={[
                  { value: 'no_ar', label: 'No ar', n: baseEstado.filter(c => c.no_ar).length },
                  { value: 'anteriores', label: 'Anteriores', n: baseEstado.filter(c => !c.no_ar).length },
                  { value: 'todas', label: 'Todas', n: baseEstado.length },
                ]} />
              <Filtro label="Semáforo" value={luz} marcado={!!luz} onChange={setLuz}
                options={[
                  { value: '', label: 'Todos', n: baseLuz.length },
                  { value: 'atencao', label: 'A corrigir', cor: 'var(--danger)', n: baseLuz.filter(c => c.light === 'vermelho' || c.light === 'amarelo').length },
                  { value: 'verde', label: 'No caminho', cor: 'var(--success)', n: baseLuz.filter(c => c.light === 'verde').length },
                ]} />
            </>
          ) : (
            <>
              <button type="button" className={vista === 'no_ar' ? 'btn btn-sm' : 'btn btn-sm btn-ghost'} onClick={() => setVista('no_ar')}>No ar</button>
              <button type="button" className={vista === 'anteriores' ? 'btn btn-sm' : 'btn btn-sm btn-ghost'} onClick={() => setVista('anteriores')}>Anteriores</button>
            </>
          )}
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginLeft: 'auto' }}>
          {Icone && Busca && (
            <Icone label="Procurar campanhas" activo={busca} onClick={() => setBusca(v => !v)}><Lupa /></Icone>
          )}
          {menu}
        </div>
      </div>

      {erro && <div style={{ color: 'var(--danger)', fontSize: 13, marginBottom: 12 }}>{erro}</div>}
      {lista == null && !erro && <div style={{ color: 'var(--text-muted)', fontSize: 13 }}>A carregar campanhas…</div>}

      {lista && (
        <>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(148px, 1fr))', gap: 10, marginBottom: 16 }}>
            {Kpi && <Kpi label="Campanhas" value={anN(visiveis.length)} sub={vista === 'no_ar' ? 'paid media Meta no ar' : 'neste filtro'} />}
            {Kpi && <Kpi label="Gasto" value={anEur(spend)} sub={inv ? `de ${anEur(inv)} de orçamento` : 'sem orçamento'} />}
            {Kpi && <Kpi label="Leads" value={anN(leadsAgg.real)} light={leadsAgg.light} sub={leadsAgg.esperado != null ? `de ${anN(leadsAgg.esperado)} esperados` : 'sem esperado à data'} />}
            {Kpi && <Kpi label="MQL" value={anN(mqlAgg.real)} light={mqlAgg.light} sub={mqlAgg.esperado != null ? `de ${anN(mqlAgg.esperado)} esperados` : 'sem esperado à data'} />}
            {Kpi && <Kpi label="Alterações" value={anN(mudancas.length)} light={p0 ? 'vermelho' : mudancas.length ? 'amarelo' : null} sub={p0 ? `${p0} para fazer agora` : 'sugestões da análise'} />}
          </div>

          {visiveis.length === 0 ? (
            <div style={{ color: 'var(--text-muted)', fontSize: 14, marginBottom: 16 }}>
              {vista === 'no_ar' ? 'Nenhuma campanha Meta no ar neste filtro.' : 'Nenhuma campanha neste filtro.'}
            </div>
          ) : (
            <>
              <div style={{ display: 'grid', gridTemplateColumns: graficoCols, gap: 12, marginBottom: 18 }}>
                {blocoGrafico(
                  'Leads · objectivo versus resultado',
                  'Barra: resultado. Traço escuro: esperado à data. Traço cinza: objectivo.',
                  'leads',
                  Gauge && (
                    <Gauge pct={leadsPct} valor={anN(leadsAgg.real)} label="Leads" luz={leadsAgg.light} size={148}
                      sub={leadsAgg.esperado != null ? `de ${anN(leadsAgg.esperado)} esperados` : 'sem esperado à data'} />
                  ),
                )}
                {blocoGrafico(
                  'Investimento · ritmo da janela',
                  'Barra: gasto. Traço escuro: quanto devia estar gasto ao ritmo da janela. Traço cinza: orçamento.',
                  'gasto',
                  Gauge && (
                    <Gauge pct={ritmo > 0 ? gastoPct : null} valor={anEur(spend)} label="Gasto" size={148}
                      luz={ritmo > 0 && window.anLuzPct ? window.anLuzPct(gastoPct) : null}
                      sub={ritmo > 0 ? `de ${anEur(ritmo)} ao ritmo` : (inv ? `de ${anEur(inv)}` : 'sem orçamento')} />
                  ),
                )}
              </div>

              <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: 8 }}>
                <div className="font-display" style={{ fontSize: 14, fontWeight: 650 }}>Alterações a fazer</div>
                {mudancas.length > 0 && <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{mudancas.length}</span>}
              </div>
              {mudancas.length > 0 ? (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 8 }}>
                  {mudancas.slice(0, 8).map((m, i) => <AnAlteracao key={`${m.campanha_id}-${i}`} m={m} onAbrir={onAbrir} />)}
                  {mudancas.length > 8 && <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Mais {mudancas.length - 8} alterações nas fichas das campanhas.</div>}
                </div>
              ) : (
                <div style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 8 }}>Sem correcções gravadas para as campanhas deste filtro.</div>
              )}
              {semAnalise.length > 0 && (
                <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 8 }}>
                  {semAnalise.length === 1 ? '1 campanha ainda sem análise gravada.' : `${semAnalise.length} campanhas ainda sem análise gravada.`} Abre a ficha e gera a leitura.
                </div>
              )}
              <div style={{ fontSize: 11, color: 'var(--text-dim)', marginBottom: 22 }}>Sugestão. Não altera a campanha na Meta.</div>

              <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: 8 }}>
                <div className="font-display" style={{ fontSize: 14, fontWeight: 650 }}>Campanhas</div>
                <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{visiveis.length}</span>
              </div>
              <AnLista campanhas={visiveis} onAbrir={onAbrir} />
            </>
          )}
        </>
      )}
    </>
  );
};

const AnDetalhe = ({ hash, onBack }) => {
  const [ficha, setFicha] = React.useState(null);
  const [erro, setErro] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [aActualizar, setAActualizar] = React.useState(false);
  const [hist, setHist] = React.useState([]);
  window.useMktZoneLoading(loading && !ficha);

  React.useEffect(() => {
    let alive = true;
    setLoading(true);
    setErro(null);
    anFetch(`/api/marketing/activacao/campanha/${encodeURIComponent(hash.camp)}/ficha`)
      .then(d => { if (alive) setFicha(d); })
      .catch(e => { if (alive) setErro(e.message); })
      .finally(() => { if (alive) setLoading(false); });
    return () => { alive = false; };
  }, [hash.camp]);

  React.useEffect(() => {
    if (!hash.correr) return undefined;
    let alive = true;
    setAActualizar(true);
    anFetch(`/api/marketing/activacao/campanha/${encodeURIComponent(hash.camp)}/analise-meta`)
      .then(d => {
        if (!alive) return;
        setFicha(prev => ({
          ...(prev || {}),
          leitura: d.leitura || prev?.leitura,
          melhorias: anDedup(d.melhorias || []),
          criado_em: d.criado_em || new Date().toISOString(),
          cpl_eur: d.metricas?.cpl != null ? Number(d.metricas.cpl) : prev?.cpl_eur,
          analise_id: d.registo_id || prev?.analise_id,
        }));
        if (d.registo_id) anWriteHash({ camp: hash.camp, registo: d.registo_id }, { replace: true });
      })
      .catch(e => { if (alive) setErro(e.message); })
      .finally(() => { if (alive) setAActualizar(false); });
    return () => { alive = false; };
  }, [hash.camp, hash.correr]);

  React.useEffect(() => {
    let alive = true;
    anFetch(`/api/marketing/activacao/campanha/${encodeURIComponent(hash.camp)}/analises-meta`)
      .then(d => { if (alive) setHist(d.analises || []); })
      .catch(() => {});
    return () => { alive = false; };
  }, [hash.camp, ficha?.criado_em]);

  const leads = anEtapa(ficha, 'leads');
  const mql = anEtapa(ficha, 'qualificados');
  const melhorias = anDedup(ficha?.melhorias);
  const sub = ficha ? [
    ficha.marca_nome,
    ficha.no_ar ? 'no ar' : 'fora do ar',
    `${anDia(ficha.janela_inicio) || '—'} → ${anDia(ficha.janela_fim) || '—'}`,
  ].filter(Boolean).join(' · ') : '';
  const Trilho = window.ResTrilho;
  const MenuAccoes = window.ResMenuAccoes;
  const menuItens = [
    { id: 'painel', label: 'Painel', sub: 'Campanhas no ar, objectivos e alterações', onClick: onBack },
    { id: 'actualizar', label: aActualizar ? 'A actualizar…' : 'Actualizar análise', sub: 'Leitura e alterações com os dados de agora', disabled: aActualizar || loading, onClick: () => anWriteHash({ camp: hash.camp, correr: true }) },
    { separador: true },
    { id: 'activacao', label: 'Abrir na activação', sub: 'Setup da campanha Meta', onClick: () => anIrSetup(hash.camp) },
    { id: 'criativo', label: 'Abrir criativo', sub: 'Produção de conteúdos', onClick: () => anIrCriativo(hash.camp) },
  ];

  return (
    <>
      {Trilho ? (
        <Trilho
          segmentos={[{ label: 'Análise de campanhas', onClick: onBack }, { label: ficha?.titulo || (loading ? 'A carregar…' : 'Campanha') }]}
          nota={ficha ? (
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontSize: 12, color: 'var(--text-muted)', flexWrap: 'wrap' }}>
              <AnPonto light={ficha.light} />
              <span>{sub}</span>
              {ficha.criado_em && <span>leitura {anQuando(ficha.criado_em)}</span>}
            </span>
          ) : null}
          extra={(
            <>
              <button type="button" className="btn btn-sm" disabled={aActualizar || loading} onClick={() => anWriteHash({ camp: hash.camp, correr: true })}>
                {aActualizar ? 'A actualizar…' : 'Actualizar análise'}
              </button>
              {MenuAccoes && <MenuAccoes icone items={menuItens} />}
            </>
          )}
        />
      ) : (
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12, marginBottom: 14 }}>
          <button type="button" onClick={onBack} style={{ border: 0, background: 'none', color: 'var(--ai-500)', fontWeight: 650, fontSize: 12, cursor: 'pointer', padding: 0 }}>
            ← Análise de campanhas
          </button>
          <button type="button" className="btn btn-sm" disabled={aActualizar || loading} onClick={() => anWriteHash({ camp: hash.camp, correr: true })}>
            {aActualizar ? 'A actualizar…' : 'Actualizar análise'}
          </button>
        </div>
      )}

      {loading && !ficha && <div style={{ color: 'var(--text-muted)', fontSize: 13 }}>A carregar objectivos e resultados…</div>}
      {erro && <div style={{ color: 'var(--danger)', fontSize: 13, marginBottom: 12 }}>{erro}</div>}
      {ficha && (
        <>
          <h2 className="font-display" style={{ margin: '0 0 4px', fontSize: 22, fontWeight: 700 }}>{ficha.titulo}</h2>
          {!Trilho && <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 14 }}>{sub}</div>}
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(148px, 1fr))', gap: 10, margin: '14px 0 16px' }}>
            {window.ResKpi && <window.ResKpi label="Gasto" value={anEur(ficha.spend_eur)} sub={`de ${anEur(ficha.investimento_eur)}${ficha.ritmo_pct != null ? ` · janela ${ficha.ritmo_pct}%` : ''}`} />}
            {window.ResKpi && <window.ResKpi label="Leads" value={anN(leads?.real)} sub={leads?.esperado != null ? `de ${anN(leads.esperado)} esperados` : 'sem esperado à data'} light={leads?.light} />}
            {window.ResKpi && <window.ResKpi label="MQL" value={anN(mql?.real)} sub={mql?.esperado != null ? `de ${anN(mql.esperado)} esperados` : 'sem esperado à data'} light={mql?.light} />}
            {window.ResKpi && <window.ResKpi label="CPL" value={ficha.cpl_eur != null ? anEur(ficha.cpl_eur) : '—'} sub={ficha.leads_n ? `${ficha.leads_n} no formulário Meta` : 'custo por lead'} />}
          </div>

          <div className="card" style={{ padding: 14, marginBottom: 16 }}>
            {anEtapasVisiveis(ficha).map(e => (
              <div key={e.key} style={{ display: 'grid', gridTemplateColumns: '140px 1fr 72px', gap: 8, alignItems: 'center', marginBottom: 8 }}>
                <div style={{ fontSize: 12 }}>{e.label}</div>
                <div>
                  <div style={{ fontSize: 12 }}>
                    {anN(e.real)}
                    {e.objectivo != null ? ` / ${anN(e.objectivo)}` : ' · sem objectivo'}
                    {e.esperado != null ? ` · esperado ${anN(e.esperado)}` : ''}
                  </div>
                  {window.resBar && window.resBar(e.objectivo ? Math.round((Number(e.real) || 0) / e.objectivo * 100) : 0, e.light)}
                </div>
                <div style={{ fontSize: 11, color: e.light ? (window.RES_LIGHT || {})[e.light] : 'var(--text-dim)' }}>{e.light || ''}</div>
              </div>
            ))}
            {!ficha.congelado && (
              <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 6 }}>Objectivos ainda não fechados na Aprovação.</div>
            )}
          </div>

          <div className="font-display" style={{ fontSize: 14, fontWeight: 650, marginBottom: 8 }}>Como está a correr</div>
          <p style={{ margin: '0 0 6px', fontSize: 15, lineHeight: 1.5, color: 'var(--text)' }}>{ficha.leitura}</p>
          <div style={{ fontSize: 11, color: 'var(--text-dim)', marginBottom: 18 }}>
            {aActualizar ? 'A actualizar a leitura…' : (ficha.criado_em ? `Leitura de ${anQuando(ficha.criado_em)}` : 'Números do portal, ainda sem leitura gravada.')}
          </div>

          <div className="font-display" style={{ fontSize: 14, fontWeight: 650, marginBottom: 8 }}>O que melhorar</div>
          {melhorias.map((m, i) => (
            <div key={i} className="card" style={{ padding: '14px 14px 12px', marginBottom: 8 }}>
              <div style={{ display: 'flex', gap: 6, alignItems: 'center', marginBottom: 6 }}>
                <span style={{ fontSize: 10, fontWeight: 700, fontFamily: 'var(--font-mono)', color: m.prioridade === 'p0' ? 'var(--danger)' : m.prioridade === 'p1' ? 'var(--warning)' : 'var(--text-muted)' }}>
                  {AN_PRIO[m.prioridade] || m.prioridade}
                </span>
                <span style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', color: 'var(--ai-500)', fontFamily: 'var(--font-mono)' }}>{AN_AREA[m.area] || m.area}</span>
              </div>
              <div style={{ fontSize: 15, fontWeight: 650, lineHeight: 1.35 }}>{m.o_que_mudar}</div>
              {m.porque && <div style={{ fontSize: 13, color: 'var(--text-muted)', marginTop: 4, lineHeight: 1.45 }}>{m.porque}</div>}
              {m.ligacao && AN_LIGACAO[m.ligacao] && (
                <button type="button" onClick={() => anLigar(hash.camp, m.ligacao)} style={{ marginTop: 8, border: 0, background: 'none', color: 'var(--ai-500)', fontWeight: 650, fontSize: 12, cursor: 'pointer', padding: 0 }}>
                  {AN_LIGACAO[m.ligacao]} →
                </button>
              )}
            </div>
          ))}
          {!melhorias.length && <div style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 12 }}>Sem correcções para esta campanha.</div>}
          <div style={{ marginTop: 8, fontSize: 11, color: 'var(--text-dim)' }}>Sugestão. Não altera a campanha na Meta.</div>

          {hist.length > 1 && (
            <details style={{ marginTop: 18 }}>
              <summary style={{ cursor: 'pointer', fontSize: 13, fontWeight: 650 }}>Leituras anteriores</summary>
              <div className="card" style={{ padding: '4px 14px', marginTop: 8 }}>
                {hist.map(h => (
                  <div key={h.id} style={{ borderTop: '1px solid var(--border)', padding: '8px 0' }}>
                    <div style={{ fontSize: 11, color: 'var(--text-dim)' }}>{anQuando(h.criado_em)}</div>
                    <div style={{ fontSize: 12, marginTop: 2, lineHeight: 1.35 }}>{h.leitura}</div>
                  </div>
                ))}
              </div>
            </details>
          )}
        </>
      )}
    </>
  );
};

const MktAnaliseCampanhasScreen = () => {
  const brandApi = window.useMktBrand ? window.useMktBrand() : { brand: 'todas', isAll: true, setBrand: () => {}, userMarcas: null };
  const { brand, isAll, setBrand, userMarcas } = brandApi;
  const bp = window.useBreakpoint ? window.useBreakpoint() : { isMobile: false };
  const isMobile = !!bp.isMobile;
  const [hash, setHash] = React.useState(anParseHash);
  const [lista, setLista] = React.useState(null);
  const [erro, setErro] = React.useState(null);
  window.useMktZoneLoading(!hash.camp && lista == null && !erro);

  React.useEffect(() => {
    const params = new URLSearchParams(String(window.location.hash || '').replace(/^#/, ''));
    if (params.get('sub') === 'analise-campanhas' && params.get('screen') === 'marketing') return;
    params.set('screen', 'marketing');
    params.set('sub', 'analise-campanhas');
    params.delete('analise');
    params.delete('correr');
    params.delete('registo');
    params.delete('camp');
    params.delete('canal');
    window.location.hash = params.toString();
  }, []);

  React.useEffect(() => {
    const onHash = () => setHash(anParseHash());
    window.addEventListener('hashchange', onHash);
    return () => {
      window.removeEventListener('hashchange', onHash);
      anClearOwnHash();
    };
  }, []);

  React.useEffect(() => {
    if (hash.camp) return undefined;
    let alive = true;
    anFetch('/api/marketing/activacao/analises-meta')
      .then(async (d) => {
        let camps = d.campanhas || [];
        if (alive) setLista(camps);
        if (!camps.some(c => !Array.isArray(c.melhorias))) return;
        const fichas = await Promise.all(camps.map(c =>
          anFetch(`/api/marketing/activacao/campanha/${encodeURIComponent(c.campanha_id)}/ficha`)
            .then(f => ({ id: c.campanha_id, melhorias: f.melhorias || [], leitura: f.leitura, criado_em: f.criado_em, cpl_eur: f.cpl_eur }))
            .catch(() => null)
        ));
        if (!alive) return;
        const porId = new Map(fichas.filter(Boolean).map(f => [f.id, f]));
        setLista(camps.map(c => {
          const f = porId.get(c.campanha_id);
          if (!f) return { ...c, melhorias: [] };
          return { ...c, melhorias: f.melhorias, leitura: f.leitura || c.leitura, criado_em: f.criado_em || c.criado_em, cpl_eur: f.cpl_eur ?? c.cpl_eur };
        }));
      })
      .catch(e => { if (alive) setErro(e.message); });
    return () => { alive = false; }
  }, [hash.camp]);

  const marcasNav = [{ id: 'todas', nome: 'Todas' }, ...((window.MKT_BRANDS || []).filter(b => b.id !== 'todas' && (!userMarcas?.length || userMarcas.includes(b.id))))];
  const headPad = isMobile ? '16px 16px 0' : '20px 40px 0';
  const bodyPad = isMobile ? '18px 16px 64px' : '28px 40px 64px';

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', overflow: 'hidden', background: 'var(--bg)' }}>
      <div style={{ background: 'var(--bg-elev)', borderBottom: '1px solid var(--border)', padding: headPad, flexShrink: 0 }}>
        <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.07em', color: 'var(--text-muted)', textTransform: 'uppercase', marginBottom: 6, fontFamily: 'var(--font-mono)' }}>
          MARKETING · ANÁLISE DE CAMPANHAS
        </div>
        <h1 style={{ margin: 0, fontSize: 21, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display)', letterSpacing: '-0.01em', lineHeight: 1.2 }}>
          Análise de campanhas
        </h1>
        <div style={{ height: 1, background: 'var(--border)', margin: isMobile ? '14px -16px 0' : '16px -40px 0' }} />
        <div style={{ display: 'flex', gap: 0, overflowX: 'auto' }}>
          {marcasNav.map(b => {
            const active = b.id === brand;
            return (
              <button key={b.id} type="button" onClick={() => setBrand && setBrand(b.id)}
                style={{
                  background: 'none', border: 'none', outline: 'none',
                  borderBottom: `2px solid ${active ? 'var(--ai-500)' : 'transparent'}`,
                  color: active ? 'var(--text)' : 'var(--text-muted)',
                  fontSize: 13, fontWeight: active ? 600 : 500,
                  fontFamily: 'var(--font-display)', letterSpacing: '.01em',
                  padding: '10px 18px 12px', cursor: 'pointer', whiteSpace: 'nowrap',
                  transition: 'color .15s, border-color .15s',
                }}>
                {b.nome}
              </button>
            );
          })}
        </div>
      </div>
      <div className="scrollbar" style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: bodyPad, background: 'var(--bg)' }}>
        {hash.camp
          ? <AnDetalhe hash={hash} onBack={() => anWriteHash({})} />
          : <AnPainel lista={lista} erro={erro} brand={brand} isAll={isAll} isMobile={isMobile} onAbrir={c => anWriteHash({ camp: c.campanha_id })} />}
      </div>
    </div>
  );
};

window.MktAnaliseCampanhasScreen = MktAnaliseCampanhasScreen;
