/* Marketing · Leads · Prospeção — pool de empresas/contactos (BD marketing), fontes Apollo, Apify e ficheiros. */

const PROSP_API = '/api/marketing/prospeccao';
const PROSP_ESTADOS = [
  { id: 'novo', label: 'Novo', cor: '#3859D0' },
  { id: 'validado', label: 'Validado', cor: '#0891b2' },
  { id: 'atribuido', label: 'Atribuído', cor: '#7c3aed' },
  { id: 'em_contacto', label: 'Em contacto', cor: '#d97706' },
  { id: 'qualificado', label: 'Qualificado', cor: '#15803d' },
  { id: 'convertido', label: 'Convertido', cor: '#15803d' },
  { id: 'descartado', label: 'Descartado', cor: '#6b7fa3' },
  { id: 'opt_out', label: 'Opt-out', cor: '#9f1239' },
  { id: 'ja_no_gestor', label: 'Já no Gestor', cor: '#15803d' },
];
const PROSP_FONTES = { apollo: 'Apollo', apify: 'Apify', pagina: 'Web Scrapping', import: 'Ficheiro', excel: 'Excel', validacao: 'Validação', manual: 'Manual' };

function prospEquipa(code) {
  return String(code || '').replace(/^MIMAKI\b/, 'Mimaki').replace(/^DECAL\b/, 'Decal');
}

function prospAtribuicoes(lista) {
  const by = new Map();
  for (const a of Array.isArray(lista) ? lista : []) {
    const eq = a.equipa || a.equipa_code;
    if (!eq) continue;
    if (!by.has(eq)) by.set(eq, []);
    const nome = a.comercial || '';
    if (nome && !by.get(eq).includes(nome)) by.get(eq).push(nome);
  }
  return [...by.entries()];
}

function prospQs(extra) {
  const p = new URLSearchParams();
  Object.entries(extra || {}).forEach(([k, v]) => { if (v !== undefined && v !== null && v !== '') p.set(k, v); });
  const email = window.currentUser?.email || '';
  if (email) p.set('email', email);
  return p.toString();
}

async function prospApi(path, { method = 'GET', body, form, query } = {}) {
  const opts = { method, headers: {} };
  if (form) opts.body = form;
  else if (body !== undefined) { opts.body = JSON.stringify(body); opts.headers['Content-Type'] = 'application/json'; }
  const r = await fetch(`${PROSP_API}${path}?${prospQs(query)}`, opts);
  const d = await r.json().catch(() => ({}));
  if (!r.ok || d.error) throw new Error(d.error || `HTTP ${r.status}`);
  return d;
}

const prospEstado = (id) => PROSP_ESTADOS.find(e => e.id === id) || { id, label: id || '—', cor: '#64748b' };
const prospData = (iso) => (iso ? new Date(iso).toLocaleString('pt-PT', { dateStyle: 'short', timeStyle: 'short' }) : '—');
const prospNum = (n) => Number(n || 0).toLocaleString('pt-PT');
function prospSemAsteriscos(v) {
  const s = String(v ?? '').trim();
  if (!s || !s.includes('*')) return s;
  return s.split(/\s+/).filter(parte => !parte.includes('*')).join(' ').trim();
}
function prospNomeDe(p) {
  if (!p) return '';
  const completo = prospSemAsteriscos(p.nome_completo);
  if (completo) return completo;
  return [prospSemAsteriscos(p.nome), prospSemAsteriscos(p.apelido)].filter(Boolean).join(' ');
}
const prospUsd = (n) => (n == null ? '—' : `$${Number(n).toFixed(2)}`);
function prospCreditos(n, eur) {
  const cred = `${n} ${Number(n) === 1 ? 'crédito' : 'créditos'}`;
  if (eur == null || eur === '') return cred;
  const valor = (Number(n) * Number(eur)).toLocaleString('pt-PT', { style: 'currency', currency: 'EUR' });
  return `${cred} (${valor})`;
}

function ProspFonteCel({ fonte, origem, href }) {
  const nome = PROSP_FONTES[fonte] || fonte;
  if (!nome && !origem) return <td style={prospTd}><span style={{ color: 'var(--text-dim)' }}>—</span></td>;
  return (
    <td style={prospTd}>
      {nome && <div style={{ fontWeight: 650 }}>{nome}</div>}
      {origem && (href
        ? <a href={href} target="_blank" rel="noreferrer" onClick={ev => ev.stopPropagation()} style={{ color: 'var(--ai-500)', textDecoration: 'none', overflowWrap: 'anywhere' }}>{origem}</a>
        : <div style={{ color: 'var(--text-muted)', overflowWrap: 'anywhere' }}>{origem}</div>)}
    </td>
  );
}

function ProspBadge({ estado }) {
  const e = prospEstado(estado);
  return <span style={{ fontSize: 11, fontWeight: 650, color: e.cor, whiteSpace: 'nowrap' }}>{e.label}</span>;
}

function ProspShell({ children }) {
  return (
    <div data-theme="light" style={{
      height: '100%', display: 'flex', flexDirection: 'column', overflow: 'hidden', background: '#f8fafc',
      '--bg': '#f8fafc', '--bg-elev': '#ffffff', '--bg-hover': '#f1f5f9', '--bg-sunken': '#e8edf5',
      '--border': '#dde3ef', '--text': '#112954', '--text-muted': '#4a5e7a', '--text-dim': '#6b7fa3', '--ai-500': '#3859D0',
    }}>
      <style>{'.prosp-row:hover{background:#f8fafc}.prosp-chip:hover{border-color:var(--ai-500)}.prosp-mapa .leaflet-tile-pane{filter:grayscale(1) sepia(.28) hue-rotate(188deg) saturate(.42) brightness(1.06) contrast(.9)}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ctdWave{0%,100%{transform:scaleY(0.25)}50%{transform:scaleY(1)}}'}</style>
      {children}
    </div>
  );
}

function ProspCard({ children, style }) {
  return <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: 16, ...style }}>{children}</div>;
}

function ProspKpis({ resumo, tab, admin, onIr }) {
  const c = resumo?.contactos || {};
  const items = [
    { id: 'base', label: 'Empresas', value: resumo?.total || 0, accent: '#3859D0' },
    { id: 'contactos', label: 'Contactos', value: c.total || 0, accent: '#7c3aed' },
    ...(admin ? [{ id: 'pesquisa', label: 'Pesquisar', value: resumo?.pesquisas || 0, accent: '#b45309' }] : []),
    { id: 'mercados', label: 'Mercados', value: resumo?.mercados || 0, accent: '#0891b2' },
    { id: 'carteira', label: 'Carteira', value: resumo?.sem_equipa?.empresas || 0, accent: '#0f766e' },
    { id: 'execucoes', label: 'Histórico', value: resumo?.execucoes || 0, accent: '#15803d' },
  ];
  const algum = items.some(k => k.id === tab);
  return (
    <div style={{ display: 'flex', gap: 12 }}>
      {items.map(k => {
        const on = tab === k.id;
        return (
          <div key={k.id} onClick={() => onIr(k.id)} style={{ flex: '1 1 0', background: '#fff', border: `1px solid ${on ? k.accent : 'var(--border)'}`, borderRadius: 8, padding: '12px 16px 0', cursor: 'pointer', display: 'flex', flexDirection: 'column', gap: 4, overflow: 'hidden', opacity: algum && !on ? 0.5 : 1 }}>
            <div style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: '0.10em', textTransform: 'uppercase', color: on ? k.accent : 'var(--text-muted)', fontFamily: 'var(--font-mono)' }}>{k.label}</div>
            <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'var(--font-display)', color: k.accent, lineHeight: 1, paddingBottom: 10 }}>{prospNum(k.value)}</div>
            <div style={{ height: 3, background: 'var(--bg-sunken)', overflow: 'hidden' }}><div style={{ height: '100%', width: '100%', background: k.accent }} /></div>
          </div>
        );
      })}
    </div>
  );
}

function ProspDrop({ label, value, onChange, options }) {
  if (typeof ResFiltro === 'function') return <ResFiltro label={label} value={value} onChange={onChange} options={options} />;
  if (typeof AudFilterDropdown === 'function') return <AudFilterDropdown label={label} value={value} onChange={onChange} options={options} />;
  return (
    <label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', background: '#fff', fontSize: 12 }}>
      <span style={{ color: 'var(--text-dim)', fontSize: 10, textTransform: 'uppercase', letterSpacing: '.06em' }}>{label}</span>
      <select value={value} onChange={e => onChange(e.target.value)} style={{ border: 'none', background: 'transparent', color: 'var(--text)', fontSize: 12 }}>
        {options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
      </select>
    </label>
  );
}

function ProspField({ label, hint, children }) {
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 6, fontSize: 12, color: 'var(--text)', minWidth: 0 }}>
      <span style={{ fontWeight: 650 }}>{label}</span>
      {children}
      {hint && <span style={{ fontSize: 12, lineHeight: 1.4, color: 'var(--text-dim)' }}>{hint}</span>}
    </label>
  );
}

function ProspSecao({ titulo, children, separador }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12, ...(separador ? { borderTop: '1px solid var(--border)', paddingTop: 16 } : {}) }}>
      {titulo && <div style={{ fontSize: 11, fontWeight: 650, letterSpacing: '.06em', textTransform: 'uppercase', color: 'var(--text-dim)' }}>{titulo}</div>}
      {children}
    </div>
  );
}

function ProspAviso({ children }) {
  return <div style={{ fontSize: 12, lineHeight: 1.45, color: 'var(--text-muted)', background: '#f4f7fb', borderRadius: 8, padding: '10px 12px' }}>{children}</div>;
}

function ProspBotao({ disabled, onClick, children }) {
  return <button type="button" className="btn btn-ai" disabled={disabled} onClick={onClick} style={{ width: '100%', justifyContent: 'center' }}>{children}</button>;
}

function ProspGrelha({ children }) {
  return <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>{children}</div>;
}

function ProspChip({ on, label, title, onClick }) {
  return (
    <button type="button" title={title || ''} onClick={onClick} className="prosp-chip" style={{
      padding: '8px 10px', borderRadius: 8, cursor: 'pointer', fontFamily: 'inherit',
      border: `1px solid ${on ? 'var(--ai-500)' : 'var(--border)'}`,
      background: on ? 'color-mix(in oklch, var(--ai-500, #3859D0) 12%, #fff)' : '#fff',
      color: on ? 'var(--ai-500)' : 'var(--text)',
      fontSize: 12.5, fontWeight: 650, lineHeight: 1.25, textAlign: 'center',
      transition: 'background .12s, border-color .12s, color .12s',
    }}>{label}</button>
  );
}

const prospInput = { border: '1px solid var(--border)', borderRadius: 8, padding: '9px 11px', fontSize: 13, background: '#fff', color: 'var(--text)', minWidth: 0, width: '100%', fontFamily: 'inherit', boxSizing: 'border-box' };
const prospTh = { textAlign: 'left', fontSize: 10, fontWeight: 600, color: 'var(--text-dim)', textTransform: 'uppercase', letterSpacing: '.04em', padding: '8px 10px', borderBottom: '1px solid var(--border)', whiteSpace: 'nowrap', background: 'none' };
const prospTd = { fontSize: 12, padding: '10px', borderBottom: '1px solid var(--border)', verticalAlign: 'top', whiteSpace: 'normal', overflowWrap: 'anywhere' };

function ProspMsg({ msg }) {
  if (!msg) return null;
  const erro = msg.tipo === 'erro';
  return <div style={{ fontSize: 13, padding: '8px 12px', borderRadius: 8, background: erro ? '#fef2f2' : '#f0fdf4', border: `1px solid ${erro ? '#fecaca' : '#bbf7d0'}`, color: erro ? '#991b1b' : '#166534' }}>{msg.texto}</div>;
}

// ── Base ──────────────────────────────────────────────────────────────────────

function prospContactos(r) {
  const n = Number(r.n_contactos) || 0;
  if (!n) return 'Sem contactos';
  return `${n} ${n === 1 ? 'contacto' : 'contactos'}`;
}

function prospTxt(v) {
  return prospSemAsteriscos(v) || '—';
}

function prospEquipaLista(lista) {
  const nomes = prospAtribuicoes(lista).map(([eq]) => prospEquipa(eq));
  return nomes.length ? nomes.join(', ') : '';
}

function prospComercialLista(lista) {
  const nomes = [];
  for (const [, pessoas] of prospAtribuicoes(lista)) nomes.push(...pessoas);
  return [...new Set(nomes)].join(', ');
}

const PROSP_COLS_EMP = [
  ['Empresa', 220], ['NIF', 130], ['Website', 190], ['Resumo do site', 420], ['Telefone', 150], ['Morada', 280],
  ['Código postal', 120], ['Cidade', 150], ['Zona', 180], ['País', 64],
  ['Equipa', 170], ['Comercial', 180], ['Contactos', 110], ['Marca', 110], ['Sector', 160], ['Segmento', 220],
  ['Estado', 120], ['Fonte', 280],
];
const PROSP_COLS_CONT = [
  ['Nome', 200], ['Cargo', 200], ['Papel', 140], ['Email', 230], ['Telefone', 160], ['LinkedIn', 96],
  ['Empresa', 220], ['Segmento', 220], ['Estado', 120], ['Morada', 280], ['Código postal', 120], ['Cidade', 150], ['Zona', 180],
  ['País', 64], ['Equipa', 170], ['Comercial', 180], ['Marca', 110], ['Fonte', 280],
];

function prospSegmento(r) {
  return [r?.segmento, r?.segmento_tipo].filter(Boolean).join(' · ');
}
function prospPapel(r) {
  if (r?.papel === 'decisor') return 'Decisor';
  if (r?.papel === 'influenciador') return 'Influenciador';
  return '';
}
function ProspPerfilCel({ row, td }) {
  const p = row?.perfil_site || {};
  const resumo = typeof p.resumo === 'string' ? p.resumo.trim() : '';
  const trabalhos = Array.isArray(p.trabalhos) ? p.trabalhos.filter(Boolean) : [];
  const equipamentos = Array.isArray(p.equipamentos) ? p.equipamentos.filter(Boolean) : [];
  if (!resumo && !trabalhos.length && !equipamentos.length) {
    return <td style={{ ...td, color: 'var(--text-dim)' }}>—</td>;
  }
  return (
    <td style={{ ...td, color: p.estado === 'sem_leitura' ? 'var(--text-muted)' : 'var(--text)' }}>
      {resumo && <div>{resumo}</div>}
      {!!trabalhos.length && <div style={{ marginTop: resumo ? 4 : 0, fontSize: 11, color: 'var(--text-muted)' }}>{trabalhos.join(', ')}</div>}
      {!!equipamentos.length && <div style={{ marginTop: 2, fontSize: 11, color: 'var(--text-muted)' }}>Equipamentos: {equipamentos.join(', ')}</div>}
    </td>
  );
}
function ProspSegmentoCel({ row, td }) {
  const texto = prospSegmento(row);
  return (
    <td style={{ ...td, color: texto ? 'var(--text)' : 'var(--text-dim)' }}>
      <div>{texto || '—'}</div>
      {texto && row.segmento_fonte === 'crm' && <div style={{ marginTop: 2, fontSize: 11, color: 'var(--text-muted)' }}>Gestor</div>}
      {texto && row.segmento_fonte === 'import' && <div style={{ marginTop: 2, fontSize: 11, color: 'var(--text-muted)' }}>Ficheiro</div>}
      {texto && row.segmento_fonte === 'manual' && <div style={{ marginTop: 2, fontSize: 11, color: 'var(--text-muted)' }}>Manual</div>}
      {texto && row.segmento_fonte === 'pesquisa' && <div style={{ marginTop: 2, fontSize: 11, color: 'var(--text-muted)' }}>Pesquisa{row.segmento_confianca != null ? ` · ${row.segmento_confianca}%` : ''}</div>}
      {texto && row.segmento_fonte === 'inferido' && row.segmento_confianca != null && <div style={{ marginTop: 2, fontSize: 11, fontWeight: 700, color: '#3730a3' }}>Confiança {row.segmento_confianca}%</div>}
    </td>
  );
}
function ProspPapelCel({ row, td }) {
  const texto = prospPapel(row);
  return (
    <td style={{ ...td, color: texto ? 'var(--text)' : 'var(--text-dim)' }}>
      <div style={{ fontWeight: texto ? 650 : 400 }}>{texto || '—'}</div>
      {row.cargo_crm && <div style={{ marginTop: 2, fontSize: 11, color: 'var(--text-muted)' }}>{row.cargo_crm}</div>}
    </td>
  );
}

function ProspEnriquecerCurso({ nota, feitos, total, titulo }) {
  const pct = total > 0 ? Math.min(100, Math.round((Number(feitos) || 0) / Number(total) * 100)) : 8;
  return (
    <div style={{ padding: '8px 0 4px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16, width: '100%' }}>
      <ProspOnda />
      <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.10em', color: 'var(--ai-500, #3859D0)', fontFamily: 'var(--font-mono, monospace)', textAlign: 'center' }}>{titulo}</div>
      <div style={{ width: '100%', padding: 16, background: 'linear-gradient(135deg, #eef2ff 0%, #f5f3ff 100%)', border: '1px solid #c7d2fe', borderRadius: 8, boxSizing: 'border-box' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10, gap: 12 }}>
          <div style={{ fontSize: 13, color: '#3730a3', fontWeight: 600, lineHeight: 1.4 }}>{nota || 'A processar…'}</div>
          <div style={{ fontSize: 12, color: '#6366f1', fontFamily: 'var(--font-mono, monospace)', fontWeight: 700, flexShrink: 0 }}>{pct}%</div>
        </div>
        <div style={{ height: 6, background: '#e0e7ff', borderRadius: 3, overflow: 'hidden' }}>
          <div style={{ width: `${pct}%`, height: '100%', background: 'linear-gradient(90deg, #6366f1, #8b5cf6)', transition: 'width 0.3s ease' }} />
        </div>
      </div>
      <div style={{ fontSize: 12, color: 'var(--text-muted)', textAlign: 'center' }}>A execução continua se fechares a janela. O resultado fica gravado na base de prospeção, com a confiança de cada contacto.</div>
    </div>
  );
}

function ProspEnriquecer({ ids, onClose, onFeito }) {
  const [dados, setDados] = React.useState(null);
  const [erro, setErro] = React.useState('');
  const [busy, setBusy] = React.useState('preparar');
  const [escolhidos, setEscolhidos] = React.useState({});
  const [runId, setRunId] = React.useState(null);
  const [curso, setCurso] = React.useState(null);
  const [resultado, setResultado] = React.useState(null);
  const vivo = React.useRef(false);
  const lista = dados?.contactos || [];
  const doGrupo = (g) => lista.filter(c => c.grupo === g);
  const emailsProntos = lista.filter(c => c.grupo === 'pronto' && c.falta_email);
  const telemoveis = lista.filter(c => c.pode_telemovel);
  const aCorrer = curso?.estado === 'a_correr';
  const tituloCurso = {
    analisar: 'A ANALISAR',
    emails: 'A REVELAR EMAILS',
    telemoveis: 'A PEDIR TELEMÓVEIS',
    enriquecer_analise: 'A ANALISAR',
    enriquecer_email: 'A REVELAR EMAILS',
    enriquecer_telemovel: 'A PEDIR TELEMÓVEIS',
  }[curso?.parametros?.tipo] || 'A ENRIQUECER';

  const aplicar = (d) => { setDados(d); setEscolhidos({}); };

  React.useEffect(() => {
    let stop = false;
    setBusy('preparar'); setErro('');
    prospApi('/contactos/enriquecer/preparar', { method: 'POST', body: { contacto_ids: ids } })
      .then(d => { if (!stop) aplicar(d); })
      .catch(e => { if (!stop) setErro(e.message); })
      .finally(() => { if (!stop) setBusy(''); });
    return () => { stop = true; };
  }, [ids]);

  React.useEffect(() => {
    if (!runId) return undefined;
    let stop = false;
    let timer;
    let falhas = 0;
    const ler = async () => {
      try {
        const d = await prospApi(`/runs/${runId}`);
        if (stop || !d.run) return;
        falhas = 0;
        if (d.run.estado === 'a_correr') {
          setCurso(d.run);
          timer = setTimeout(ler, 2000);
          return;
        }
        setCurso(d.run);
        setBusy('');
        vivo.current = false;
        if (d.run.estado === 'erro') {
          setErro(d.run.notas || 'O enriquecimento falhou.');
          return;
        }
        const res = d.run.parametros?.resultado || { notas: d.run.notas, linhas: [], media: null, gravados: d.run.n_contactos };
        setResultado(res);
        if (res.tipo === 'analise' && Array.isArray(res.contactos)) {
          setDados(prev => ({ ...(prev || {}), contactos: res.contactos, resumo: res.resumo || prev?.resumo }));
          setEscolhidos({});
        } else if (Array.isArray(res.linhas)) {
          setDados(prev => ({
            ...(prev || {}),
            contactos: (prev?.contactos || []).map(c => {
              const linha = res.linhas.find(l => Number(l.id) === Number(c.id));
              if (!linha || (!linha.gravado && linha.confianca == null && !linha.apollo_id)) return c;
              const apollo = linha.apollo_id || c.apollo_id;
              return {
                ...c,
                confianca: linha.confianca ?? c.confianca,
                apollo_id: apollo || c.apollo_id,
                falta_email: linha.gravado ? false : c.falta_email,
                grupo: (linha.gravado || linha.apollo_id) ? 'pronto' : c.grupo,
                pode_telemovel: linha.gravado && c.falta_telemovel && apollo ? true : c.pode_telemovel,
              };
            }),
          }));
          setEscolhidos(prev => {
            const n = { ...prev };
            for (const l of res.linhas) if (l.gravado) delete n[l.id];
            return n;
          });
        }
        onFeito?.();
      } catch (e) {
        if (stop) return;
        falhas += 1;
        if (falhas >= 4) {
          setErro(e.message);
          setBusy('');
          vivo.current = false;
          setCurso(c => (c ? { ...c, estado: 'erro', notas: e.message } : c));
          return;
        }
        timer = setTimeout(ler, 2000);
      }
    };
    ler();
    return () => { stop = true; clearTimeout(timer); };
  }, [runId]);

  const lancar = async (tipo, path, body) => {
    if (vivo.current) return;
    vivo.current = true;
    setBusy(tipo); setErro(''); setResultado(null);
    setCurso({ estado: 'a_correr', notas: 'A preparar…', parametros: { tipo, progresso: { feitos: 0, total: 1 } } });
    try {
      const d = await prospApi(path, { method: 'POST', body });
      if (!d.run_id) {
        vivo.current = false;
        setCurso(null);
        setBusy('');
        if (d.resultado) setResultado(d.resultado);
        return;
      }
      setRunId(d.run_id);
      setCurso({ id: d.run_id, estado: 'a_correr', notas: 'A preparar…', parametros: { tipo, progresso: { feitos: 0, total: 1 } } });
    } catch (e) {
      vivo.current = false;
      setCurso(null);
      setErro(e.message);
      setBusy('');
    }
  };
  const analisar = () => lancar('analisar', '/contactos/enriquecer/analisar', { contacto_ids: ids });
  const revelar = () => {
    const revers = doGrupo('rever').filter(c => escolhidos[c.id]);
    const itens = [
      ...emailsProntos.map(c => ({ id: c.id, apollo_id: c.candidatos?.[0]?.apollo_id || c.apollo_id || null, confirmar_apelido: !!c.confirmar_apelido })),
      ...revers.map(c => ({ id: c.id, apollo_id: escolhidos[c.id] === 'confirmar' ? null : escolhidos[c.id], confirmar_apelido: !!c.confirmar_apelido })),
    ];
    if (!itens.length) return;
    lancar('emails', '/contactos/enriquecer/emails', { itens });
  };
  const pedirTelemoveis = () => {
    if (!telemoveis.length) return;
    lancar('telemoveis', '/contactos/enriquecer/telemoveis', { contacto_ids: telemoveis.map(c => c.id) });
  };

  const linha = (c, extra) => (
    <div key={c.id} style={{ display: 'flex', gap: 8, alignItems: 'flex-start', fontSize: 13, padding: '8px 0', borderBottom: '1px solid var(--border)' }}>
      {extra}
      <div style={{ minWidth: 0 }}>
        <div style={{ fontWeight: 650 }}>{c.nome || 'Sem nome'}{c.empresa ? ` · ${c.empresa}` : ''}{c.confianca != null && <span style={{ marginLeft: 8, fontSize: 12, fontWeight: 700, color: '#3730a3', fontFamily: 'var(--font-mono, monospace)' }}>{c.confianca}%</span>}</div>
        <div style={{ color: 'var(--text-muted)', fontSize: 12, lineHeight: 1.4 }}>
          {c.motivo}
          {c.telemovel_empresa ? ' O número actual é o da empresa.' : ''}
          {c.falta_email ? ' Sem email verified.' : ''}
          {c.falta_telemovel ? ' Sem telemóvel directo.' : ''}
          {prospPapel(c) ? ` ${prospPapel(c)}.` : ''}
          {c.cargo_crm ? ` Cargo no Gestor: ${c.cargo_crm}.` : ''}
          {prospSegmento(c) ? ` Segmento ${prospSegmento(c)}.` : ''}
        </div>
        {c.candidatos?.length > 1 && (
          <select style={{ ...prospInput, marginTop: 6, width: 'auto' }} value={escolhidos[c.id] && escolhidos[c.id] !== 'confirmar' ? escolhidos[c.id] : ''} onChange={ev => setEscolhidos(p => ({ ...p, [c.id]: ev.target.value }))}>
            <option value="">Escolher pessoa</option>
            {c.candidatos.map(p => <option key={p.apollo_id} value={p.apollo_id}>{[p.nome, p.cargo, p.empresa].filter(Boolean).join(' · ')}{p.confianca != null ? ` · ${p.confianca}%` : ''}</option>)}
          </select>
        )}
      </div>
    </div>
  );

  const nEmails = emailsProntos.length + doGrupo('rever').filter(c => escolhidos[c.id]).length;
  const caixa = (titulo, itens, render) => !itens.length ? null : (
    <div>
      <div style={{ fontWeight: 650, fontSize: 13 }}>{titulo} · {itens.length}</div>
      <div style={{ maxHeight: 200, overflow: 'auto' }}>{itens.map(render)}</div>
    </div>
  );

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 9999, background: 'rgba(15,23,42,.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }} onClick={() => { if (!aCorrer) onClose(); }}>
      <div style={{ width: 'min(740px, 100%)', maxHeight: 'min(88vh, 860px)', overflow: 'auto', background: '#fff', borderRadius: 12, padding: 20, display: 'flex', flexDirection: 'column', gap: 14, boxShadow: '0 16px 50px rgba(0,0,0,.18)' }} onClick={ev => ev.stopPropagation()}>
        <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, alignItems: 'flex-start' }}>
          <div>
            <div style={{ fontWeight: 700, fontSize: 16 }}>Enriquecer contactos</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginTop: 4 }}>O Apollo só corre depois de confirmares. O email fica gravado se vier verified e a pessoa coincidir em dois campos: nome, empresa ou LinkedIn.</div>
          </div>
          <button type="button" className="btn btn-sm btn-ghost" onClick={onClose}>Fechar</button>
        </div>
        {dados?.cortados > 0 && <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>Esta volta usa {dados.max} contactos. Os outros {dados.cortados} continuam seleccionados para a volta seguinte.</div>}
        {erro && <ProspMsg msg={{ tipo: 'erro', texto: erro }} />}
        {busy === 'preparar' && !dados && <ProspEnriquecerCurso titulo="A PREPARAR" nota="A ler a selecção…" feitos={0} total={0} />}
        {aCorrer && <ProspEnriquecerCurso titulo={tituloCurso} nota={curso?.notas} feitos={curso?.parametros?.progresso?.feitos} total={curso?.parametros?.progresso?.total} />}
        {resultado && !aCorrer && (
          <div style={{ padding: 14, background: resultado.gravados ? '#f0fdf4' : '#f8fafc', border: `1px solid ${resultado.gravados ? '#bbf7d0' : 'var(--border)'}`, borderRadius: 8 }}>
            <div style={{ fontWeight: 700, fontSize: 14 }}>{resultado.notas}</div>
            {resultado.media != null && <div style={{ marginTop: 6, fontSize: 13 }}>Confiança média do enriquecimento: <strong>{resultado.media}%</strong></div>}
            <div style={{ marginTop: 4, fontSize: 12, color: 'var(--text-muted)' }}>A confiança junta o LinkedIn da pessoa, o nome, o domínio ou a empresa, e sobe quando o email verified fica gravado.</div>
            {!!resultado.linhas?.length && (
              <div style={{ maxHeight: 220, overflow: 'auto', marginTop: 8 }}>
                {resultado.linhas.map(l => (
                  <div key={l.id} style={{ display: 'flex', justifyContent: 'space-between', gap: 12, fontSize: 12, padding: '6px 0', borderBottom: '1px solid var(--border)' }}>
                    <span style={{ minWidth: 0 }}>{l.nome || 'Sem nome'}{l.empresa ? ` · ${l.empresa}` : ''}{l.motivo ? <span style={{ color: 'var(--text-muted)' }}>{` · ${l.motivo}`}</span> : ''}</span>
                    <span style={{ fontWeight: 700, color: l.confianca != null ? '#3730a3' : 'var(--text-dim)', fontFamily: 'var(--font-mono, monospace)', flexShrink: 0 }}>{l.confianca != null ? `${l.confianca}%` : '—'}</span>
                  </div>
                ))}
              </div>
            )}
          </div>
        )}
        {!aCorrer && caixa('Prontos', doGrupo('pronto'), c => linha(c))}
        {!aCorrer && caixa('A rever', doGrupo('rever'), c => linha(c, (c.pode_confirmar || c.candidatos?.length) ? (
          <input type="checkbox" style={{ marginTop: 3 }} checked={!!escolhidos[c.id]} onChange={() => setEscolhidos(p => {
            if (p[c.id]) { const n = { ...p }; delete n[c.id]; return n; }
            return { ...p, [c.id]: c.candidatos?.[0]?.apollo_id || 'confirmar' };
          })} />
        ) : <span style={{ width: 16 }} />))}
        {!aCorrer && caixa('Ignorados', doGrupo('ignorado'), c => linha(c))}
        {!aCorrer && caixa('Por analisar', doGrupo('analisar'), c => linha(c))}
        {!aCorrer && (
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            {doGrupo('analisar').length > 0 && <button type="button" className="btn btn-sm" disabled={!!busy} onClick={analisar}>Analisar correspondência · 0 créditos</button>}
            <button type="button" className="btn btn-sm btn-ai" disabled={!!busy || !nEmails} onClick={revelar}>{`Revelar emails · até ${prospCreditos(nEmails)}`}</button>
            <button type="button" className="btn btn-sm" disabled={!!busy || !telemoveis.length} onClick={pedirTelemoveis}>{`Pedir telemóveis · até ${prospCreditos(telemoveis.length * 8)}`}</button>
          </div>
        )}
      </div>
    </div>
  );
}

function ProspListas({ inicio, onChanged }) {
  const [rows, setRows] = React.useState([]);
  const [aberta, setAberta] = React.useState(null);
  const [nome, setNome] = React.useState('');
  const [novoNome, setNovoNome] = React.useState('');
  const [empresas, setEmpresas] = React.useState([]);
  const [contactos, setContactos] = React.useState([]);
  const [selE, setSelE] = React.useState(new Set());
  const [selC, setSelC] = React.useState(new Set());
  const [vista, setVista] = React.useState(inicio?.pessoas ? 'contactos' : 'empresas');
  const [erro, setErro] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [enriquecerIds, setEnriquecerIds] = React.useState(null);
  const [procura, setProcura] = React.useState('');
  const [achados, setAchados] = React.useState(null);
  const [totalAchados, setTotalAchados] = React.useState(0);
  const [selAchados, setSelAchados] = React.useState(new Set());
  const pessoas = !!inicio?.pessoas;
  const ids = inicio?.ids || [];
  const aAdicionar = inicio?.modo === 'adicionar' && ids.length > 0;

  const recarregar = async () => {
    const d = await prospApi('/listas-enrichment');
    setRows(d.rows || []);
    return d.rows || [];
  };
  const abrir = async (row) => {
    if (!row?.id) return;
    if (aberta?.id !== row.id) {
      setProcura('');
      setAchados(null);
      setTotalAchados(0);
      setSelAchados(new Set());
    }
    setAberta(row);
    setNome(row.nome || '');
    setSelE(new Set());
    setSelC(new Set());
    const [em, co] = await Promise.all([
      prospApi('/empresas', { query: { lista_id: row.id, limit: 5000, ordem: 'nome' } }),
      prospApi('/contactos', { query: { lista_id: row.id, limit: 5000, ordem: 'nome' } }),
    ]);
    setEmpresas(em.rows || []);
    setContactos(co.rows || []);
    const lista = await recarregar();
    const fresco = lista.find(r => r.id === row.id);
    if (fresco) setAberta(fresco);
  };
  React.useEffect(() => { recarregar().catch(e => setErro(e.message)); }, []);

  const correr = async (fn) => {
    setBusy(true); setErro('');
    try { return await fn(); }
    catch (e) { setErro(e.message); return null; }
    finally { setBusy(false); }
  };
  const criarOuJuntar = (listaId) => correr(async () => {
    const body = pessoas ? { contacto_ids: ids } : { empresa_ids: ids };
    const d = listaId
      ? await prospApi(`/listas-enrichment/${listaId}/membros`, { method: 'POST', body })
      : await prospApi('/listas-enrichment', { method: 'POST', body: { nome: novoNome, ...body } });
    setNovoNome('');
    await abrir(d.row);
    onChanged?.();
  });
  const guardarNome = () => correr(async () => {
    const d = await prospApi(`/listas-enrichment/${aberta.id}`, { method: 'PATCH', body: { nome } });
    setAberta(d.row);
    await recarregar();
  });
  const apagar = () => {
    if (!window.confirm(`Apagar a lista “${aberta.nome}”? As empresas e os contactos ficam na base.`)) return;
    return correr(async () => {
      await prospApi(`/listas-enrichment/${aberta.id}`, { method: 'DELETE' });
      setAberta(null); setEmpresas([]); setContactos([]);
      await recarregar();
      onChanged?.();
    });
  };
  const retirar = () => correr(async () => {
    const d = await prospApi(`/listas-enrichment/${aberta.id}/retirar`, { method: 'POST', body: { empresa_ids: [...selE], contacto_ids: [...selC] } });
    await abrir(d.row);
  });
  const trazer = () => correr(async () => {
    const d = await prospApi(`/listas-enrichment/${aberta.id}/contactos-das-empresas`, { method: 'POST' });
    setVista('contactos');
    await abrir(d.row);
  });
  const procurarContactos = () => correr(async () => {
    const todas = !selE.size || selE.size === empresas.length;
    const d = await prospApi(`/listas-enrichment/${aberta.id}/contactos`, {
      method: 'POST',
      body: { q: procura.trim(), empresa_ids: todas ? [] : [...selE] },
    });
    setAchados(d.rows || []);
    setTotalAchados(d.total || (d.rows || []).length);
    setSelAchados(new Set());
  });
  const juntarAchados = () => correr(async () => {
    const d = await prospApi(`/listas-enrichment/${aberta.id}/membros`, { method: 'POST', body: { contacto_ids: [...selAchados] } });
    setVista('contactos');
    await abrir(d.row);
  });
  const naLista = new Set(contactos.map(c => c.id));
  const toggleAchado = (id) => setSelAchados(prev => { const n = new Set(prev); if (n.has(id)) n.delete(id); else n.add(id); return n; });
  const porAdicionar = (achados || []).filter(r => !naLista.has(r.id));
  const todasAchados = porAdicionar.length > 0 && porAdicionar.every(r => selAchados.has(r.id));
  const linhas = vista === 'contactos' ? contactos : empresas;
  const todasLinhas = linhas.length > 0 && linhas.every(r => (vista === 'contactos' ? selC : selE).has(r.id));
  const sel = vista === 'contactos' ? selC : selE;
  const setSel = vista === 'contactos' ? setSelC : setSelE;
  const toggle = (id) => setSel(prev => { const n = new Set(prev); if (n.has(id)) n.delete(id); else n.add(id); return n; });

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {erro && <ProspMsg msg={{ tipo: 'erro', texto: erro }} />}
        {aAdicionar && (
          <div style={{ fontSize: 13, color: 'var(--text)', background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: '12px 14px' }}>
            <strong>{ids.length} {pessoas ? (ids.length === 1 ? 'contacto seleccionado' : 'contactos seleccionados') : (ids.length === 1 ? 'empresa seleccionada' : 'empresas seleccionadas')}.</strong> Cria uma lista ou abre uma existente para os acrescentar.
          </div>
        )}
        {!aberta && (
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
            <input style={{ ...prospInput, flex: '1 1 240px', maxWidth: 420 }} value={novoNome} placeholder="Nome da nova lista" onChange={ev => setNovoNome(ev.target.value)} />
            <button type="button" className="btn btn-sm btn-ai" disabled={busy || !novoNome.trim()} onClick={() => criarOuJuntar(null)}>{aAdicionar ? 'Criar e adicionar' : 'Criar lista'}</button>
          </div>
        )}
        {!aberta && (
          <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, overflow: 'auto' }}>
            <table style={{ width: '100%', borderCollapse: 'collapse' }}>
              <thead>
                <tr>
                  <th style={prospTh}>Lista</th>
                  <th style={prospTh}>Empresas</th>
                  <th style={prospTh}>Contactos</th>
                </tr>
              </thead>
              <tbody>
                {rows.map(r => (
                  <tr key={r.id} onClick={() => (aAdicionar ? criarOuJuntar(r.id) : abrir(r))} style={{ cursor: 'pointer' }}>
                    <td style={{ ...prospTd, fontWeight: 650 }}>{r.nome}</td>
                    <td style={prospTd}>{prospNum(r.n_empresas)}</td>
                    <td style={prospTd}>{prospNum(r.n_contactos)}</td>
                  </tr>
                ))}
                {!rows.length && <tr><td colSpan={3} style={{ ...prospTd, textAlign: 'center', color: 'var(--text-muted)', padding: 28 }}>Ainda não há listas. Dá um nome e cria a primeira.</td></tr>}
              </tbody>
            </table>
          </div>
        )}
        {aberta && (
          <button type="button" className="btn btn-sm" onClick={() => setAberta(null)}>{aAdicionar ? 'Adicionar esta selecção a outra lista' : 'Todas as listas'}</button>
        )}
        {aberta && (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10, borderTop: '1px solid var(--border)', paddingTop: 12 }}>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
              <input style={{ ...prospInput, flex: '1 1 220px' }} value={nome} onChange={ev => setNome(ev.target.value)} />
              <button type="button" className="btn btn-sm btn-ai" disabled={busy || !nome.trim()} onClick={guardarNome}>Guardar nome</button>
              <button type="button" className="btn btn-sm" disabled={busy} onClick={apagar}>Apagar lista</button>
            </div>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              <button type="button" className="btn btn-sm" onClick={() => setVista('empresas')}>Empresas · {empresas.length}</button>
              <button type="button" className="btn btn-sm" onClick={() => setVista('contactos')}>Contactos · {contactos.length}</button>
              <button type="button" className="btn btn-sm" disabled={busy || !(selE.size || selC.size)} onClick={retirar}>Tirar da lista</button>
              <button type="button" className="btn btn-sm" disabled={busy || !empresas.length} onClick={trazer}>Trazer contactos das empresas</button>
              <button type="button" className="btn btn-sm btn-ai" disabled={!contactos.length} onClick={() => setEnriquecerIds(contactos.map(c => c.id))}>Enriquecer contactos</button>
            </div>
            {!!empresas.length && (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
                  <input style={{ ...prospInput, flex: '1 1 240px', maxWidth: 420 }} value={procura} placeholder="Nome do contacto, cargo, email ou empresa" onChange={ev => setProcura(ev.target.value)} onKeyDown={ev => { if (ev.key === 'Enter') procurarContactos(); }} />
                  <button type="button" className="btn btn-sm btn-ai" disabled={busy} onClick={procurarContactos}>{selE.size && selE.size < empresas.length ? `Procurar contactos das ${selE.size} empresas` : 'Procurar contactos das empresas'}</button>
                </div>
                {achados && (
                  <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 8, overflow: 'auto' }}>
                    <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap', padding: '10px 12px', borderBottom: '1px solid var(--border)' }}>
                      <span style={{ fontSize: 13 }}>{achados.length ? `${prospNum(achados.length)}${totalAchados > achados.length ? ` de ${prospNum(totalAchados)}` : ''} ${achados.length === 1 ? 'contacto' : 'contactos'}` : 'Estas empresas ainda não têm contactos na base.'}</span>
                      <button type="button" className="btn btn-sm btn-ai" disabled={busy || !selAchados.size} onClick={juntarAchados}>Adicionar à lista</button>
                    </div>
                    {!!achados.length && (
                      <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                        <thead>
                          <tr>
                            <th style={prospTh}><input type="checkbox" checked={todasAchados} disabled={!porAdicionar.length} onChange={() => setSelAchados(todasAchados ? new Set() : new Set(porAdicionar.map(r => r.id)))} /></th>
                            <th style={prospTh}>Empresa</th>
                            <th style={prospTh}>Contacto</th>
                            <th style={prospTh}>Cargo</th>
                            <th style={prospTh}>Email</th>
                          </tr>
                        </thead>
                        <tbody>
                          {achados.map(r => (
                            <tr key={r.id}>
                              <td style={prospTd}>{naLista.has(r.id) ? <span style={{ fontSize: 11, color: 'var(--text-dim)' }}>Na lista</span> : <input type="checkbox" checked={selAchados.has(r.id)} onChange={() => toggleAchado(r.id)} />}</td>
                              <td style={{ ...prospTd, fontWeight: 650 }}>{r.empresa_nome || '—'}</td>
                              <td style={prospTd}>{prospNomeDe(r) || '—'}</td>
                              <td style={prospTd}>{r.cargo || '—'}</td>
                              <td style={prospTd}>{prospTxt(r.email)}</td>
                            </tr>
                          ))}
                        </tbody>
                      </table>
                    )}
                  </div>
                )}
              </div>
            )}
            <div style={{ overflow: 'auto', border: '1px solid var(--border)', borderRadius: 8, background: '#fff' }}>
              <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                <thead>
                  <tr>
                    <th style={prospTh}><input type="checkbox" checked={todasLinhas} disabled={!linhas.length} onChange={() => setSel(todasLinhas ? new Set() : new Set(linhas.map(r => r.id)))} /></th>
                    <th style={prospTh}>{vista === 'contactos' ? 'Contacto' : 'Empresa'}</th>
                    <th style={prospTh}>{vista === 'contactos' ? 'Empresa' : 'Website'}</th>
                    <th style={prospTh}>Segmento</th>
                    {vista === 'contactos' && <th style={prospTh}>Email</th>}
                  </tr>
                </thead>
                <tbody>
                  {linhas.map(r => (
                    <tr key={r.id}>
                      <td style={prospTd}><input type="checkbox" checked={sel.has(r.id)} onChange={() => toggle(r.id)} /></td>
                      <td style={{ ...prospTd, fontWeight: 650 }}>{vista === 'contactos' ? (prospNomeDe(r) || '—') : (prospSemAsteriscos(r.nome) || '—')}</td>
                      <td style={prospTd}>{vista === 'contactos' ? (r.empresa_nome || '—') : (r.website || r.dominio || '—')}</td>
                      <td style={prospTd}>{prospSegRotulo(r.segmento, r.segmento_tipo) || '—'}</td>
                      {vista === 'contactos' && <td style={prospTd}>{prospTxt(r.email)}</td>}
                    </tr>
                  ))}
                  {!linhas.length && <tr><td colSpan={vista === 'contactos' ? 5 : 4} style={{ ...prospTd, textAlign: 'center', color: 'var(--text-muted)', padding: 20 }}>Esta lista ainda não tem {vista === 'contactos' ? 'contactos' : 'empresas'}.</td></tr>}
                </tbody>
              </table>
            </div>
          </div>
        )}
        {enriquecerIds && <ProspEnriquecer ids={enriquecerIds} onClose={() => setEnriquecerIds(null)} onFeito={() => { if (aberta) abrir(aberta); onChanged?.(); }} />}
    </div>
  );
}

function ProspBase({ resumo, admin, onChanged, vendedores, marca, onOpen, desde, ate, f, setF, vista, cFiltro, onVista, onCFiltro, onLista }) {
  const [page, setPage] = React.useState(1);
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const [erro, setErro] = React.useState('');
  const [sel, setSel] = React.useState(new Set());
  const [msg, setMsg] = React.useState(null);
  const [tick, setTick] = React.useState(0);
  const [extracao, setExtracao] = React.useState(null);
  const [aAdicionar, setAAdicionar] = React.useState(false);
  const [enriquecerIds, setEnriquecerIds] = React.useState(null);
  const [aSeleccionar, setASeleccionar] = React.useState(false);
  const [aGravar, setAGravar] = React.useState(false);
  const pessoas = vista === 'contactos';

  const filtros = React.useMemo(() => {
    const arquivo = f.estado === '__arquivadas__' ? '1' : '';
    const estado = f.estado === '__arquivadas__' ? '' : f.estado;
    return pessoas
      ? { marca, desde, ate, page, limit: 50, estado, arquivo, pais: f.pais, fonte: f.fonte, equipa: f.equipa, comercial: f.comercial, zona: f.zona, segmento: f.segmento, ordem: f.ordem === 'nome' ? 'nome' : 'recentes', contacto: cFiltro }
      : { ...f, estado, arquivo, marca, desde, ate, page, limit: 50 };
  }, [pessoas, f, marca, desde, ate, page, cFiltro]);
  React.useEffect(() => { setPage(1); setSel(new Set()); }, [marca, desde, ate, vista, cFiltro, f.estado, f.pais, f.fonte, f.equipa, f.comercial, f.zona, f.segmento, f.com_email, f.com_telefone, f.ordem]);
  React.useEffect(() => {
    let stop = false;
    setLoading(true); setErro('');
    const t = setTimeout(() => {
      prospApi(pessoas ? '/contactos' : '/empresas', { query: filtros })
        .then(d => { if (!stop) setData(d); })
        .catch(e => { if (!stop) setErro(e.message); })
        .finally(() => { if (!stop) setLoading(false); });
    }, 250);
    return () => { stop = true; clearTimeout(t); };
  }, [filtros, tick, pessoas]);

  const rows = data?.rows || [];
  const pages = data ? Math.max(1, Math.ceil(data.total / data.limit)) : 1;
  const toggle = (id) => setSel(prev => { const n = new Set(prev); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const todos = !!(data?.total && sel.size >= data.total);
  const seleccionarTodas = async () => {
    if (todos) { setSel(new Set()); return; }
    if (!data?.total) return;
    if (data.total <= rows.length) { setSel(new Set(rows.map(r => r.id))); return; }
    setASeleccionar(true); setMsg(null);
    try {
      const d = await prospApi(pessoas ? '/contactos' : '/empresas', { query: { ...filtros, ids: '1' } });
      setSel(new Set((d.ids || []).map(id => String(id))));
      if (d.cortados) setMsg({ tipo: 'ok', texto: `Seleccionei ${prospNum((d.ids || []).length)}.` });
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setASeleccionar(false); }
  };

  const acao = async (fn, ok) => {
    setMsg(null);
    try { const d = await fn(); setMsg({ tipo: 'ok', texto: ok(d) }); setSel(new Set()); setTick(t => t + 1); onChanged?.(); }
    catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
  };
  const unidade = (n) => (pessoas ? (n === 1 ? 'contacto' : 'contactos') : (n === 1 ? 'empresa' : 'empresas'));
  const gravarSelecao = async (fn, ok) => {
    setAGravar(true);
    try { await acao(fn, ok); }
    finally { setAGravar(false); }
  };
  const arquivarSelecao = () => {
    const n = sel.size;
    const restaurar = f.estado === '__arquivadas__';
    const texto = restaurar
      ? `Restaurar ${prospNum(n)} ${unidade(n)} para a lista?`
      : `Arquivar ${prospNum(n)} ${unidade(n)}? Saem desta lista e ficam em Estado › Arquivadas.`;
    if (!window.confirm(texto)) return;
    const path = pessoas ? '/contactos/arquivar' : '/empresas/arquivar';
    const participio = (n) => {
      if (restaurar) return pessoas ? (n === 1 ? 'restaurado' : 'restaurados') : (n === 1 ? 'restaurada' : 'restauradas');
      return pessoas ? (n === 1 ? 'arquivado' : 'arquivados') : (n === 1 ? 'arquivada' : 'arquivadas');
    };
    gravarSelecao(
      () => prospApi(path, { method: 'POST', body: { ids: [...sel], arquivado: !restaurar } }),
      d => `${prospNum(d.n)} ${unidade(d.n)} ${participio(d.n)}.`
    );
  };
  const apagarSelecao = () => {
    const n = sel.size;
    const texto = pessoas
      ? `Apagar ${prospNum(n)} ${unidade(n)}?`
      : `Apagar ${prospNum(n)} ${unidade(n)}? Os contactos dessas empresas também saem da base.`;
    if (!window.confirm(texto)) return;
    const path = pessoas ? '/contactos/apagar' : '/empresas/apagar';
    gravarSelecao(
      () => prospApi(path, { method: 'POST', body: { ids: [...sel] } }),
      d => `${prospNum(d.n)} ${unidade(d.n)} ${pessoas ? (d.n === 1 ? 'apagado' : 'apagados') : (d.n === 1 ? 'apagada' : 'apagadas')}.`
    );
  };
  const extrairSites = async () => {
    setMsg(null);
    try {
      const d = await prospApi('/apify/websites', { method: 'POST', body: { empresa_ids: [...sel] } });
      setSel(new Set());
      setExtracao({ id: d.run_id, estado: 'a_correr', notas: 'A ler os websites…', parametros: {} });
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
  };
  React.useEffect(() => {
    if (!extracao?.id || extracao.estado !== 'a_correr') return;
    let stop = false;
    const ler = async () => {
      try {
        const d = await prospApi(`/runs/${extracao.id}`);
        if (stop || !d.run || d.run.estado === 'a_correr') return;
        setExtracao({ id: d.run.id, estado: d.run.estado, notas: d.run.notas, parametros: d.run.parametros || {} });
      } catch (e) { if (!stop) setMsg({ tipo: 'erro', texto: e.message }); }
    };
    const id = setInterval(ler, 4000);
    ler();
    return () => { stop = true; clearInterval(id); };
  }, [extracao?.id, extracao?.estado]);
  const adicionarExtracao = async (escolhas) => {
    if (!extracao?.id) return;
    setAAdicionar(true); setMsg(null);
    try {
      const d = await prospApi('/pesquisas/apify/gravar', { method: 'POST', body: { run_id: extracao.id, escolhas } });
      setExtracao(r => ({ ...r, parametros: { ...(r?.parametros || {}), adicionados: d.adicionados, contactos_adicionados: d.contactos_adicionados }, notas: d.notas }));
      setMsg({ tipo: 'ok', texto: `${d.empresas} empresas actualizadas, ${d.contactos} contactos adicionados.` });
      setTick(t => t + 1);
      onChanged?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setAAdicionar(false); }
  };
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18, minWidth: 0, maxWidth: '100%' }}>
      <ProspMsg msg={msg} />
      {extracao && (
        <ProspApifyResultados run={extracao} alvo="empresas" aCarregar={extracao.estado === 'a_correr'} aAdicionar={aAdicionar} onAdicionar={adicionarExtracao} />
      )}
      {erro && <ProspMsg msg={{ tipo: 'erro', texto: erro }} />}

      {data && (
        <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>
          {pessoas
            ? `${prospNum(data.total)} ${data.total === 1 ? 'contacto' : 'contactos'} · ${prospNum(data.empresas)} ${data.empresas === 1 ? 'empresa' : 'empresas'}`
            : `${prospNum(data.total)} ${data.total === 1 ? 'empresa' : 'empresas'} · ${prospNum(data.contactos)} ${data.contactos === 1 ? 'contacto' : 'contactos'}`}
        </div>
      )}
      {admin && sel.size > 0 && (
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap', fontSize: 13, background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: '12px 14px' }}>
          <strong>{sel.size} {pessoas ? (sel.size === 1 ? 'seleccionado' : 'seleccionados') : (sel.size === 1 ? 'seleccionada' : 'seleccionadas')}</strong>
          <button type="button" className="btn btn-sm btn-ai" onClick={() => onLista?.({ modo: 'adicionar', ids: [...sel], pessoas })}>Colocar na lista de enrichment</button>
          {pessoas ? (
            <button type="button" className="btn btn-sm" onClick={() => setEnriquecerIds([...sel])}>Enriquecer já</button>
          ) : (
            <>
              <button type="button" className="btn btn-sm btn-ai" onClick={() => acao(() => prospApi('/validar', { method: 'POST', body: { ids: [...sel], marca: marca || undefined } }), d => `Validação #${d.run_id} a correr — vê no Histórico.`)}>Validar</button>
              <button type="button" className="btn btn-sm" onClick={extrairSites}>Extrair contactos dos websites</button>
            </>
          )}
          <button type="button" className="btn btn-sm" disabled={aGravar} onClick={arquivarSelecao}>{f.estado === '__arquivadas__' ? 'Restaurar' : 'Arquivar'}</button>
          <button type="button" className="btn btn-sm" disabled={aGravar} onClick={apagarSelecao} style={{ color: '#9f1239' }}>Apagar</button>
          <button type="button" className="btn btn-sm btn-ghost" onClick={() => setSel(new Set())}>Limpar</button>
        </div>
      )}
      {enriquecerIds && (
        <ProspEnriquecer ids={enriquecerIds} onClose={() => setEnriquecerIds(null)} onFeito={() => { setTick(t => t + 1); onChanged?.(); }} />
      )}
      <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, overflowX: 'auto', width: '100%', maxWidth: '100%' }}>
        {(() => {
          const cols = pessoas ? PROSP_COLS_CONT : PROSP_COLS_EMP;
          const largura = (admin ? 36 : 0) + cols.reduce((s, [, w]) => s + w, 0);
          const td = prospTd;
          const cel = (v, extra) => <td style={{ ...td, color: v ? 'var(--text)' : 'var(--text-dim)', ...extra }} title={v || undefined}>{prospTxt(v)}</td>;
          const nCols = cols.length + (admin ? 1 : 0);
          return (
            <table style={{ width: largura, tableLayout: 'fixed', borderCollapse: 'collapse' }}>
              <colgroup>
                {admin && <col style={{ width: 36 }} />}
                {cols.map(([label, w]) => <col key={label} style={{ width: w }} />)}
              </colgroup>
              <thead style={{ position: 'sticky', top: 0, zIndex: 2, background: '#fff' }}>
                <tr>
                  {admin && <th style={{ ...prospTh, width: 36, background: '#fff' }}><input type="checkbox" checked={todos} disabled={aSeleccionar || !data?.total} title={data?.total > rows.length ? `Seleccionar todas (${prospNum(data.total)})` : 'Seleccionar esta página'} onChange={seleccionarTodas} /></th>}
                  {cols.map(([label]) => <th key={label} style={{ ...prospTh, background: '#fff' }}>{label}</th>)}
                </tr>
              </thead>
              <tbody>
                {pessoas ? rows.map(r => (
                  <tr key={r.id} className="prosp-row" onClick={() => onOpen({ id: r.empresa_id, nome: r.empresa_nome, pais: r.pais, fonte: r.fonte, estado: r.empresa_estado })} style={{ cursor: 'pointer' }}>
                    {admin && <td style={td} onClick={e => e.stopPropagation()}><input type="checkbox" checked={sel.has(r.id)} onChange={() => toggle(r.id)} /></td>}
                    <td style={{ ...td, fontWeight: 650 }} title={prospNomeDe(r)}>{prospNomeDe(r) || '—'}</td>
                    {cel(r.cargo && r.cargo !== 'Contacto publicado' ? r.cargo : '')}
                    <ProspPapelCel row={r} td={td} />
                    <td style={{ ...td, color: r.email ? 'var(--text)' : 'var(--text-dim)' }}>
                      <div>{prospTxt(r.email)}</div>
                      {r.confianca != null && <div style={{ marginTop: 2, fontSize: 11, fontWeight: 700, color: '#3730a3' }}>Confiança {r.confianca}%</div>}
                    </td>
                    {cel(r.telemovel_e164 || r.telemovel || r.empresa_telefone_e164 || r.empresa_telefone)}
                    <td style={td}>{r.linkedin_url ? <a href={r.linkedin_url} target="_blank" rel="noreferrer" onClick={ev => ev.stopPropagation()} style={{ color: 'var(--ai-500)', textDecoration: 'none' }}>{r.linkedin_url}</a> : <span style={{ color: 'var(--text-dim)' }}>—</span>}</td>
                    {cel(r.empresa_nome)}
                    <ProspSegmentoCel row={r} td={td} />
                    <td style={td}><ProspBadge estado={r.empresa_estado} /></td>
                    {cel(r.morada)}
                    {cel(r.codigo_postal)}
                    {cel(r.cidade)}
                    {cel(r.zona)}
                    {cel(r.pais)}
                    {cel(prospEquipaLista(r.atribuicoes))}
                    {cel(prospComercialLista(r.atribuicoes))}
                    {cel(r.marca_alvo)}
                    <ProspFonteCel fonte={r.fonte} origem={r.origem} href={r.origem_href} />
                  </tr>
                )) : rows.map(r => (
                  <tr key={r.id} className="prosp-row" onClick={() => onOpen(r)} style={{ cursor: 'pointer' }}>
                    {admin && <td style={td} onClick={e => e.stopPropagation()}><input type="checkbox" checked={sel.has(r.id)} onChange={() => toggle(r.id)} /></td>}
                    <td style={{ ...td, fontWeight: 650 }} title={r.nome}>{r.nome || '—'}</td>
                    {cel(r.nif)}
                    <td style={td}>{r.website || r.dominio ? <a href={/^https?:/.test(r.website || '') ? r.website : `https://${r.dominio || r.website}`} target="_blank" rel="noreferrer" onClick={ev => ev.stopPropagation()} style={{ color: 'var(--ai-500)', textDecoration: 'none' }}>{r.website || r.dominio}</a> : <span style={{ color: 'var(--text-dim)' }}>—</span>}</td>
                    <ProspPerfilCel row={r} td={td} />
                    {cel(r.telefone_e164 || r.telefone)}
                    {cel(r.morada)}
                    {cel(r.codigo_postal)}
                    {cel(r.cidade)}
                    {cel(r.zona)}
                    {cel(r.pais)}
                    {cel(prospEquipaLista(r.atribuicoes))}
                    {cel(prospComercialLista(r.atribuicoes))}
                    {cel(prospContactos(r), { color: r.n_contactos ? 'var(--text)' : 'var(--text-dim)' })}
                    {cel(r.marca_alvo)}
                    {cel(r.industria)}
                    <ProspSegmentoCel row={r} td={td} />
                    <td style={td}><ProspBadge estado={r.estado} /></td>
                    <ProspFonteCel fonte={r.fonte} origem={r.origem} href={r.origem_href} />
                  </tr>
                ))}
                {loading && !rows.length && <tr><td colSpan={nCols} style={{ ...prospTd, padding: 36 }}><div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', gap: 10 }}><ProspSpin />A carregar…</div></td></tr>}
                {!rows.length && !loading && <tr><td colSpan={nCols} style={{ ...prospTd, textAlign: 'center', color: 'var(--text-muted)', padding: 28 }}>{pessoas ? 'Sem contactos com estes filtros.' : (marca ? 'Nenhuma empresa desta marca. Em Todas vês a base completa.' : 'Sem empresas com estes filtros.')}</td></tr>}
              </tbody>
            </table>
          );
        })()}
      </div>

      {pages > 1 && (
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', fontSize: 12 }}>
          <button type="button" className="btn" disabled={page <= 1} onClick={() => setPage(p => p - 1)}>Anterior</button>
          <span style={{ color: 'var(--text-muted)' }}>{(page - 1) * 50 + 1}–{Math.min(data?.total || 0, page * 50)} de {prospNum(data?.total)}</span>
          <button type="button" className="btn" disabled={page >= pages} onClick={() => setPage(p => p + 1)}>Seguinte</button>
        </div>
      )}
    </div>
  );
}

function ProspFicha({ id, admin, vendedores, onClose, onChanged, onLoaded }) {
  const [d, setD] = React.useState(null);
  const [erro, setErro] = React.useState('');
  const [tick, setTick] = React.useState(0);
  const [notas, setNotas] = React.useState('');
  const [msg, setMsg] = React.useState(null);
  const [segmento, setSegmento] = React.useState('');
  const [decisao, setDecisao] = React.useState(null);
  const [entradas, setEntradas] = React.useState(null);
  const [aDecidir, setADecidir] = React.useState(false);

  React.useEffect(() => {
    let stop = false;
    setErro('');
    prospApi(`/empresas/${id}`).then(r => { if (!stop) { setD(r); setSegmento(prospSegValor(r?.empresa?.segmento, r?.empresa?.segmento_tipo)); if (r?.empresa) onLoaded?.(r.empresa); } }).catch(e => { if (!stop) setErro(e.message); });
    return () => { stop = true; };
  }, [id, tick]);

  const patch = async (body, texto) => {
    setMsg(null);
    try { await prospApi(`/empresas/${id}`, { method: 'PATCH', body: { ...body, notas: notas || undefined } }); setNotas(''); setMsg({ tipo: 'ok', texto }); setTick(t => t + 1); onChanged?.(); }
    catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
  };
  const guardarSegmento = async (op) => {
    const seg = prospSegPartes(segmento);
    if (!seg) return;
    setADecidir(true); setMsg(null);
    try {
      const body = { segmento: seg.segmento, segmento_tipo: seg.segmento_tipo };
      if (op) body.decisao = op;
      const r = await prospApi(`/empresas/${id}/segmento`, { method: 'POST', body });
      if (!op && r.pendentes?.total) setDecisao(r.pendentes);
      if (!op && prospTemEntradas(r.entradas)) setEntradas(r.entradas);
      if (!op && (r.pendentes?.total || prospTemEntradas(r.entradas))) {
        if (!r.pendentes?.total) {
          setMsg({ tipo: 'ok', texto: 'Segmento actualizado.' });
          setTick(t => t + 1);
          onChanged?.();
        }
        return;
      }
      setDecisao(null);
      setMsg({ tipo: 'ok', texto: op ? prospTextoDecisao(op) : 'Segmento actualizado.' });
      setTick(t => t + 1);
      onChanged?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setADecidir(false); }
  };
  const escolherEntrada = async (campanha, op) => {
    setADecidir(true); setMsg(null);
    try {
      const r = await prospEnviarEntrada(campanha, op);
      setEntradas(atual => prospEntradasSem(atual, campanha.id));
      setMsg({ tipo: 'ok', texto: prospTextoResultadoEntrada(op, campanha.nome, r) });
      setTick(t => t + 1);
      onChanged?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setADecidir(false); }
  };
  const revelar = async (ids) => {
    setMsg(null);
    try { const r = await prospApi('/contactos/revelar', { method: 'POST', body: { contacto_ids: ids } }); setMsg({ tipo: 'ok', texto: `${r.revelados} de ${r.pedidos} emails revelados (Apollo).` }); setTick(t => t + 1); }
    catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
  };

  const e = d?.empresa;
  const redes = redesDaEmpresa(e);
  const temRedes = ['facebook', 'instagram', 'tiktok', 'linkedin'].some(k => redes[k]);
  const v = e?.validacao || {};
  const porRevelar = (d?.contactos || []).filter(c => c.apollo_id && !c.email).map(c => c.id);
  const linha = (label, valor) => valor ? <div style={{ display: 'flex', gap: 8, fontSize: 13 }}><span style={{ color: 'var(--text-muted)', minWidth: 110 }}>{label}</span><span style={{ minWidth: 0, overflowWrap: 'anywhere' }}>{valor}</span></div> : null;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18, maxWidth: 980 }}>
      <ProspDecisaoSegmento pedido={decisao} entradas={entradas} aDecidir={aDecidir} onEscolher={guardarSegmento} onEntrada={escolherEntrada} onFechar={() => prospFecharDecisoes({ pedido: decisao, entradas, setDecisao, setEntradas, setMsg })} />
      {!e && !erro && <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>A carregar…</div>}
      {erro && <ProspMsg msg={{ tipo: 'erro', texto: erro }} />}
        <ProspMsg msg={msg} />
        {e && (
          <>
            <ProspCard style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {linha('NIF', e.nif && `${e.nif}${v.nif ? (v.nif.ok === false ? ' · inválido' : v.nif.ok ? ' · válido' : ' · por confirmar') : ''}${v.nif?.vies?.registado ? ' · VIES' : ''}`)}
              {linha('Nome oficial', v.nif?.vies?.nome_oficial)}
              {linha('Website', e.website && <a href={/^https?:/.test(e.website) ? e.website : `https://${e.website}`} target="_blank" rel="noreferrer">{e.website}</a>)}
              {e.perfil_site?.resumo && linha('Perfil do site', e.perfil_site.resumo)}
              {!!e.perfil_site?.trabalhos?.length && linha('Trabalhos', e.perfil_site.trabalhos.join(', '))}
              {!!e.perfil_site?.equipamentos?.length && linha('Equipamentos', e.perfil_site.equipamentos.join(', '))}
              {temRedes && linha('Redes', <ProspLinksRede redes={redes} />)}
              {linha('Telefone', e.telefone_e164 || e.telefone)}
              {linha('Morada', [e.morada, e.codigo_postal, e.cidade, e.zona, e.distrito, e.pais].filter((v, i, arr) => v && arr.indexOf(v) === i).join(', '))}
              {linha('Equipa', (d.atribuicoes || []).length ? d.atribuicoes.map(a => `${prospEquipa(a.equipa)}${a.comercial ? ` · ${a.comercial}` : ''}`).join(' · ') : 'Sem equipa')}
              {linha('Fonte', e.fonte && <span>{PROSP_FONTES[e.fonte] || e.fonte}{e.origem ? (e.origem_href ? <> · <a href={e.origem_href} target="_blank" rel="noreferrer">{e.origem}</a></> : <> · {e.origem}</>) : ''}</span>)}
              {linha('Sector', [e.industria, e.cae && `CAE ${e.cae}`].filter(Boolean).join(' · '))}
              {linha('Segmento', (
                <span style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
                  <select style={{ ...prospInput, width: 'auto', minWidth: 220 }} value={segmento} onChange={ev => setSegmento(ev.target.value)}>
                    <option value="">Sem segmento</option>
                    {PROSP_SEGMENTOS.map(s => <option key={prospSegValor(s.segmento, s.tipo)} value={prospSegValor(s.segmento, s.tipo)}>{prospSegRotulo(s.segmento, s.tipo)}</option>)}
                  </select>
                  <button type="button" className="btn btn-sm" disabled={aDecidir || !prospSegPartes(segmento) || segmento === prospSegValor(e.segmento, e.segmento_tipo)} onClick={() => guardarSegmento()}>Guardar segmento</button>
                  {e.segmento_fonte === 'crm' ? <span style={{ color: 'var(--text-muted)' }}>Gestor</span> : e.segmento_fonte === 'import' ? <span style={{ color: 'var(--text-muted)' }}>Ficheiro</span> : e.segmento_fonte === 'manual' ? <span style={{ color: 'var(--text-muted)' }}>Manual</span> : e.segmento_fonte === 'pesquisa' ? <span style={{ color: 'var(--text-muted)' }}>Pesquisa</span> : e.segmento_confianca != null ? <span style={{ color: 'var(--text-muted)' }}>confiança {e.segmento_confianca}%</span> : null}
                </span>
              ))}
              {linha('Empregados', e.funcionarios)}
              {linha('Google', e.sinais?.gmb && `${e.sinais.gmb.rating ?? '—'}★ · ${e.sinais.gmb.reviews ?? 0} avaliações`)}
              {linha('Gestor', e.fm_entidade_id && `Já existe no Gestor (${e.fm_tenant} #${e.fm_entidade_id}, por ${e.fm_match_por})`)}
              {linha('Validação', e.validado_em && `${prospData(e.validado_em)}${v.dominio ? ` · domínio ${v.dominio.mx ? 'com' : 'sem'} email (MX)` : ''}`)}
            </ProspCard>

            <ProspCard style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
              <div style={{ fontWeight: 650 }}>Seguimento comercial</div>
              <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                <select style={prospInput} value={e.vendedor_id || ''} onChange={ev => patch({ vendedor_id: ev.target.value || null }, 'Vendedor actualizado.')}>
                  <option value="">Sem vendedor</option>
                  {vendedores.map(vd => <option key={vd.email} value={vd.email}>{vd.nome}</option>)}
                  {e.vendedor_id && !vendedores.some(vd => vd.email === e.vendedor_id) && <option value={e.vendedor_id}>{e.vendedor_id}</option>}
                </select>
                <select style={prospInput} value={e.estado} onChange={ev => patch({ estado: ev.target.value }, 'Estado actualizado.')}>
                  {PROSP_ESTADOS.map(s => <option key={s.id} value={s.id}>{s.label}</option>)}
                </select>
              </div>
              <textarea style={{ ...prospInput, minHeight: 60, resize: 'vertical' }} placeholder="Nota (opcional) — fica no histórico" value={notas} onChange={ev => setNotas(ev.target.value)} />
              {notas && <div><button type="button" className="btn btn-sm" onClick={() => patch({}, 'Nota registada.')}>Guardar nota</button></div>}
            </ProspCard>

            <ProspCard style={{ padding: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', padding: '12px 16px', gap: 8 }}>
                <div style={{ fontWeight: 650, flex: 1 }}>Contactos ({d.contactos.length})</div>
                {admin && porRevelar.length > 0 && <button type="button" className="btn btn-sm btn-ai" onClick={() => revelar(porRevelar)} title="Usa créditos Apollo">Revelar {porRevelar.length} emails (Apollo)</button>}
              </div>
              <div style={{ overflowX: 'auto' }}>
              <table style={{ width: '100%', minWidth: 980, borderCollapse: 'collapse' }}>
                <thead><tr><th style={prospTh}>Nome</th><th style={prospTh}>Cargo</th><th style={prospTh}>Email</th><th style={prospTh}>Telemóvel</th><th style={prospTh}>LinkedIn</th></tr></thead>
                <tbody>
                  {d.contactos.map(c => (
                    <tr key={c.id} style={{ opacity: c.opt_out ? 0.5 : 1 }}>
                      <td style={prospTd}>{prospNomeDe(c) || '—'}{c.opt_out && <div style={{ fontSize: 11, color: '#b91c1c' }}>opt-out</div>}</td>
                      <td style={prospTd}>{prospSemAsteriscos(c.cargo) || '—'}{c.papel && <div style={{ fontSize: 11, fontWeight: 700, color: '#3730a3' }}>{c.papel === 'decisor' ? 'Decisor' : 'Influenciador'}{c.cargo_crm ? ` · ${prospSemAsteriscos(c.cargo_crm)}` : ''}</div>}</td>
                      <td style={prospTd}>{(prospSemAsteriscos(c.email) || (c.apollo_id ? <span style={{ color: 'var(--text-dim)' }}>por revelar</span> : '—'))}{c.email_status && prospSemAsteriscos(c.email) && <div style={{ fontSize: 10, color: c.email_status === 'invalido' ? '#b91c1c' : 'var(--text-dim)' }}>{c.email_status}{c.validacao?.email?.generico ? ' · genérico' : ''}</div>}{c.validacao?.enriquecimento?.confianca != null && <div style={{ fontSize: 11, fontWeight: 700, color: '#3730a3' }}>Confiança {c.validacao.enriquecimento.confianca}%</div>}</td>
                      <td style={prospTd}>{prospTxt(c.telemovel_e164 || c.telemovel)}</td>
                      <td style={prospTd}>{prospSemAsteriscos(c.linkedin_url) ? <a href={c.linkedin_url} target="_blank" rel="noreferrer">{prospSemAsteriscos(c.linkedin_url)}</a> : '—'}</td>
                    </tr>
                  ))}
                  {!d.contactos.length && <tr><td colSpan={5} style={{ ...prospTd, color: 'var(--text-muted)' }}>Sem contactos. {admin && e.website ? 'Selecciona a empresa na lista e usa “Extrair contactos dos websites”.' : ''}</td></tr>}
                </tbody>
              </table>
              </div>
            </ProspCard>

            {d.eventos.length > 0 && (
              <ProspCard style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                <div style={{ fontWeight: 650 }}>Histórico</div>
                {d.eventos.map(ev => (
                  <div key={ev.id} style={{ fontSize: 12, borderLeft: '2px solid var(--border)', paddingLeft: 10 }}>
                    <div><strong>{ev.tipo.replace('estado:', 'Estado → ')}</strong> · {prospData(ev.criado_em)} · {ev.criado_por}</div>
                    {ev.notas && <div style={{ color: 'var(--text-muted)', whiteSpace: 'pre-wrap' }}>{ev.notas}</div>}
                  </div>
                ))}
              </ProspCard>
            )}
          </>
        )}
    </div>
  );
}

// ── Nova pesquisa ─────────────────────────────────────────────────────────────

const PROSP_FONTES_PESQUISA = [
  { id: 'apollo', label: 'Apollo' },
  { id: 'maps', label: 'Google Maps' },
  { id: 'pagina', label: 'Web Scrapping' },
  { id: 'ficheiro', label: 'Importar ficheiro' },
];
const PROSP_SEGMENTOS = [
  { segmento: 'Marcas', tipo: '' },
  { segmento: 'Agências Publicidade e Criativas', tipo: '' },
  { segmento: 'SignGraphics', tipo: 'Impressão Digital' },
  { segmento: 'SignGraphics', tipo: 'Decoração Interiores' },
  { segmento: 'Textil', tipo: 'Estamparia Digital' },
  { segmento: 'Textil', tipo: 'Confecções Moda Desporto' },
  { segmento: 'Textil', tipo: 'Textil Lar HomeDecor' },
  { segmento: 'Textil', tipo: 'Calçado Peles' },
  { segmento: 'Decal Mimaki Partners', tipo: 'Digital Printer - Enduser' },
  { segmento: 'Decal Mimaki Partners', tipo: 'Distribuidor - Partner' },
  { segmento: 'NetScreen', tipo: 'Farmácias' },
  { segmento: 'NetScreen', tipo: 'Gabinetes de Arquitectura e Engenharia' },
  { segmento: 'NetScreen', tipo: 'Grupos de Lojas' },
  { segmento: 'NetScreen', tipo: 'Stand Automóveis' },
  { segmento: 'NetScreen', tipo: 'Lojistas Individuais' },
  { segmento: 'NetScreen', tipo: 'Ópticas' },
  { segmento: 'NetScreen', tipo: 'Câmaras Municipais' },
  { segmento: 'NetScreen', tipo: 'Imobiliárias' },
  { segmento: 'NetScreen', tipo: 'Agencias Meios e Anunciantes BD' },
];
const prospSegValor = (segmento, tipo) => (segmento ? `${segmento}|||${tipo || ''}` : '');
const prospSegPartes = (valor) => {
  const [segmento, tipo] = String(valor || '').split('|||');
  return segmento ? { segmento, segmento_tipo: tipo || null } : null;
};
const prospSegRotulo = (segmento, tipo) => [segmento, tipo].filter(Boolean).join(' · ');
const PROSP_REDES = [
  { id: 'facebook', label: 'Facebook', nota: 'Páginas de empresa: nome, categoria, telefone, email e site.' },
  { id: 'instagram', label: 'Instagram', nota: 'Perfis públicos do segmento. O site entra quando o perfil o tem.' },
  { id: 'tiktok', label: 'TikTok', nota: 'Perfis públicos. Útil em decoração e reclamos; na indústria rende pouco.' },
];
const PROSP_PAISES = [{ value: 'PT', label: 'Portugal' }, { value: 'ES', label: 'Espanha' }, { value: 'FR', label: 'França' }];

function redesDaEmpresa(e) {
  const w = e?.sinais?.website_contactos || {};
  const feira = e?.sinais?.pagina || {};
  return { linkedin: w.linkedin || feira.linkedin, facebook: w.facebook, instagram: w.instagram, ...(e?.sinais?.redes || {}) };
}

function ProspLinksRede({ redes }) {
  const links = [
    ['Facebook', redes?.facebook],
    ['Instagram', redes?.instagram],
    ['TikTok', redes?.tiktok],
    ['LinkedIn', redes?.linkedin],
  ].filter(([, url]) => url);
  if (!links.length) return null;
  return (
    <span style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }} onClick={ev => ev.stopPropagation()}>
      {links.map(([label, url]) => <a key={label} href={url} target="_blank" rel="noreferrer" style={{ fontSize: 12, color: 'var(--ai-500)', textDecoration: 'none' }}>{label}</a>)}
    </span>
  );
}

function ProspSeparadores({ items, activo, onChange }) {
  return (
    <div style={{ display: 'flex', gap: 0, flexWrap: 'wrap' }}>
      {items.map(b => {
        const on = b.id === activo;
        return (
          <button key={b.id} type="button" onClick={() => onChange(b.id)} style={{
            background: 'none', border: 'none', outline: 'none',
            borderBottom: `2px solid ${on ? 'var(--ai-500)' : 'transparent'}`,
            color: on ? 'var(--text)' : 'var(--text-muted)',
            fontSize: 13, fontWeight: on ? 600 : 500,
            fontFamily: 'var(--font-display)', letterSpacing: '.01em',
            padding: '10px 16px 12px', cursor: 'pointer', whiteSpace: 'nowrap',
          }}>{b.label}</button>
        );
      })}
    </div>
  );
}

function ProspMenuFontes({ activo, onChange, filtros }) {
  const [over, setOver] = React.useState('');
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      {PROSP_FONTES_PESQUISA.map(p => {
        const on = p.id === activo;
        const hover = over === p.id && !on;
        return (
          <div key={p.id}
            onMouseEnter={() => setOver(p.id)} onMouseLeave={() => setOver('')}
            style={{
              border: `1px solid ${on || hover ? 'var(--ai-500)' : 'var(--border)'}`,
              borderRadius: 8, overflow: 'hidden',
              background: on ? 'color-mix(in oklch, var(--ai-500, #3859D0) 8%, #fff)' : (hover ? '#f4f7ff' : '#fff'),
              transition: 'background .12s, border-color .12s',
            }}>
            <button type="button" onClick={() => onChange(p.id)} style={{
              display: 'block', width: '100%', textAlign: 'left', background: 'transparent', border: 'none',
              color: on ? 'var(--ai-500)' : 'var(--text)', padding: '10px 12px',
              fontSize: 13, fontWeight: 650, cursor: 'pointer', fontFamily: 'inherit',
            }}>{p.label}</button>
            {on && (
              <div style={{ borderTop: '1px solid var(--border)', background: '#fff', padding: '12px 12px 14px', display: 'flex', flexDirection: 'column', gap: 16 }}>
                {filtros}
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

function ProspPesquisasGuardadas({ g }) {
  const [over, setOver] = React.useState(null);
  const [nome, setNome] = React.useState('');
  const [segmento, setSegmento] = React.useState('');
  const aberta = g.rows.find(r => r.id === g.aberta) || null;
  React.useEffect(() => {
    setNome(aberta?.nome || '');
    setSegmento(prospSegValor(aberta?.segmento, aberta?.segmento_tipo));
  }, [g.aberta, aberta?.nome, aberta?.segmento, aberta?.segmento_tipo]);
  const canalDe = (fonte) => PROSP_FONTES_PESQUISA.find(p => p.id === fonte)?.label || PROSP_FONTES[fonte] || fonte;
  const nomeFinal = (nome.trim() || g.rascunho?.rotulo || '').trim();
  const seg = prospSegPartes(segmento);
  const botaoSec = (label, onClick, disabled) => (
    <button type="button" disabled={disabled} onClick={onClick} style={{
      width: '100%', border: '1px solid var(--border)', background: '#fff', borderRadius: 8,
      padding: '8px 10px', fontFamily: 'inherit', fontSize: 13, fontWeight: 650, color: 'var(--text)',
      cursor: disabled ? 'default' : 'pointer', opacity: disabled ? 0.5 : 1,
    }}>{label}</button>
  );
  return (
    <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ fontSize: 11, fontWeight: 650, letterSpacing: '.06em', textTransform: 'uppercase', color: 'var(--text-dim)' }}>Pesquisas guardadas</div>
      {!g.rows.length && (
        <div style={{ border: '1px solid var(--border)', borderRadius: 8, padding: '10px 12px', fontSize: 13, color: 'var(--text-muted)' }}>Ainda não há pesquisas guardadas.</div>
      )}
      {g.rows.length > 0 && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {g.rows.map(r => {
            const on = g.aberta === r.id;
            const hover = over === r.id && !on;
            const nEmp = Number(r.n_empresas) || 0;
            const nCon = Number(r.n_contactos) || 0;
            return (
              <div key={r.id} onMouseEnter={() => setOver(r.id)} onMouseLeave={() => setOver(null)} style={{
                display: 'flex', alignItems: 'center', gap: 8,
                border: `1px solid ${on || hover ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 8, padding: '8px 10px',
                background: on ? 'color-mix(in oklch, var(--ai-500, #3859D0) 10%, #fff)' : (hover ? '#f4f7ff' : '#fff'),
              }}>
                <button type="button" onClick={() => g.onAbrir(r)} style={{ flex: 1, minWidth: 0, textAlign: 'left', background: 'transparent', border: 'none', cursor: 'pointer', fontFamily: 'inherit', padding: 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 650, color: on ? 'var(--ai-500)' : 'var(--text)' }}>{r.nome}</div>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{canalDe(r.fonte)} · {nEmp} empresas · {nCon} contactos</div>
                  {r.segmento && <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{prospSegRotulo(r.segmento, r.segmento_tipo)}</div>}
                </button>
                <button type="button" aria-label="Apagar pesquisa" onClick={() => g.onApagar(r.id)} style={{ border: 'none', background: 'transparent', color: 'var(--text-dim)', cursor: 'pointer', fontSize: 16, lineHeight: 1, padding: 4 }}>×</button>
              </div>
            );
          })}
        </div>
      )}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8, borderTop: '1px solid var(--border)', paddingTop: 12 }}>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.4 }}>{aberta ? 'O nome edita-se aqui. A grelha à direita mostra só as empresas e os contactos desta pesquisa.' : 'Guarda o nome, os filtros e as empresas e contactos já gravados nesta execução.'}</div>
        <input style={prospInput} value={nome} placeholder={g.rascunho?.rotulo || 'Nome da pesquisa'} onChange={ev => setNome(ev.target.value)} />
        <select style={prospInput} value={segmento} onChange={ev => setSegmento(ev.target.value)}>
          <option value="">Segmento das empresas</option>
          {PROSP_SEGMENTOS.map(s => <option key={prospSegValor(s.segmento, s.tipo)} value={prospSegValor(s.segmento, s.tipo)}>{prospSegRotulo(s.segmento, s.tipo)}</option>)}
        </select>
        {aberta ? (
          <>
            <ProspBotao disabled={!nomeFinal || g.aGuardar} onClick={() => g.onNome(aberta.id, nomeFinal)}>{g.aGuardar ? 'A guardar…' : 'Guardar nome'}</ProspBotao>
            {botaoSec('Aplicar segmento às empresas', () => g.onSegmento(aberta.id, seg), !seg || g.aGuardar)}
            {botaoSec('Juntar resultados desta execução', () => g.onJuntar(aberta.id), !g.runId || g.aGuardar)}
            {botaoSec('Actualizar filtros', () => g.onFiltros(aberta.id, nomeFinal, seg), !g.rascunho?.pode || !nomeFinal || g.aGuardar)}
            {botaoSec('Guardar como nova', () => g.onGuardar(nomeFinal, seg, true), !g.rascunho?.pode || !nomeFinal || g.aGuardar)}
          </>
        ) : (
          <ProspBotao disabled={!g.rascunho?.pode || !nomeFinal || g.aGuardar} onClick={() => g.onGuardar(nomeFinal, seg, false)}>{g.aGuardar ? 'A guardar…' : 'Guardar esta'}</ProspBotao>
        )}
        {g.erro && <div style={{ fontSize: 12, color: '#b91c1c', lineHeight: 1.4 }}>{g.erro}</div>}
      </div>
    </div>
  );
}

function ProspDirectorio({ busy, caixa, resultados, onRun }) {
  const [url, setUrl] = React.useState('');
  const valido = /^https?:\/\/\S+\.\S+/.test(url.trim());
  const reportar = caixa.onRascunho;
  React.useEffect(() => {
    let rotulo = 'Web Scrapping';
    try { if (url.trim()) rotulo = new URL(url.trim()).hostname.replace(/^www\./, ''); } catch { /* ainda não é um endereço */ }
    reportar?.({ fonte: 'pagina', alvo: caixa.alvo, parametros: { url: url.trim() }, rotulo, pode: valido });
  }, [url, valido, caixa.alvo, reportar]);
  React.useEffect(() => {
    const p = caixa.pedido;
    if (!p || p.fonte !== 'pagina') return;
    setUrl(p.parametros?.url || '');
  }, [caixa.pedido && caixa.pedido.n]);
  return (
    <ProspColunas caixa={caixa} resultados={resultados} filtros={
      <>
        <ProspSecao titulo="Endereço">
          <ProspField label="URL" hint="Qualquer página pública: directório, tabela ou ficha. Num directório abre cada empresa.">
            <input style={prospInput} value={url} placeholder="https://" disabled={busy} onChange={ev => setUrl(ev.target.value)} />
          </ProspField>
        </ProspSecao>
        <ProspAviso>Lê o HTML da página. Num directório abre cada ficha; tabelas e listas entram sem créditos. O ScrapeGraph só entra quando a página não traz as empresas, ou quando o site bloqueia a leitura, e gasta créditos do plano dele.</ProspAviso>
        <ProspBotao disabled={busy || !valido} onClick={() => onRun({ url: url.trim() })}>
          {busy ? 'A extrair…' : 'Extrair contactos'}
        </ProspBotao>
      </>
    } />
  );
}

function ProspPesquisa({ fonte, onFonte, onLancada, onOpen, onAberto, marca, marcaLabel }) {
  const [msg, setMsg] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const [run, setRun] = React.useState(null);
  const [rows, setRows] = React.useState([]);
  const [alvo, setAlvo] = React.useState('empresas');
  const [aberto, setAberto] = React.useState(false);
  const [guardadas, setGuardadas] = React.useState([]);
  const [aberta, setAberta] = React.useState(null);
  const [rascunho, setRascunho] = React.useState(null);
  const [pedido, setPedido] = React.useState(null);
  const [aGuardar, setAGuardar] = React.useState(false);
  const [aAdicionar, setAAdicionar] = React.useState(false);
  const [erroGuardar, setErroGuardar] = React.useState('');
  const [decisao, setDecisao] = React.useState(null);
  const [entradas, setEntradas] = React.useState(null);
  const [aDecidir, setADecidir] = React.useState(false);
  const [consulta, setConsulta] = React.useState(null);
  const [enriquecerIds, setEnriquecerIds] = React.useState(null);
  const [decisores, setDecisores] = React.useState(null);
  const onRascunho = React.useCallback((snap) => {
    setRascunho(prev => {
      const antes = prev && { fonte: prev.fonte, alvo: prev.alvo, rotulo: prev.rotulo, pode: prev.pode, parametros: prev.parametros };
      return JSON.stringify(antes) === JSON.stringify(snap) ? prev : snap;
    });
  }, []);
  React.useEffect(() => {
    prospApi('/pesquisas/guardadas').then(d => setGuardadas(d.rows || [])).catch(() => setGuardadas([]));
  }, []);
  const grupo = ['facebook', 'instagram', 'tiktok'].includes(fonte) ? 'redes' : fonte;
  const fonteApify = fonte === 'maps' || fonte === 'google' || ['facebook', 'instagram', 'tiktok'].includes(fonte);
  const comMarca = (b) => (marca ? { ...b, marca } : b);
  const aLer = busy || run?.estado === 'a_correr';
  const correr = async (fn, nota = 'A pesquisar…') => {
    setBusy(true); setMsg(null); setRows([]); setRun({ estado: 'a_correr', notas: nota });
    try {
      const d = await fn();
      setRun({ id: d.run_id, estado: d.estado || 'a_correr', notas: nota });
      onLancada?.();
    } catch (e) { setRun(null); setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setBusy(false); }
  };
  React.useEffect(() => { setRun(null); setRows([]); setMsg(null); }, [fonte]);
  React.useEffect(() => { onAberto?.(aberto); }, [aberto, onAberto]);
  React.useEffect(() => {
    if (!run?.id || run.estado !== 'a_correr') return;
    let stop = false;
    const ler = async () => {
      try {
        const d = await prospApi(`/runs/${run.id}`);
        if (stop || !d.run) return;
        if (d.run.estado === 'a_correr') {
          setRun(d.run);
          if (!fonteApify && Number(d.run.n_empresas) > 0) {
            const e = await prospApi(alvo === 'contactos' ? '/contactos' : '/empresas', { query: { run_id: run.id, limit: 1000 } });
            if (!stop) setRows(e.rows || []);
          }
          return;
        }
        setRun(d.run);
        if (d.run.estado === 'concluido') onLancada?.();
      } catch (e) { if (!stop) setMsg({ tipo: 'erro', texto: e.message }); }
    };
    ler();
    const id = setInterval(ler, 2000);
    return () => { stop = true; clearInterval(id); };
  }, [run?.id, run?.estado, alvo, fonteApify]);
  React.useEffect(() => {
    if (fonteApify || !run?.id || run.estado !== 'concluido' || run.fonte === 'validacao') {
      if (run?.fonte === 'validacao') setRows([]);
      return;
    }
    let stop = false;
    prospApi(alvo === 'contactos' ? '/contactos' : '/empresas', { query: { run_id: run.id, limit: 1000 } })
      .then(e => { if (!stop) setRows(e.rows || []); })
      .catch(() => { if (!stop) setRows([]); });
    return () => { stop = true; };
  }, [run?.id, run?.estado, run?.fonte, alvo, fonteApify]);
  const escolher = (id) => {
    if (id !== fonte && id !== grupo) { setConsulta(null); setAberta(null); setEnriquecerIds(null); }
    if (['facebook', 'instagram', 'tiktok'].includes(id)) { setAberto(true); onFonte(id); return; }
    if (id === grupo && aberto) { setAberto(false); return; }
    setAberto(true);
    onFonte(id);
  };
  const redeActual = PROSP_REDES.find(r => r.id === fonte);
  const notaMarca = marcaLabel ? <>Fica em <strong>{marcaLabel}</strong>.</> : 'Sem marca. Escolhe uma marca na tab se quiseres que fique associada.';
  const porRow = (row) => setGuardadas(lista => [row, ...lista.filter(x => x.id !== row.id)]);
  const carregarConsulta = async (item) => {
    if (!item?.id) return;
    setConsulta(c => ({ id: item.id, nome: item.nome || c?.nome || '', aCarregar: true, empresas: c?.id === item.id ? c.empresas : [], contactos: c?.id === item.id ? c.contactos : [] }));
    try {
      const [em, co] = await Promise.all([
        prospApi('/empresas', { query: { pesquisa_id: item.id, limit: 1000, ordem: 'nome' } }),
        prospApi('/contactos', { query: { pesquisa_id: item.id, limit: 1000, ordem: 'nome' } }),
      ]);
      setConsulta({ id: item.id, nome: item.nome || '', empresas: em.rows || [], contactos: co.rows || [] });
    } catch (e) {
      setErroGuardar(e.message);
      setConsulta(c => (c?.id === item.id ? { ...c, aCarregar: false } : c));
    }
  };
  const abrirGuardada = (item) => {
    setAberta(item.id);
    setEnriquecerIds(null);
    setDecisores(null);
    setAlvo(item.alvo === 'contactos' ? 'contactos' : 'empresas');
    setAberto(true);
    onFonte(item.fonte);
    setPedido({ n: Date.now(), fonte: item.fonte, alvo: item.alvo, parametros: item.parametros || {} });
    carregarConsulta(item);
  };
  const runIdGuardar = (() => {
    if (!run?.id || run.estado === 'erro') return null;
    if (fonte === 'maps' || fonte === 'google' || ['facebook', 'instagram', 'tiktok'].includes(fonte)) return run.fonte === 'apify' ? run.id : null;
    if ((fonte === 'pagina' || fonte === 'apollo') && (run.fonte === fonte || !run.fonte)) return run.id;
    return null;
  })();
  const guardarEsta = async (nome, seg) => {
    if (!rascunho?.pode || !nome) return false;
    setAGuardar(true); setErroGuardar('');
    try {
      const d = await prospApi('/pesquisas/guardadas', { method: 'POST', body: { nome, fonte: rascunho.fonte, alvo: rascunho.alvo || alvo, marca: marca || undefined, parametros: rascunho.parametros, run_id: runIdGuardar || undefined, segmento: seg?.segmento, segmento_tipo: seg?.segmento_tipo } });
      porRow(d.row);
      setAberta(d.row.id);
      if (d.row.pendentes?.total) setDecisao(d.row.pendentes);
      if (prospTemEntradas(d.row.entradas)) setEntradas(d.row.entradas);
      await carregarConsulta(d.row);
      return true;
    } catch (e) { setErroGuardar(e.message); return false; }
    finally { setAGuardar(false); }
  };
  const guardarNome = async (id, nome) => {
    if (!nome) return;
    setAGuardar(true); setErroGuardar('');
    try {
      const d = await prospApi(`/pesquisas/guardadas/${id}`, { method: 'PATCH', body: { nome } });
      porRow(d.row);
      setConsulta(c => (c?.id === id ? { ...c, nome: d.row.nome } : c));
    } catch (e) { setErroGuardar(e.message); }
    finally { setAGuardar(false); }
  };
  const guardarSegmento = async (id, seg) => {
    if (!seg) return;
    setAGuardar(true); setErroGuardar('');
    try {
      const d = await prospApi(`/pesquisas/guardadas/${id}`, { method: 'PATCH', body: { segmento: seg.segmento, segmento_tipo: seg.segmento_tipo } });
      porRow(d.row);
      setMsg({ tipo: 'ok', texto: `Segmento aplicado a ${d.row.segmento_aplicado ?? d.row.n_empresas} empresas.` });
      if (d.row.pendentes?.total) setDecisao(d.row.pendentes);
      if (prospTemEntradas(d.row.entradas)) setEntradas(d.row.entradas);
      if (consulta?.id === id) await carregarConsulta(d.row);
    } catch (e) { setErroGuardar(e.message); }
    finally { setAGuardar(false); }
  };
  const guardarFiltros = async (id, nome, seg) => {
    if (!rascunho?.pode || !nome) return;
    setAGuardar(true); setErroGuardar('');
    try {
      const d = await prospApi(`/pesquisas/guardadas/${id}`, { method: 'PATCH', body: { nome, fonte: rascunho.fonte, alvo: rascunho.alvo || alvo, marca: marca || undefined, parametros: rascunho.parametros, segmento: seg?.segmento, segmento_tipo: seg?.segmento_tipo } });
      porRow(d.row);
      if (d.row.pendentes?.total) setDecisao(d.row.pendentes);
      if (prospTemEntradas(d.row.entradas)) setEntradas(d.row.entradas);
      if (consulta?.id === id) await carregarConsulta(d.row);
    } catch (e) { setErroGuardar(e.message); }
    finally { setAGuardar(false); }
  };
  const juntarResultados = async (id) => {
    if (!runIdGuardar) return;
    setAGuardar(true); setErroGuardar('');
    try {
      const d = await prospApi(`/pesquisas/guardadas/${id}/resultados`, { method: 'POST', body: { run_id: runIdGuardar } });
      porRow(d.row);
      setMsg({ tipo: 'ok', texto: `${d.row.n_empresas} empresas e ${d.row.n_contactos} contactos nesta pesquisa.` });
      if (d.pendentes?.total) setDecisao(d.pendentes);
      if (prospTemEntradas(d.entradas)) setEntradas(d.entradas);
      await carregarConsulta(d.row);
    } catch (e) { setErroGuardar(e.message); }
    finally { setAGuardar(false); }
  };
  const apagarGuardada = async (id) => {
    setGuardadas(lista => lista.filter(x => x.id !== id));
    if (aberta === id) setAberta(null);
    if (consulta?.id === id) setConsulta(null);
    try { await prospApi(`/pesquisas/guardadas/${id}`, { method: 'DELETE' }); }
    catch (e) { setErroGuardar(e.message); prospApi('/pesquisas/guardadas').then(d => setGuardadas(d.rows || [])).catch(() => {}); }
  };
  const procurarDecisores = async () => {
    if (!consulta?.id || decisores?.estado === 'a_correr') return;
    setMsg(null);
    try {
      const d = await prospApi(`/pesquisas/guardadas/${consulta.id}/decisores`, { method: 'POST', body: {} });
      if (!d.run_id) { setMsg({ tipo: 'ok', texto: d.notas }); return; }
      setDecisores({ id: d.run_id, estado: 'a_correr', notas: d.notas, parametros: { progresso: { feitos: 0, total: d.total }, tipo: 'pesquisa_decisores' } });
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
  };
  const abrirEnriquecer = (ids) => {
    const unicos = [...new Set((ids || []).map(Number).filter(Boolean))];
    if (!unicos.length) {
      setMsg({ tipo: 'erro', texto: 'Esta pesquisa ainda não tem decisores nem influenciadores. Procura-os no Apollo primeiro.' });
      return;
    }
    setEnriquecerIds(unicos.slice(0, 40));
    if (unicos.length > 40) setMsg({ tipo: 'ok', texto: `A janela trata 40 contactos. Ficam ${unicos.length - 40} para a volta seguinte.` });
  };
  React.useEffect(() => {
    if (!decisores?.id || decisores.estado !== 'a_correr') return undefined;
    let stop = false;
    const ler = async () => {
      try {
        const d = await prospApi(`/runs/${decisores.id}`);
        if (stop || !d.run) return;
        if (d.run.estado === 'a_correr') { setDecisores(d.run); return; }
        setDecisores(d.run);
        setMsg({ tipo: d.run.estado === 'erro' ? 'erro' : 'ok', texto: d.run.notas || 'Procura concluída.' });
        const lista = await prospApi('/pesquisas/guardadas');
        if (stop) return;
        setGuardadas(lista.rows || []);
        const fresco = (lista.rows || []).find(r => r.id === aberta);
        if (fresco) await carregarConsulta(fresco);
      } catch (e) { if (!stop) setMsg({ tipo: 'erro', texto: e.message }); }
    };
    const id = setInterval(ler, 2000);
    ler();
    return () => { stop = true; clearInterval(id); };
  }, [decisores?.id, decisores?.estado]);
  const caixa = { alvo, onAlvo: setAlvo, nota: notaMarca, activo: aberto ? grupo : '', onCanal: escolher, onRascunho, pedido, onExecucao: (id) => { if (id) setRun({ id, fonte: 'apollo', estado: 'a_correr' }); }, guardadas: { rows: guardadas, aberta, rascunho, aGuardar, erro: erroGuardar, runId: runIdGuardar, onAbrir: abrirGuardada, onGuardar: guardarEsta, onNome: guardarNome, onSegmento: guardarSegmento, onFiltros: guardarFiltros, onJuntar: juntarResultados, onApagar: apagarGuardada }, extra: grupo === 'redes' ? (
    <>
      <ProspSeparadores items={PROSP_REDES} activo={fonte} onChange={escolher} />
      <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{redeActual?.nota} Só a página pública. Sem seguidores nem publicações.</div>
    </>
  ) : null };
  const adicionarApify = async (escolhas) => {
    if (!run?.id || !escolhas.length) return;
    setAAdicionar(true); setMsg(null);
    try {
      const d = await prospApi('/pesquisas/apify/gravar', { method: 'POST', body: { run_id: run.id, escolhas } });
      setRun(r => ({ ...r, parametros: { ...(r?.parametros || {}), adicionados: d.adicionados, contactos_adicionados: d.contactos_adicionados } }));
      setMsg({ tipo: 'ok', texto: `${d.empresas} empresas na base (${d.empresasNovas} novas, ${d.jaNoGestor} já no Gestor), ${d.contactos} contactos.` });
      onLancada?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setAAdicionar(false); }
  };
  const aviso = msg ? <ProspMsg msg={msg} /> : null;
  const tabela = fonteApify
    ? <ProspApifyResultados run={run} alvo={alvo} aCarregar={aLer} aAdicionar={aAdicionar} onAdicionar={adicionarApify} />
    : <ProspTabelaRun run={run} rows={rows} alvo={alvo} onOpen={onOpen} aCarregar={aLer} />;
  const painelConsulta = consulta ? (
    <>
      {aviso}
      <ProspConsulta consulta={consulta} alvo={alvo} curso={decisores} onOpen={onOpen} onEnriquecer={abrirEnriquecer} onDecisores={procurarDecisores} />
      {enriquecerIds && <ProspEnriquecer ids={enriquecerIds} onClose={() => setEnriquecerIds(null)} onFeito={() => carregarConsulta({ id: consulta.id, nome: consulta.nome })} />}
    </>
  ) : null;
  caixa.vista = painelConsulta;
  const resultados = painelConsulta || <>{aviso}{tabela}</>;
  const canalPessoas = alvo === 'contactos' && (fonte === 'google' || redeActual);
  const escolherDecisao = async (op) => {
    setADecidir(true);
    try {
      await prospEnviarDecisao(decisao, op);
      setMsg({ tipo: 'ok', texto: prospTextoDecisao(op) });
      setDecisao(null);
      onLancada?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setADecidir(false); }
  };
  const escolherEntrada = async (campanha, op) => {
    setADecidir(true);
    try {
      const r = await prospEnviarEntrada(campanha, op);
      setEntradas(atual => prospEntradasSem(atual, campanha.id));
      setMsg({ tipo: 'ok', texto: prospTextoResultadoEntrada(op, campanha.nome, r) });
      onLancada?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setADecidir(false); }
  };
  return (
    <>
      <ProspDecisaoSegmento pedido={decisao} entradas={entradas} aDecidir={aDecidir} onEscolher={escolherDecisao} onEntrada={escolherEntrada} onFechar={() => prospFecharDecisoes({ pedido: decisao, entradas, setDecisao, setEntradas, setMsg })} />
      {fonte === 'maps' && <ProspFormMaps busy={busy} alvo={alvo} caixa={caixa} resultados={resultados} onRun={(b) => correr(() => prospApi('/pesquisas/apify', { method: 'POST', body: comMarca(b) }))} />}
      {fonte === 'google' && !canalPessoas && <ProspFormGoogle busy={busy} caixa={caixa} resultados={resultados} onRun={(b) => correr(() => prospApi('/pesquisas/apify', { method: 'POST', body: comMarca({ ...b, modo: 'google' }) }))} />}
      {redeActual && !canalPessoas && <ProspFormRede rede={redeActual} busy={busy} caixa={caixa} resultados={resultados} onRun={(b) => correr(() => prospApi('/pesquisas/apify', { method: 'POST', body: comMarca({ ...b, modo: redeActual.id }) }))} />}
      {canalPessoas && <ProspColunas caixa={caixa} resultados={resultados} filtros={<ProspCanaisPessoa onIr={escolher} />} />}
      {fonte === 'apollo' && alvo === 'contactos' && <ProspApolloPessoas busy={busy} setBusy={setBusy} setMsg={setMsg} onDone={onLancada} marca={marca} caixa={caixa} aviso={aviso} />}
      {fonte === 'apollo' && alvo !== 'contactos' && <ProspApollo busy={busy} setBusy={setBusy} setMsg={setMsg} onDone={onLancada} marca={marca} caixa={caixa} aviso={aviso} />}
      {fonte === 'pagina' && <ProspDirectorio busy={aLer} caixa={caixa} resultados={resultados} onRun={(b) => correr(() => prospApi('/pesquisas/pagina', { method: 'POST', body: comMarca(b) }), 'A ler a página…')} />}
      {fonte === 'ficheiro' && <ProspFormFicheiro busy={busy} setBusy={setBusy} setMsg={setMsg} onDone={onLancada} marca={marca} caixa={caixa} aviso={aviso} alvo={alvo} />}
    </>
  );
}

const prospLinhas = { display: 'flex', flexDirection: 'column', gap: 12 };

function ProspColunas({ caixa, filtros, resultados, alvos }) {
  const [overAlvo, setOverAlvo] = React.useState('');
  const separadores = alvos || [{ id: 'empresas', label: 'Empresas' }, { id: 'contactos', label: 'Contactos' }];
  const alvoBtn = (id, label) => {
    const on = caixa.alvo === id;
    const hover = overAlvo === id && !on;
    return (
      <button key={id} type="button" onClick={() => caixa.onAlvo(id)}
        onMouseEnter={() => setOverAlvo(id)} onMouseLeave={() => setOverAlvo('')}
        style={{
          flex: 1, border: `1px solid ${on || hover ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 6,
          background: on ? 'color-mix(in oklch, var(--ai-500, #3859D0) 12%, #fff)' : (hover ? '#f4f7ff' : '#fff'),
          color: on ? 'var(--ai-500)' : 'var(--text)', padding: '8px 10px', cursor: 'pointer',
          fontSize: 13, fontWeight: 650, fontFamily: 'inherit',
          transition: 'background .12s, color .12s, border-color .12s',
        }}>{label}</button>
    );
  };
  const unico = !alvos && PROSP_FONTES_PESQUISA.length === 1;
  return (
    <div style={{ display: 'flex', gap: 20, alignItems: 'flex-start' }}>
      <aside style={{ width: 360, flexShrink: 0, display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div style={{ display: 'flex', gap: 8 }}>
            {separadores.map(s => alvoBtn(s.id, s.label))}
          </div>
          {caixa.nota && <div style={{ fontSize: 12, lineHeight: 1.45, color: 'var(--text-muted)' }}>{caixa.nota}</div>}
          {alvos ? (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>{filtros}</div>
          ) : unico ? (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
              {caixa.extra}
              {filtros}
            </div>
          ) : (
            <ProspMenuFontes activo={caixa.activo} onChange={caixa.onCanal} filtros={
              <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
                {caixa.extra}
                {filtros}
              </div>
            } />
          )}
        </div>
        {!alvos && caixa.guardadas && <ProspPesquisasGuardadas g={caixa.guardadas} />}
      </aside>
      <div style={{ flex: 1, minWidth: 0 }}>{resultados}</div>
    </div>
  );
}

function ProspSpin({ size = 16 }) {
  return <span style={{ width: size, height: size, borderRadius: '50%', border: '2px solid var(--border)', borderTopColor: 'var(--ai-500)', animation: 'spin .8s linear infinite', display: 'inline-block', flexShrink: 0 }} />;
}

function prospCurso(nota) {
  const n = String(nota || '');
  if (/gravar/i.test(n)) return { step: 3, total: 3 };
  if (/ScrapeGraph|bloqueou|páginas|website/i.test(n)) return { step: 2, total: 3 };
  return { step: 1, total: 3 };
}

function ProspOnda() {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', gap: 4, height: 48 }}>
      {[0, 1, 2, 3, 4, 5, 6].map(i => (
        <div key={i} style={{
          width: 4, height: 32, background: 'var(--ai-500, #3859D0)', borderRadius: 4,
          animation: 'ctdWave 1s ease-in-out infinite', animationDelay: `${i * 0.1}s`, transformOrigin: 'bottom',
        }} />
      ))}
    </div>
  );
}

function ProspGenBar({ nota }) {
  const { step, total } = prospCurso(nota);
  const pct = total > 0 ? Math.round((step / total) * 100) : 0;
  return (
    <div style={{ padding: 16, background: 'linear-gradient(135deg, #eef2ff 0%, #f5f3ff 100%)', border: '1px solid #c7d2fe', borderRadius: 8 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10, gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0, flex: 1 }}>
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 2, height: 20, flexShrink: 0 }}>
            {[0, 1, 2, 3, 4].map(i => (
              <div key={i} style={{
                width: 3, height: 16, background: '#6366f1', borderRadius: 2,
                animation: 'ctdWave 1s ease-in-out infinite', animationDelay: `${i * 0.12}s`, transformOrigin: 'bottom',
              }} />
            ))}
          </div>
          <div style={{ fontSize: 13, color: '#3730a3', fontWeight: 600, lineHeight: 1.4 }}>{nota || 'A processar…'}</div>
        </div>
        <div style={{ fontSize: 12, color: '#6366f1', fontFamily: 'var(--font-mono, monospace)', fontWeight: 600, flexShrink: 0 }}>{step}/{total}</div>
      </div>
      <div style={{ height: 6, background: '#e0e7ff', borderRadius: 3, overflow: 'hidden' }}>
        <div style={{ width: `${pct}%`, height: '100%', background: 'linear-gradient(90deg, #6366f1, #8b5cf6)', transition: 'width 0.3s ease' }} />
      </div>
    </div>
  );
}

function ProspACorrer({ nota, titulo = 'A EXTRAIR' }) {
  return (
    <div style={{ padding: '8px 0 16px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16, width: '100%', boxSizing: 'border-box' }}>
      <ProspOnda />
      <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.10em', color: 'var(--ai-500, #3859D0)', fontFamily: 'var(--font-mono, monospace)', textAlign: 'center' }}>{titulo}</div>
      <div style={{ width: '100%' }}><ProspGenBar nota={nota} /></div>
    </div>
  );
}

function ProspCentroTabela({ colSpan, children }) {
  return (
    <tr>
      <td colSpan={colSpan} style={{ padding: 0, border: 0, height: 280 }}>
        <div style={{ position: 'sticky', left: 0, width: '100cqw', height: 280, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{ width: 'min(480px, calc(100% - 32px))' }}>{children}</div>
        </div>
      </td>
    </tr>
  );
}

function ProspApifyResultados({ run, alvo, aCarregar = false, aAdicionar = false, onAdicionar }) {
  const preview = Array.isArray(run?.parametros?.preview) ? run.parametros.preview : [];
  const adicionados = new Set((run?.parametros?.adicionados || []).map(Number));
  const contactosAdicionados = new Set(run?.parametros?.contactos_adicionados || []);
  const pessoas = alvo === 'contactos';
  const linhas = pessoas
    ? preview.flatMap((item, itemIdx) => (item.contactos || []).map((c, cIdx) => ({
        key: `${itemIdx}:${cIdx}`, item, c,
        ja: adicionados.has(itemIdx) || contactosAdicionados.has(`${itemIdx}:${cIdx}`),
      })))
    : preview.map((item, itemIdx) => ({
        key: String(itemIdx), item,
        ja: adicionados.has(itemIdx),
      }));
  const [sel, setSel] = React.useState([]);
  const marcaSel = `${run?.id || ''}|${(run?.parametros?.adicionados || []).join(',')}|${(run?.parametros?.contactos_adicionados || []).join(',')}`;
  React.useEffect(() => { setSel([]); }, [marcaSel]);
  const livres = linhas.filter(l => !l.ja);
  const todas = livres.length > 0 && livres.every(l => sel.includes(l.key));
  const toggle = (key) => setSel(s => (s.includes(key) ? s.filter(x => x !== key) : [...s, key]));
  const vazio = (v) => prospSemAsteriscos(v) || '—';
  const emailsDe = (item) => (item.contactos || []).map(c => prospSemAsteriscos(c.email) || prospNomeDe(c)).filter(Boolean).join(', ');
  const adicionar = () => {
    if (!sel.length || !onAdicionar) return;
    if (pessoas) {
      const map = new Map();
      sel.forEach(key => {
        const [i, c] = key.split(':').map(Number);
        if (!map.has(i)) map.set(i, []);
        map.get(i).push(c);
      });
      onAdicionar([...map.entries()].map(([item, contactos]) => ({ item, contactos })));
    } else {
      onAdicionar(sel.map(key => ({ item: Number(key) })));
    }
  };
  const erro = run?.estado === 'erro';
  const cols = pessoas
    ? [['', 36], ['Contacto', 180], ['Cargo', 140], ['Email', 200], ['Telefone', 130], ['LinkedIn', 220], ['Empresa', 180], ['Morada', 200], ['Código postal', 110], ['Cidade', 120], ['País', 60]]
    : [['', 36], ['Empresa', 200], ['Website', 220], ['Telefone', 130], ['Morada', 200], ['Código postal', 110], ['Cidade', 120], ['País', 60], ['Contactos', 220]];
  const largura = cols.reduce((s, [, w]) => s + w, 0);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0, width: '100%' }}>
      {sel.length > 0 && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap', background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: '12px 14px' }}>
          <strong style={{ fontSize: 13 }}>{sel.length} {pessoas ? (sel.length === 1 ? 'contacto' : 'contactos') : (sel.length === 1 ? 'empresa' : 'empresas')}</strong>
          <button type="button" className="btn btn-sm btn-ai" disabled={aAdicionar} onClick={adicionar}>
            {aAdicionar ? 'A adicionar…' : 'Adicionar à base de prospeção'}
          </button>
        </div>
      )}
      <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, minHeight: 280, overflowX: 'auto', width: '100%', maxWidth: '100%', containerType: 'inline-size' }}>
      {aCarregar && linhas.length > 0 && (
        <div style={{ padding: 12, borderBottom: '1px solid var(--border)' }}>
          <ProspGenBar nota={run?.notas || 'A pesquisar…'} />
        </div>
      )}
      {erro && <div style={{ padding: '28px 16px', textAlign: 'center', color: '#b91c1c', fontSize: 13, lineHeight: 1.45 }}>{run.notas || 'A pesquisa falhou.'}</div>}
      {!erro && run?.estado === 'concluido' && (
        <div style={{ padding: '12px 14px', fontSize: 13, color: 'var(--text-muted)', borderBottom: '1px solid var(--border)' }}>{run.notas || 'Nada entrou na base. Escolhe o que queres adicionar.'}</div>
      )}
      <table style={{ width: largura, minWidth: '100%', tableLayout: 'fixed', borderCollapse: 'collapse' }}>
        <colgroup>{cols.map(([label, w], i) => <col key={label || i} style={{ width: w }} />)}</colgroup>
        <thead>
          <tr>
            <th style={{ ...prospTh, background: '#fff' }}>{livres.length > 0 && <input type="checkbox" checked={todas} onChange={() => setSel(todas ? [] : livres.map(l => l.key))} />}</th>
            {cols.slice(1).map(([label]) => <th key={label} style={{ ...prospTh, background: '#fff' }}>{label}</th>)}
          </tr>
        </thead>
        <tbody>
          {linhas.map(l => {
            const e = l.item.empresa || {};
            return (
              <tr key={l.key}>
                <td style={prospTd}>{l.ja ? <span style={{ fontSize: 11, color: 'var(--text-dim)' }}>Na base</span> : <input type="checkbox" checked={sel.includes(l.key)} onChange={() => toggle(l.key)} />}</td>
                {pessoas ? (
                  <>
                    <td style={{ ...prospTd, fontWeight: 650 }}>{vazio(l.c.nome_completo || l.c.nome)}</td>
                    <td style={prospTd}>{vazio(l.c.cargo)}</td>
                    <td style={prospTd}>{vazio(l.c.email)}</td>
                    <td style={prospTd}>{vazio(l.c.telemovel)}</td>
                    <td style={prospTd}>{l.c.linkedin_url ? <a href={l.c.linkedin_url} target="_blank" rel="noreferrer" style={{ color: 'var(--ai-500)', textDecoration: 'none' }}>{l.c.linkedin_url}</a> : '—'}</td>
                    <td style={prospTd}>{vazio(e.nome)}</td>
                    <td style={prospTd}>{vazio(e.morada)}</td>
                    <td style={prospTd}>{vazio(e.codigo_postal)}</td>
                    <td style={prospTd}>{vazio(e.cidade)}</td>
                    <td style={prospTd}>{vazio(e.pais)}</td>
                  </>
                ) : (
                  <>
                    <td style={{ ...prospTd, fontWeight: 650 }}>{vazio(e.nome)}</td>
                    <td style={prospTd}>{e.website ? <a href={e.website} target="_blank" rel="noreferrer" style={{ color: 'var(--ai-500)', textDecoration: 'none' }}>{e.website}</a> : '—'}</td>
                    <td style={prospTd}>{vazio(e.telefone)}</td>
                    <td style={prospTd}>{vazio(e.morada)}</td>
                    <td style={prospTd}>{vazio(e.codigo_postal)}</td>
                    <td style={prospTd}>{vazio(e.cidade)}</td>
                    <td style={prospTd}>{vazio(e.pais)}</td>
                    <td style={prospTd}>{vazio(emailsDe(l.item))}</td>
                  </>
                )}
              </tr>
            );
          })}
          {!linhas.length && (aCarregar
            ? <ProspCentroTabela colSpan={cols.length}><ProspACorrer nota={run?.notas || 'A pesquisar…'} titulo="A PESQUISAR" /></ProspCentroTabela>
            : <tr><td colSpan={cols.length} style={{ ...prospTd, textAlign: 'center', color: 'var(--text-muted)', padding: 28 }}>{run?.notas || 'Sem resultados.'}</td></tr>
          )}
        </tbody>
      </table>
      </div>
    </div>
  );
}

function ProspConsulta({ consulta, alvo, curso, onOpen, onEnriquecer, onDecisores }) {
  const pessoas = alvo === 'contactos';
  const rows = pessoas ? (consulta.contactos || []) : (consulta.empresas || []);
  const [sel, setSel] = React.useState(() => new Set());
  const marcaSel = `${consulta.id}|${pessoas ? 'c' : 'e'}|${rows.length}`;
  React.useEffect(() => { setSel(new Set()); }, [marcaSel]);
  const decisores = (consulta.contactos || []).filter(c => c.papel === 'decisor' || c.papel === 'influenciador');
  const aCorrer = curso?.estado === 'a_correr';
  const toggle = (id) => setSel(prev => { const n = new Set(prev); if (n.has(id)) n.delete(id); else n.add(id); return n; });
  const todos = rows.length > 0 && rows.every(r => sel.has(r.id));
  const cols = pessoas ? PROSP_COLS_CONT : [
    ['Empresa', 220], ['NIF', 130], ['Website', 190], ['Resumo do site', 420], ['Telefone', 150], ['Morada', 280],
    ['Código postal', 120], ['Cidade', 140], ['Distrito', 140], ['Zona', 160], ['País', 64],
    ['Funcionários', 110], ['Equipa', 160], ['Comercial', 170], ['Contactos', 110], ['Marca', 110],
    ['Sector', 160], ['Segmento', 220], ['Estado', 120], ['Fonte', 240],
  ];
  const largura = 36 + cols.reduce((s, [, w]) => s + w, 0);
  const td = prospTd;
  const cel = (v) => <td style={{ ...td, color: v ? 'var(--text)' : 'var(--text-dim)' }}>{prospTxt(v)}</td>;
  const site = (r) => r.website || (r.dominio ? `https://${r.dominio}` : '');
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0, width: '100%' }}>
      <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 10 }}>
        <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>
          <strong style={{ color: 'var(--text)' }}>{consulta.nome || 'Pesquisa'}</strong>
          {` · ${prospNum((consulta.empresas || []).length)} empresas · ${prospNum((consulta.contactos || []).length)} contactos · ${prospNum(decisores.length)} decisores e influenciadores`}
        </div>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          <button type="button" className="btn btn-sm btn-ai" disabled={aCorrer} onClick={onDecisores}>{aCorrer ? 'A procurar…' : 'Procurar decisores no Apollo'}</button>
          <button type="button" className="btn btn-sm" disabled={!decisores.length || aCorrer} onClick={() => onEnriquecer(decisores.map(c => c.id))}>Enriquecer emails e telemóveis</button>
          {pessoas && sel.size > 0 && <button type="button" className="btn btn-sm" onClick={() => onEnriquecer([...sel])}>Enriquecer seleccionados</button>}
        </div>
        <div style={{ fontSize: 12, lineHeight: 1.45, color: 'var(--text-muted)' }}>A procura na Apollo não gasta créditos e grava só decisores e influenciadores. O email verified e o telemóvel pedem-se na janela seguinte.</div>
        {aCorrer && <ProspEnriquecerCurso titulo="A PROCURAR DECISORES" nota={curso?.notas} feitos={curso?.parametros?.progresso?.feitos} total={curso?.parametros?.progresso?.total} />}
      </div>
      <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, overflowX: 'auto', width: '100%', maxWidth: '100%' }}>
        <table style={{ width: largura, tableLayout: 'fixed', borderCollapse: 'collapse' }}>
          <colgroup>
            <col style={{ width: 36 }} />
            {cols.map(([label, w]) => <col key={label} style={{ width: w }} />)}
          </colgroup>
          <thead>
            <tr>
              <th style={{ ...prospTh, width: 36, background: '#fff' }}>{rows.length > 0 && <input type="checkbox" checked={todos} onChange={() => setSel(todos ? new Set() : new Set(rows.map(r => r.id)))} />}</th>
              {cols.map(([label]) => <th key={label} style={{ ...prospTh, background: '#fff' }}>{label}</th>)}
            </tr>
          </thead>
          <tbody>
            {pessoas ? rows.map(r => (
              <tr key={r.id} className="prosp-row" onClick={() => onOpen?.({ id: r.empresa_id, nome: r.empresa_nome, pais: r.pais, fonte: r.fonte, estado: r.empresa_estado })} style={{ cursor: 'pointer' }}>
                <td style={td} onClick={ev => ev.stopPropagation()}><input type="checkbox" checked={sel.has(r.id)} onChange={() => toggle(r.id)} /></td>
                <td style={{ ...td, fontWeight: 650 }}>{prospNomeDe(r) || '—'}</td>
                {cel(r.cargo && r.cargo !== 'Contacto publicado' ? r.cargo : '')}
                <ProspPapelCel row={r} td={td} />
                <td style={{ ...td, color: r.email ? 'var(--text)' : 'var(--text-dim)' }}>
                  <div>{prospTxt(r.email)}</div>
                  {r.confianca != null && <div style={{ marginTop: 2, fontSize: 11, fontWeight: 700, color: '#3730a3' }}>Confiança {r.confianca}%</div>}
                </td>
                {cel(r.telemovel_e164 || r.telemovel || r.empresa_telefone_e164 || r.empresa_telefone)}
                <td style={td}>{r.linkedin_url ? <a href={r.linkedin_url} target="_blank" rel="noreferrer" onClick={ev => ev.stopPropagation()} style={{ color: 'var(--ai-500)', textDecoration: 'none' }}>{r.linkedin_url}</a> : <span style={{ color: 'var(--text-dim)' }}>—</span>}</td>
                {cel(r.empresa_nome)}
                <ProspSegmentoCel row={r} td={td} />
                <td style={td}><ProspBadge estado={r.empresa_estado} /></td>
                {cel(r.morada)}
                {cel(r.codigo_postal)}
                {cel(r.cidade)}
                {cel(r.zona)}
                {cel(r.pais)}
                {cel(prospEquipaLista(r.atribuicoes))}
                {cel(prospComercialLista(r.atribuicoes))}
                {cel(r.marca_alvo)}
                <ProspFonteCel fonte={r.fonte} origem={r.origem} href={r.origem_href} />
              </tr>
            )) : rows.map(r => (
              <tr key={r.id} className="prosp-row" onClick={() => onOpen?.(r)} style={{ cursor: 'pointer' }}>
                <td style={td} onClick={ev => ev.stopPropagation()}><input type="checkbox" checked={sel.has(r.id)} onChange={() => toggle(r.id)} /></td>
                <td style={{ ...td, fontWeight: 650 }}>{r.nome || '—'}</td>
                {cel(r.nif)}
                <td style={td}>{site(r) ? <a href={/^https?:/.test(r.website || '') ? r.website : `https://${r.dominio || r.website}`} target="_blank" rel="noreferrer" onClick={ev => ev.stopPropagation()} style={{ color: 'var(--ai-500)', textDecoration: 'none' }}>{r.website || r.dominio}</a> : <span style={{ color: 'var(--text-dim)' }}>—</span>}</td>
                <ProspPerfilCel row={r} td={td} />
                {cel(r.telefone_e164 || r.telefone)}
                {cel(r.morada)}
                {cel(r.codigo_postal)}
                {cel(r.cidade)}
                {cel(r.distrito)}
                {cel(r.zona)}
                {cel(r.pais)}
                {cel(r.funcionarios)}
                {cel(prospEquipaLista(r.atribuicoes))}
                {cel(prospComercialLista(r.atribuicoes))}
                {cel(prospContactos(r))}
                {cel(r.marca_alvo)}
                {cel(r.industria)}
                <ProspSegmentoCel row={r} td={td} />
                <td style={td}><ProspBadge estado={r.estado} /></td>
                <ProspFonteCel fonte={r.fonte} origem={r.origem} href={r.origem_href} />
              </tr>
            ))}
            {consulta.aCarregar && !rows.length && <tr><td colSpan={cols.length + 1} style={{ ...td, padding: 36 }}><div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', gap: 10 }}><ProspSpin />A carregar a pesquisa…</div></td></tr>}
            {!consulta.aCarregar && !rows.length && <tr><td colSpan={cols.length + 1} style={{ ...td, textAlign: 'center', color: 'var(--text-muted)', padding: 28 }}>{pessoas ? 'Sem contactos nesta pesquisa.' : 'Esta pesquisa ainda não tem empresas. Quando a execução gravar, usa Juntar resultados.'}</td></tr>}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function ProspTabelaRun({ run, rows, alvo, onOpen, aCarregar = false }) {
  const pessoas = alvo === 'contactos';
  const cols = pessoas
    ? PROSP_COLS_CONT.filter(([label]) => label !== 'Fonte')
    : PROSP_COLS_EMP.filter(([label]) => !['Contactos', 'Estado', 'Fonte', 'Marca', 'Equipa', 'Comercial'].includes(label));
  const largura = cols.reduce((s, [, w]) => s + w, 0);
  const erro = run?.estado === 'erro';
  const vazio = run?.fonte === 'validacao'
    ? (run.notas || 'Validação concluída. O estado actualiza na lista.')
    : (run?.estado === 'concluido' && run?.notas) || 'Sem resultados.';
  const site = (r) => r.website || (r.dominio ? `https://${r.dominio}` : '');
  const vazioCel = (v) => prospSemAsteriscos(v) || '—';
  return (
    <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, minHeight: 280, overflowX: 'auto', width: '100%', maxWidth: '100%', containerType: 'inline-size' }}>
      {aCarregar && rows.length > 0 && (
        <div style={{ padding: 12, borderBottom: '1px solid var(--border)' }}>
          <ProspGenBar nota={run?.notas || 'A pesquisar…'} />
        </div>
      )}
      {erro && (
        <div style={{ padding: '28px 16px', textAlign: 'center', color: '#b91c1c', fontSize: 13, lineHeight: 1.45 }}>{run.notas || 'A leitura falhou.'}</div>
      )}
      <table style={{ width: largura, minWidth: '100%', tableLayout: 'fixed', borderCollapse: 'collapse' }}>
        <colgroup>{cols.map(([label, w]) => <col key={label} style={{ width: w }} />)}</colgroup>
        <thead>
          <tr>{cols.map(([label]) => <th key={label} style={{ ...prospTh, background: '#fff' }}>{label}</th>)}</tr>
        </thead>
        <tbody>
          {run && run.estado !== 'erro' && run.fonte !== 'validacao' && (pessoas ? rows.map(r => (
            <tr key={r.id} className="prosp-row" onClick={() => onOpen?.({ id: r.empresa_id, nome: r.empresa_nome, pais: r.pais, fonte: r.fonte, estado: r.empresa_estado })} style={{ cursor: 'pointer' }}>
              <td style={{ ...prospTd, fontWeight: 650 }}>{prospNomeDe(r) || '—'}</td>
              <td style={prospTd}>{vazioCel(r.cargo && r.cargo !== 'Contacto publicado' ? r.cargo : '')}</td>
              <td style={prospTd}>{vazioCel(prospPapel(r))}{r.cargo_crm ? <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>{r.cargo_crm}</div> : null}</td>
              <td style={prospTd}>{vazioCel(r.email)}</td>
              <td style={prospTd}>{vazioCel(r.telemovel_e164 || r.telemovel || r.empresa_telefone_e164 || r.empresa_telefone)}</td>
              <td style={prospTd}>{r.linkedin_url ? <a href={r.linkedin_url} target="_blank" rel="noreferrer" onClick={ev => ev.stopPropagation()} style={{ color: 'var(--ai-500)', textDecoration: 'none' }}>{r.linkedin_url}</a> : '—'}</td>
              <td style={prospTd}>{vazioCel(r.empresa_nome)}</td>
              <td style={prospTd}>{vazioCel(prospSegmento(r))}</td>
              <td style={prospTd}><ProspBadge estado={r.empresa_estado || r.estado} /></td>
              <td style={prospTd}>{vazioCel(r.morada)}</td>
              <td style={prospTd}>{vazioCel(r.codigo_postal)}</td>
              <td style={prospTd}>{vazioCel(r.cidade)}</td>
              <td style={prospTd}>{vazioCel(r.zona)}</td>
              <td style={prospTd}>{vazioCel(r.pais)}</td>
              <td style={prospTd}>{vazioCel(prospEquipaLista(r.atribuicoes))}</td>
              <td style={prospTd}>{vazioCel(prospComercialLista(r.atribuicoes))}</td>
              <td style={prospTd}>{vazioCel(r.marca_alvo)}</td>
            </tr>
          )) : rows.map(r => (
            <tr key={r.id} className="prosp-row" onClick={() => onOpen?.(r)} style={{ cursor: 'pointer' }}>
              <td style={{ ...prospTd, fontWeight: 650 }}>{r.nome || '—'}</td>
              <td style={prospTd}>{vazioCel(r.nif)}</td>
              <td style={prospTd}>{site(r) ? <a href={site(r)} target="_blank" rel="noreferrer" onClick={ev => ev.stopPropagation()} style={{ color: 'var(--ai-500)', textDecoration: 'none' }}>{r.website || r.dominio}</a> : '—'}</td>
              <ProspPerfilCel row={r} td={prospTd} />
              <td style={prospTd}>{vazioCel(r.telefone_e164 || r.telefone)}</td>
              <td style={prospTd}>{vazioCel(r.morada)}</td>
              <td style={prospTd}>{vazioCel(r.codigo_postal)}</td>
              <td style={prospTd}>{vazioCel(r.cidade)}</td>
              <td style={prospTd}>{vazioCel(r.zona)}</td>
              <td style={prospTd}>{vazioCel(r.pais)}</td>
              <td style={prospTd}>{vazioCel(r.industria)}</td>
              <td style={prospTd}>{vazioCel(prospSegmento(r))}</td>
            </tr>
          )))}
          {aCarregar && !rows.length && (
            <ProspCentroTabela colSpan={cols.length}>
              <ProspACorrer nota={run?.notas || 'A ler a página…'} titulo={run?.fonte === 'pagina' ? 'A EXTRAIR CONTACTOS' : 'A PESQUISAR'} />
            </ProspCentroTabela>
          )}
          {!aCarregar && !erro && (!run || run.fonte === 'validacao' || !rows.length) && (
            <tr><td colSpan={cols.length} style={{ ...prospTd, textAlign: 'center', color: 'var(--text-muted)', padding: 28 }}>{vazio}</td></tr>
          )}
        </tbody>
      </table>
    </div>
  );
}

function ProspCanaisPessoa({ onIr }) {
  return (
    <>
      <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Este canal encontra a página ou o site da empresa. Para pessoas, usa um canal que as traz.</div>
      <ProspEscolha on={false} label="Apollo" hint="Cargo, email, telemóvel e LinkedIn." onClick={() => onIr('apollo')} />
      <ProspEscolha on={false} label="Google Maps" hint="Decisores e emails do website." onClick={() => onIr('maps')} />
    </>
  );
}

function ProspTrilho({ segmentos, nota, extra }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px', background: '#fff', borderRadius: 8, border: '1px solid var(--border)', boxShadow: '0 1px 4px rgba(40,41,61,0.04), 0 4px 16px rgba(96,97,112,0.08)', flexWrap: 'wrap' }}>
      {segmentos.map((seg, i) => {
        const ultimo = i === segmentos.length - 1;
        return (
          <React.Fragment key={i}>
            {seg.onClick && !ultimo ? (
              <button type="button" onClick={seg.onClick} style={{ background: 'transparent', border: 0, cursor: 'pointer', padding: 0, fontSize: 12, color: 'var(--ai-500)' }}>{seg.label}</button>
            ) : (
              <span style={{ fontSize: 12, color: 'var(--text)', fontWeight: ultimo ? 700 : 400 }}>{seg.label}</span>
            )}
            {!ultimo && <span style={{ color: 'var(--text-dim)', fontSize: 12 }}>›</span>}
          </React.Fragment>
        );
      })}
      {nota}
      {extra && <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 8 }}>{extra}</div>}
    </div>
  );
}

const MAPS_DEPTS = [
  { id: 'c_suite', label: 'Direcção' },
  { id: 'sales', label: 'Comercial' },
  { id: 'marketing', label: 'Marketing' },
  { id: 'operations', label: 'Produção' },
  { id: 'finance', label: 'Financeiro' },
];

function ProspFormMaps({ busy, onRun, caixa, resultados, alvo }) {
  const [b, setB] = React.useState({ pesquisas: '', localizacao: '', pais: 'PT', max_por_pesquisa: 50, extrair_contactos: false, leads: false, leads_por_empresa: 2, leads_departamentos: [] });
  const s = (k) => (ev) => setB(p => ({ ...p, [k]: ev.target.type === 'checkbox' ? ev.target.checked : ev.target.value }));
  const n = b.pesquisas.split(/[,;\n]/).filter(x => x.trim()).length;
  const reportar = caixa.onRascunho;
  React.useEffect(() => {
    const termos = b.pesquisas.split(/[,;\n]/).map(x => x.trim()).filter(Boolean);
    reportar?.({
      fonte: 'maps', alvo: caixa.alvo, pode: termos.length > 0 && Boolean((b.localizacao || '').trim()),
      parametros: b, rotulo: [termos[0], (b.localizacao || '').trim()].filter(Boolean).join(' · ') || 'Google Maps',
    });
  }, [b, caixa.alvo, reportar]);
  React.useEffect(() => {
    const p = caixa.pedido;
    if (!p || p.fonte !== 'maps') return;
    const f = p.parametros || {};
    setB({
      pesquisas: f.pesquisas || '', localizacao: f.localizacao || '', pais: f.pais || 'PT',
      max_por_pesquisa: f.max_por_pesquisa || 50, extrair_contactos: !!f.extrair_contactos, leads: !!f.leads,
      leads_por_empresa: f.leads_por_empresa || 2, leads_departamentos: Array.isArray(f.leads_departamentos) ? f.leads_departamentos : [],
    });
  }, [caixa.pedido && caixa.pedido.n]);
  const toggleDept = (id) => setB(p => ({ ...p, leads_departamentos: p.leads_departamentos.includes(id) ? p.leads_departamentos.filter(x => x !== id) : [...p.leads_departamentos, id] }));
  return (
    <ProspColunas caixa={caixa} resultados={resultados} filtros={
      <>
        <div style={prospLinhas}>
          <ProspField label="O que procurar" hint="Separa por vírgulas — ex.: gráfica, empresa de reclamos, decoração de interiores"><input style={prospInput} value={b.pesquisas} onChange={s('pesquisas')} /></ProspField>
          <ProspField label="Onde" hint='Ex.: "Braga, Portugal" ou "Madrid, Spain"'><input style={prospInput} value={b.localizacao} onChange={s('localizacao')} /></ProspField>
          <ProspDrop label="País" value={b.pais} onChange={v => setB(p => ({ ...p, pais: v }))} options={PROSP_PAISES} />
          <ProspField label="Máximo por pesquisa" hint="Até 500 no total. A procura não grava."><input type="number" min="1" max="500" style={prospInput} value={b.max_por_pesquisa} onChange={s('max_por_pesquisa')} /></ProspField>
        </div>
        {alvo === 'contactos' && <div style={{ fontSize: 11, fontWeight: 650, letterSpacing: '.04em', textTransform: 'uppercase', color: 'var(--text-muted)' }}>Pessoa</div>}
        <ProspEscolha on={b.extrair_contactos} label="Emails do website" hint="Lê o site do lugar. Entram na base só se os escolheres." onClick={() => setB(p => ({ ...p, extrair_contactos: !p.extrair_contactos }))} />
        <ProspEscolha on={b.leads} label="Decisores" hint="Nome, cargo, email e LinkedIn." onClick={() => setB(p => ({ ...p, leads: !p.leads }))} />
        {b.leads && (
          <>
            <ProspField label="Decisores por empresa" hint="Máximo 5"><input type="number" min="1" max="5" style={prospInput} value={b.leads_por_empresa} onChange={s('leads_por_empresa')} /></ProspField>
            {MAPS_DEPTS.map(c => <ProspEscolha key={c.id} on={b.leads_departamentos.includes(c.id)} label={c.label} onClick={() => toggleDept(c.id)} />)}
            <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Sem departamento seleccionado, traz de todos.</div>
          </>
        )}
        <div><button type="button" className="btn btn-ai" disabled={busy || !n || !b.localizacao.trim() || (alvo === 'contactos' && !b.extrair_contactos && !b.leads)} onClick={() => onRun(b)}>{busy ? 'A lançar…' : (alvo === 'contactos' ? 'Pesquisar contactos' : `Pesquisar ${n || ''} termo${n === 1 ? '' : 's'}`)}</button></div>
      </>
    } />
  );
}

function ProspFormRede({ rede, busy, onRun, caixa, resultados }) {
  const [b, setB] = React.useState({ pesquisas: '', localizacao: '', pais: 'PT', max_resultados: 20 });
  const s = (k) => (ev) => setB(p => ({ ...p, [k]: ev.target.value }));
  const n = b.pesquisas.split(/[,;\n]/).filter(x => x.trim()).length;
  return (
    <ProspColunas caixa={caixa} resultados={resultados} filtros={
      <>
        <div style={prospLinhas}>
          <ProspField label="Segmento" hint="Separa por vírgulas — ex.: decoração de interiores, empresa de reclamos"><input style={prospInput} value={b.pesquisas} onChange={s('pesquisas')} /></ProspField>
          <ProspField label="Zona" hint="Opcional. Ex.: Braga, Porto, Madrid"><input style={prospInput} value={b.localizacao} onChange={s('localizacao')} /></ProspField>
          <ProspDrop label="País" value={b.pais} onChange={v => setB(p => ({ ...p, pais: v }))} options={PROSP_PAISES} />
          <ProspField label="Máximo" hint={rede.id === 'facebook' ? 'Até 50 no total. A procura não grava.' : 'Até 50 por termo. A procura não grava.'}><input type="number" min="1" max="50" style={prospInput} value={b.max_resultados} onChange={s('max_resultados')} /></ProspField>
        </div>
        <div><button type="button" className="btn btn-ai" disabled={busy || !n} onClick={() => onRun(b)}>{busy ? 'A lançar…' : `Pesquisar ${n || ''} termo${n === 1 ? '' : 's'}`}</button></div>
      </>
    } />
  );
}

function ProspFormGoogle({ busy, onRun, caixa, resultados }) {
  const [b, setB] = React.useState({ pesquisas: '', localizacao: '', pais: 'PT', max_paginas: 1 });
  const s = (k) => (ev) => setB(p => ({ ...p, [k]: ev.target.value }));
  const n = b.pesquisas.split(/[,;\n]/).filter(x => x.trim()).length;
  return (
    <ProspColunas caixa={caixa} resultados={resultados} filtros={
      <>
        <div style={prospLinhas}>
          <ProspField label="O que procurar" hint="Um termo por linha ou separados por vírgulas — até 10."><textarea style={{ ...prospInput, minHeight: 72, resize: 'vertical' }} value={b.pesquisas} onChange={s('pesquisas')} /></ProspField>
          <ProspField label="Zona" hint="Acrescentada a cada termo. Ex.: Braga"><input style={prospInput} value={b.localizacao} onChange={s('localizacao')} /></ProspField>
          <ProspDrop label="País" value={b.pais} onChange={v => setB(p => ({ ...p, pais: v }))} options={PROSP_PAISES} />
          <ProspField label="Páginas por termo" hint="Cerca de 10 resultados por página, até 3. A procura não grava."><input type="number" min="1" max="3" style={prospInput} value={b.max_paginas} onChange={s('max_paginas')} /></ProspField>
        </div>
        <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Uma empresa por site, sem redes sociais nem directórios.</div>
        <div><button type="button" className="btn btn-ai" disabled={busy || !n} onClick={() => onRun(b)}>{busy ? 'A lançar…' : `Pesquisar ${n || ''} termo${n === 1 ? '' : 's'}`}</button></div>
      </>
    } />
  );
}

const APOLLO_TIPOS = [
  { id: 'direccao', label: 'Direcção', hint: 'Gerência e administração' },
  { id: 'comercial', label: 'Comercial', hint: 'Vendas' },
  { id: 'compras', label: 'Compras', hint: 'Aprovisionamento' },
  { id: 'marketing', label: 'Marketing', hint: 'Marketing e comunicação' },
  { id: 'producao', label: 'Produção', hint: 'Operações' },
  { id: 'financeiro', label: 'Financeiro', hint: 'Finanças' },
];
const APOLLO_EMPREGADOS = [
  { id: '1,10', label: '1–10' },
  { id: '11,20', label: '11–20' },
  { id: '21,50', label: '21–50' },
  { id: '51,100', label: '51–100' },
  { id: '101,200', label: '101–200' },
  { id: '201,500', label: '201–500' },
  { id: '501,1000', label: '501–1.000' },
  { id: '1001,2000', label: '1.001–2.000' },
];
const APOLLO_SENIORIDADES = [
  { id: 'owner', label: 'Dono' },
  { id: 'c_suite', label: 'C-level' },
  { id: 'vp', label: 'VP' },
  { id: 'director', label: 'Director' },
  { id: 'manager', label: 'Manager' },
  { id: 'senior', label: 'Sénior' },
];
const GESTOR_CAMPOS = [
  { id: 'website', label: 'Website' },
  { id: 'morada', label: 'Morada' },
  { id: 'codigo_postal', label: 'Código postal' },
  { id: 'cidade', label: 'Cidade' },
  { id: 'nome', label: 'Nome oficial' },
];

function ProspEscolha({ on, label, hint, onClick }) {
  return (
    <button type="button" onClick={onClick} className="prosp-chip" style={{
      textAlign: 'left', padding: '10px 12px', borderRadius: 8, cursor: 'pointer', fontFamily: 'inherit',
      width: '100%', border: `1px solid ${on ? 'var(--ai-500)' : 'var(--border)'}`,
      background: on ? 'color-mix(in oklch, var(--ai-500, #3859D0) 10%, #fff)' : '#fff', color: 'var(--text)',
      transition: 'background .12s, border-color .12s',
    }}>
      <div style={{ fontSize: 13, fontWeight: 650, color: on ? 'var(--ai-500)' : 'var(--text)' }}>{label}</div>
      {hint && <div style={{ fontSize: 12, lineHeight: 1.4, color: 'var(--text-muted)', marginTop: 3 }}>{hint}</div>}
    </button>
  );
}

function ProspPais({ value, onChange }) {
  return (
    <ProspField label="País">
      <select style={prospInput} value={value} onChange={ev => onChange(ev.target.value)}>
        {PROSP_PAISES.map(p => <option key={p.value} value={p.value}>{p.label}</option>)}
      </select>
    </ProspField>
  );
}

function ProspApolloPessoas({ busy, setBusy, setMsg, onDone, marca, caixa, aviso }) {
  const [tarifa, setTarifa] = React.useState(null);
  React.useEffect(() => { prospApi('/apollo/custo').then(setTarifa).catch(() => {}); }, []);
  const [b, setB] = React.useState({ pais: 'PT', nome: '', localizacoes: '', palavras_chave: '', max: 25 });
  const [tipos, setTipos] = React.useState([]);
  const [senioridades, setSenioridades] = React.useState([]);
  const [res, setRes] = React.useState(null);
  const [sel, setSel] = React.useState([]);
  const [dados, setDados] = React.useState({ linkedin: true, email: false, telemovel: false });
  const [modoEmpresa, setModoEmpresa] = React.useState('apollo');
  const [segmento, setSegmento] = React.useState('');
  const [decisao, setDecisao] = React.useState(null);
  const [porEntrar, setPorEntrar] = React.useState(null);
  const [aDecidir, setADecidir] = React.useState(false);
  const [qEmp, setQEmp] = React.useState('');
  const [achadas, setAchadas] = React.useState([]);
  const [empresaAlvo, setEmpresaAlvo] = React.useState(null);
  const s = (k) => (ev) => setB(p => ({ ...p, [k]: ev.target.value }));
  const toggle = (lista, setLista, id) => setLista(lista.includes(id) ? lista.filter(x => x !== id) : [...lista, id]);
  const reportar = caixa.onRascunho;
  React.useEffect(() => {
    const nomePessoa = (b.nome || '').trim();
    const pode = tipos.length > 0 || Boolean(nomePessoa || (b.palavras_chave || '').trim() || (b.localizacoes || '').trim());
    reportar?.({
      fonte: 'apollo', alvo: 'contactos', pode,
      parametros: { ...b, tipos, senioridades },
      rotulo: nomePessoa || (b.palavras_chave || '').trim() || (b.localizacoes || '').trim() || 'Apollo · contactos',
    });
  }, [b, tipos, senioridades, reportar]);
  React.useEffect(() => {
    const p = caixa.pedido;
    if (!p || p.fonte !== 'apollo' || p.alvo !== 'contactos') return;
    const f = p.parametros || {};
    setB({ pais: f.pais || 'PT', nome: f.nome || '', localizacoes: f.localizacoes || '', palavras_chave: f.palavras_chave || '', max: f.max || 25 });
    setTipos(Array.isArray(f.tipos) ? f.tipos : []);
    setSenioridades(Array.isArray(f.senioridades) ? f.senioridades : []);
  }, [caixa.pedido && caixa.pedido.n]);
  React.useEffect(() => {
    if (modoEmpresa !== 'existente') return undefined;
    const termo = qEmp.trim();
    if (termo.length < 2 || empresaAlvo) { setAchadas([]); return undefined; }
    let stop = false;
    const t = setTimeout(() => {
      prospApi('/empresas', { query: { q: termo, limit: 8, ordem: 'nome' } })
        .then(d => { if (!stop) setAchadas(d.rows || []); })
        .catch(() => { if (!stop) setAchadas([]); });
    }, 180);
    return () => { stop = true; clearTimeout(t); };
  }, [qEmp, modoEmpresa, empresaAlvo]);
  const procurar = async () => {
    setBusy(true); setMsg(null); setRes(null); setSel([]);
    try {
      const d = await prospApi('/pesquisas/apollo/pessoas/preview', { method: 'POST', body: { filtros: { ...b, tipos, senioridades }, max: Number(b.max) || 25 } });
      setRes(d);
      setSel([]);
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setBusy(false); }
  };
  const guardar = async () => {
    const pessoas = sel.map(i => res.pessoas[i]).filter(Boolean);
    if (!pessoas.length) return;
    if (modoEmpresa === 'existente' && !empresaAlvo) return;
    const ja = pessoas.filter(p => p.ja_na_base);
    if (ja.length) {
      const rotulo = (p) => prospNomeDe(p) || 'contacto';
      const linhas = ja.slice(0, 8).map(p => (p.ja_empresa ? `${rotulo(p)} (${p.ja_empresa})` : rotulo(p))).join('\n');
      const mais = ja.length > 8 ? `\ne mais ${ja.length - 8}` : '';
      const titulo = ja.length === 1
        ? 'Este contacto já está na base de prospeção:'
        : `${ja.length} contactos já estão na base de prospeção:`;
      if (!window.confirm(`${titulo}\n${linhas}${mais}\n\nQueres gravar na mesma? A ficha existente é actualizada.`)) return;
    }
    const seg = prospSegPartes(segmento);
    setBusy(true); setMsg(null);
    try {
      const d = await prospApi('/pesquisas/apollo/pessoas', {
        method: 'POST',
        body: {
          filtros: b, pessoas, dados, marca: marca || undefined,
          empresa_id: modoEmpresa === 'existente' ? empresaAlvo.id : undefined,
          segmento: seg?.segmento,
          segmento_tipo: seg?.segmento_tipo,
        },
      });
      caixa.onExecucao?.(d.run_id);
      const onde = modoEmpresa === 'existente' ? ` em ${empresaAlvo.nome}` : '';
      const segTxt = seg ? `, segmento ${prospSegRotulo(seg.segmento, seg.segmento_tipo)}` : '';
      const jaN = Number(d.jaExistiam) || 0;
      const jaTxt = jaN === 1 ? ' 1 já estava na base e foi actualizado.' : jaN > 1 ? ` ${jaN} já estavam na base e foram actualizados.` : '';
      setMsg({ tipo: 'ok', texto: `${d.contactos} contactos guardados${onde}${segTxt}.${jaTxt} ${d.empresas} empresas (${d.empresasNovas} novas, ${d.jaNoGestor} já no Gestor).` });
      if (d.pendentes?.total) setDecisao(d.pendentes);
      if (prospTemEntradas(d.entradas)) setPorEntrar(d.entradas);
      setRes(null); setSel([]);
      onDone?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setBusy(false); }
  };
  const todas = res && sel.length === res.pessoas.length;
  const nome = (p) => prospNomeDe(p) || '—';
  const pessoas = res?.pessoas || [];
  const jaVista = pessoas.filter(p => p.ja_na_base).length;
  const jaSel = sel.map(i => pessoas[i]).filter(p => p?.ja_na_base);
  const blocoIndexar = (largo) => (
    <div style={{ display: 'flex', flexDirection: largo ? 'row' : 'column', gap: 12, alignItems: 'stretch' }}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0, flex: 1 }}>
        <span style={{ fontSize: 12, fontWeight: 650, color: 'var(--text)' }}>Empresa</span>
        <div style={{ display: 'flex', gap: 8 }}>
          {[{ id: 'apollo', label: 'Da Apollo' }, { id: 'existente', label: 'Já na base' }].map(op => (
            <button key={op.id} type="button" onClick={() => setModoEmpresa(op.id)} style={{
              flex: 1, border: `1px solid ${modoEmpresa === op.id ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 6,
              background: modoEmpresa === op.id ? 'color-mix(in oklch, var(--ai-500, #3859D0) 12%, #fff)' : '#fff',
              color: modoEmpresa === op.id ? 'var(--ai-500)' : 'var(--text)', padding: '7px 8px', cursor: 'pointer',
              fontSize: 12, fontWeight: 650, fontFamily: 'inherit',
            }}>{op.label}</button>
          ))}
        </div>
        {modoEmpresa === 'apollo' && <span style={{ fontSize: 12, lineHeight: 1.4, color: 'var(--text-muted)' }}>Cada contacto fica na empresa que a Apollo devolveu. Se ainda não existir, entra na base.</span>}
        {modoEmpresa === 'existente' && (
          <>
            <input style={prospInput} value={empresaAlvo ? empresaAlvo.nome : qEmp} placeholder="Nome, domínio ou NIF" onChange={ev => { setEmpresaAlvo(null); setQEmp(ev.target.value); }} />
            {empresaAlvo && <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{[empresaAlvo.cidade, empresaAlvo.pais, empresaAlvo.dominio].filter(Boolean).join(' · ') || 'Empresa da base'}</span>}
            {!!achadas.length && !empresaAlvo && (
              <div style={{ border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' }}>
                {achadas.map(r => (
                  <button key={r.id} type="button" onClick={() => { setEmpresaAlvo(r); setQEmp(''); setAchadas([]); }} style={{
                    display: 'block', width: '100%', textAlign: 'left', background: '#fff', border: 'none', borderBottom: '1px solid var(--border)',
                    padding: '8px 10px', cursor: 'pointer', fontFamily: 'inherit',
                  }}>
                    <span style={{ fontSize: 13, fontWeight: 650 }}>{r.nome}</span>
                    <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{[r.cidade, r.pais, r.dominio].filter(Boolean).length ? ` · ${[r.cidade, r.pais, r.dominio].filter(Boolean).join(' · ')}` : ''}</span>
                  </button>
                ))}
              </div>
            )}
          </>
        )}
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <ProspField label="Segmento" hint="Opcional. Fica na empresa e uma leitura posterior não o substitui.">
          <select style={prospInput} value={segmento} onChange={ev => setSegmento(ev.target.value)}>
            <option value="">Sem segmento</option>
            {PROSP_SEGMENTOS.map(s => <option key={prospSegValor(s.segmento, s.tipo)} value={prospSegValor(s.segmento, s.tipo)}>{prospSegRotulo(s.segmento, s.tipo)}</option>)}
          </select>
        </ProspField>
      </div>
    </div>
  );
  const barraContactos = sel.length > 0 && (
    <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
        <strong style={{ fontSize: 13, marginRight: 4 }}>{sel.length} {sel.length === 1 ? 'contacto' : 'contactos'}</strong>
        <ProspChip on={dados.linkedin} label="LinkedIn" onClick={() => setDados(d => ({ ...d, linkedin: !d.linkedin }))} />
        <ProspChip on={dados.email} label="Email" title="1 crédito por pessoa. Só entra email verified." onClick={() => setDados(d => ({ ...d, email: !d.email }))} />
        <ProspChip on={dados.telemovel} label="Telemóvel" title="8 créditos por número válido." onClick={() => setDados(d => ({ ...d, telemovel: !d.telemovel }))} />
        <button type="button" className="btn btn-sm btn-ai" disabled={busy || (modoEmpresa === 'existente' && !empresaAlvo)} onClick={guardar} style={{ marginLeft: 'auto' }}>{busy ? 'A adicionar…' : 'Adicionar à base de prospeção'}</button>
      </div>
      {blocoIndexar(true)}
      {jaSel.length > 0 && (
        <div style={{ fontSize: 13, lineHeight: 1.45, color: '#9a3412', background: '#fff7ed', border: '1px solid #fdba74', borderRadius: 8, padding: '10px 12px' }}>
          {jaSel.length === 1
            ? <>{nome(jaSel[0])} já está na base{jaSel[0].ja_empresa ? ` (${jaSel[0].ja_empresa})` : ''}. Gravar actualiza a ficha existente.</>
            : <>{jaSel.length} dos contactos seleccionados já estão na base. Gravar actualiza essas fichas.</>}
        </div>
      )}
      {dados.email && <ProspAviso>Até {prospCreditos(sel.length * (tarifa?.email ?? 1), tarifa?.eur_por_credito)}. Só entra email verified.</ProspAviso>}
      {dados.telemovel && <ProspAviso>Até {prospCreditos(sel.length * (tarifa?.telemovel ?? 8), tarifa?.eur_por_credito)}. O número chega depois e só entra se for válido.{tarifa && !tarifa.telemovel_webhook ? ' Falta APOLLO_WEBHOOK_TOKEN no servidor.' : ''}</ProspAviso>}
    </div>
  );
  const tabela = (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
      {barraContactos}
      <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, minHeight: 280, overflow: 'auto', containerType: 'inline-size' }}>
      {res && <div style={{ padding: '12px 14px', fontSize: 13, color: 'var(--text-muted)' }}>A Apollo tem {prospNum(res.total)} pessoas. Estás a ver {prospNum(pessoas.length)}. {sel.length} escolhidas.{jaVista > 0 ? ` ${jaVista} ${jaVista === 1 ? 'já está' : 'já estão'} na base.` : ''} Esta procura não gastou créditos. O email e o telemóvel só entram depois de gravar, e só se forem válidos.</div>}
      <table style={{ width: 1680, minWidth: '100%', borderCollapse: 'collapse' }}>
        <thead>
          <tr>
            <th style={{ ...prospTh, width: 36 }}>{res && <input type="checkbox" checked={todas} onChange={() => setSel(todas ? [] : pessoas.map((_, i) => i))} />}</th>
            <th style={prospTh}>Contacto</th>
            <th style={prospTh}>Cargo</th>
            <th style={prospTh}>Email</th>
            <th style={prospTh}>Telemóvel</th>
            <th style={prospTh}>LinkedIn</th>
            <th style={prospTh}>Empresa</th>
            <th style={prospTh}>Morada</th>
            <th style={prospTh}>Código postal</th>
            <th style={prospTh}>Cidade</th>
            <th style={prospTh}>País</th>
          </tr>
        </thead>
        <tbody>
          {pessoas.map((p, i) => (
            <tr key={p.apollo_id || nome(p) + i} style={p.ja_na_base ? { background: '#fff7ed' } : undefined}>
              <td style={prospTd}><input type="checkbox" checked={sel.includes(i)} onChange={() => toggle(sel, setSel, i)} /></td>
              <td style={{ ...prospTd, fontWeight: 650 }}>
                <div>{nome(p)}</div>
                {p.ja_na_base && <div style={{ marginTop: 3, fontSize: 11, fontWeight: 700, color: '#c2410c' }}>Já na base{p.ja_empresa ? ` · ${p.ja_empresa}` : ''}</div>}
              </td>
              <td style={prospTd}>{p.cargo || '—'}</td>
              <td style={prospTd}>{p.has_email ? 'Disponível' : '—'}</td>
              <td style={prospTd}>{p.has_telemovel ? 'Disponível' : '—'}</td>
              <td style={prospTd}>{p.linkedin_url ? <a href={p.linkedin_url} target="_blank" rel="noreferrer" style={{ color: 'var(--ai-500)', textDecoration: 'none' }}>{p.linkedin_url}</a> : '—'}</td>
              <td style={prospTd}>{p.empresa?.nome || '—'}</td>
              <td style={prospTd}>{p.empresa?.morada || '—'}</td>
              <td style={prospTd}>{p.empresa?.codigo_postal || '—'}</td>
              <td style={prospTd}>{p.empresa?.cidade || '—'}</td>
              <td style={prospTd}>{p.empresa?.pais || '—'}</td>
            </tr>
          ))}
          {!pessoas.length && (busy
            ? <ProspCentroTabela colSpan={11}><ProspACorrer nota="A procurar contactos na Apollo." titulo="A PROCURAR" /></ProspCentroTabela>
            : <tr><td colSpan={11} style={{ ...prospTd, textAlign: 'center', color: 'var(--text-muted)', padding: 28 }}>Sem resultados.</td></tr>
          )}
        </tbody>
      </table>
      </div>
    </div>
  );
  const escolherDecisao = async (op) => {
    setADecidir(true);
    try {
      await prospEnviarDecisao(decisao, op);
      setMsg({ tipo: 'ok', texto: prospTextoDecisao(op) });
      setDecisao(null);
      onDone?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setADecidir(false); }
  };
  const escolherEntrada = async (campanha, op) => {
    setADecidir(true);
    try {
      const r = await prospEnviarEntrada(campanha, op);
      setPorEntrar(atual => prospEntradasSem(atual, campanha.id));
      setMsg({ tipo: 'ok', texto: prospTextoResultadoEntrada(op, campanha.nome, r) });
      onDone?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setADecidir(false); }
  };
  return (
    <>
    <ProspDecisaoSegmento pedido={decisao} entradas={porEntrar} aDecidir={aDecidir} onEscolher={escolherDecisao} onEntrada={escolherEntrada} onFechar={() => prospFecharDecisoes({ pedido: decisao, entradas: porEntrar, setDecisao, setEntradas: setPorEntrar, setMsg })} />
    <ProspColunas caixa={caixa} resultados={caixa.vista || <>{aviso}{tabela}</>} filtros={
      <>
        <ProspSecao titulo="Pessoa">
          <ProspField label="Nome" hint="Opcional. Ex.: Maria Silva. Entram nomes que contêm todas as palavras.">
            <input style={prospInput} value={b.nome} placeholder="Nome da pessoa" onChange={s('nome')} />
          </ProspField>
        </ProspSecao>
        <ProspSecao titulo="Ao gravar">
          {blocoIndexar(false)}
        </ProspSecao>
        <ProspSecao titulo="Onde">
          <ProspPais value={b.pais} onChange={v => setB(p => ({ ...p, pais: v }))} />
          <ProspField label="Localizações" hint="Opcional. Ex.: Porto, Braga"><input style={prospInput} value={b.localizacoes} onChange={s('localizacoes')} /></ProspField>
          <ProspField label="Sector" hint="Ex.: printing, signage, interior design"><input style={prospInput} value={b.palavras_chave} onChange={s('palavras_chave')} /></ProspField>
          <ProspField label="Quantas ver" hint="Máximo 100. Ainda não grava."><input type="number" min="1" max="100" style={prospInput} value={b.max} onChange={s('max')} /></ProspField>
        </ProspSecao>
        <ProspSecao titulo="Cargo">
          <ProspGrelha>
            {APOLLO_TIPOS.map(t => <ProspChip key={t.id} on={tipos.includes(t.id)} label={t.label} title={t.hint} onClick={() => toggle(tipos, setTipos, t.id)} />)}
          </ProspGrelha>
          <span style={{ fontSize: 12, lineHeight: 1.4, color: 'var(--text-dim)' }}>Obrigatório quando o nome está vazio. Com nome, o cargo afunila a procura.</span>
        </ProspSecao>
        <ProspSecao titulo="Senioridade">
          <ProspGrelha>
            {APOLLO_SENIORIDADES.map(t => <ProspChip key={t.id} on={senioridades.includes(t.id)} label={t.label} onClick={() => toggle(senioridades, setSenioridades, t.id)} />)}
          </ProspGrelha>
          <span style={{ fontSize: 12, lineHeight: 1.4, color: 'var(--text-dim)' }}>Opcional. Sem escolha, entram todos os níveis.</span>
        </ProspSecao>
        <ProspAviso>Esta procura não gasta créditos. Email e telemóvel não aparecem.</ProspAviso>
        <ProspBotao disabled={busy || (!tipos.length && !(b.nome || '').trim())} onClick={procurar}>{busy && !res ? 'A procurar…' : 'Procurar contactos'}</ProspBotao>
      </>
    } />
    </>
  );
}

function ProspApollo({ busy, setBusy, setMsg, onDone, marca, caixa, aviso }) {
  const [tarifa, setTarifa] = React.useState(null);
  React.useEffect(() => { prospApi('/apollo/custo').then(setTarifa).catch(() => {}); }, []);
  const [b, setB] = React.useState({ pais: 'PT', localizacoes: '', palavras_chave: '', nome: '', empregados: [], max: 25 });
  const [res, setRes] = React.useState(null);
  const [vistas, setVistas] = React.useState({});
  const [pagina, setPagina] = React.useState(1);
  const [escolhas, setEscolhas] = React.useState({});
  const [progresso, setProgresso] = React.useState('');
  const [tipos, setTipos] = React.useState([]);
  const [dados, setDados] = React.useState({ linkedin: true, email: false, telemovel: false });
  const [porEmpresa, setPorEmpresa] = React.useState(3);
  const [gestorOn, setGestorOn] = React.useState(false);
  const [gestorCampos, setGestorCampos] = React.useState(['website', 'morada', 'codigo_postal', 'cidade']);
  const [fase, setFase] = React.useState(null);
  const s = (k) => (ev) => setB(p => ({ ...p, [k]: ev.target.value }));
  const toggle = (lista, setLista, id) => setLista(lista.includes(id) ? lista.filter(x => x !== id) : [...lista, id]);
  const reportar = caixa.onRascunho;
  React.useEffect(() => {
    const pode = Boolean((b.palavras_chave || '').trim() || (b.nome || '').trim() || (b.localizacoes || '').trim() || (b.empregados || []).length);
    reportar?.({
      fonte: 'apollo', alvo: 'empresas', pode,
      parametros: { pais: b.pais, localizacoes: b.localizacoes, palavras_chave: b.palavras_chave, nome: b.nome, empregados: b.empregados, max: b.max },
      rotulo: [(b.palavras_chave || '').trim(), (b.nome || '').trim(), (b.localizacoes || '').trim()].filter(Boolean).join(' · ') || 'Apollo · empresas',
    });
  }, [b, reportar]);
  React.useEffect(() => {
    const p = caixa.pedido;
    if (!p || p.fonte !== 'apollo' || p.alvo === 'contactos') return;
    const f = p.parametros || {};
    setB({
      pais: f.pais || 'PT',
      localizacoes: f.localizacoes || '',
      palavras_chave: f.palavras_chave || '',
      nome: f.nome || '',
      empregados: Array.isArray(f.empregados) ? f.empregados : [],
      max: f.max || 25,
    });
  }, [caixa.pedido && caixa.pedido.n]);

  const chaveEmp = (e) => String(e?.apollo_org_id || `${e?.nome || ''}|${e?.dominio || e?.website || ''}`);
  const sel = Object.values(escolhas);
  const haSel = sel.length > 0;
  React.useEffect(() => {
    if (!haSel) return;
    prospApi('/apollo/custo').then(setTarifa).catch(() => {});
  }, [haSel]);
  const procurar = async (page = 1, manter = false) => {
    setBusy(true); setMsg(null);
    if (!manter) { setRes(null); setVistas({}); setEscolhas({}); setTipos([]); setPagina(1); setProgresso(''); }
    try {
      const { max, ...filtros } = b;
      const d = await prospApi('/pesquisas/apollo/preview', { method: 'POST', body: { filtros, page } });
      setVistas(v => (manter ? { ...v, [d.page]: d.empresas } : { [d.page]: d.empresas }));
      setPagina(d.page);
      setRes(prev => ({ ...d, creditos: (manter ? (prev?.creditos || 0) : 0) + (d.creditos || 1) }));
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setBusy(false); }
  };
  const irPagina = (n) => {
    if (vistas[n]) { setPagina(n); return; }
    procurar(n, true);
  };
  const seleccionarTodas = async () => {
    if (!res) return;
    const totalPages = res.total_pages || 1;
    const acumulado = { ...vistas };
    let creditosExtra = 0;
    setBusy(true); setMsg(null);
    try {
      for (let p = 1; p <= totalPages; p++) {
        if (acumulado[p]) continue;
        setProgresso(`A carregar página ${p} de ${totalPages}…`);
        const { max, ...filtros } = b;
        const d = await prospApi('/pesquisas/apollo/preview', { method: 'POST', body: { filtros, page: p } });
        acumulado[d.page] = d.empresas;
        creditosExtra += d.creditos || 1;
      }
      setVistas(acumulado);
      setRes(prev => (prev ? { ...prev, creditos: (prev.creditos || 0) + creditosExtra } : prev));
      setEscolhas(m => {
        const n = { ...m };
        Object.values(acumulado).flat().forEach(e => { if (e?.nome) n[chaveEmp(e)] = e; });
        return n;
      });
    } catch (e) {
      setVistas(acumulado);
      setRes(prev => (prev ? { ...prev, creditos: (prev.creditos || 0) + creditosExtra } : prev));
      setEscolhas(m => {
        const n = { ...m };
        Object.values(acumulado).flat().forEach(e => { if (e?.nome) n[chaveEmp(e)] = e; });
        return n;
      });
      setMsg({ tipo: 'erro', texto: e.message });
    } finally {
      setProgresso('');
      setBusy(false);
    }
  };
  const guardar = async () => {
    const empresas = sel.filter(e => e?.nome);
    if (!empresas.length) {
      setMsg({ tipo: 'erro', texto: 'As empresas seleccionadas não têm nome.' });
      return;
    }
    const n = empresas.length;
    const textoInicial = tipos.length
      ? `A gravar ${prospNum(n)} empresas. A seguir, até ${porEmpresa} contactos por empresa.`
      : `A gravar ${prospNum(n)} empresas na base.`;
    setBusy(true); setMsg(null); setFase({ texto: textoInicial, aCorrer: true });
    try {
      const d = await prospApi('/pesquisas/apollo', {
        method: 'POST',
        body: {
          filtros: b,
          creditos_pagina: res?.creditos,
          empresas,
          contactos: { tipos, dados, por_empresa: porEmpresa },
          gestor: { activo: gestorOn, campos: gestorCampos },
          marca: marca || undefined,
        },
      });
      caixa.onExecucao?.(d.run_id);
      setRes(null); setVistas({}); setEscolhas({}); setPagina(1);
      onDone?.();
      if (d.notas) setFase({ texto: d.notas, aCorrer: true });
      if (!d.a_correr) {
        setFase(null);
        setMsg({ tipo: 'ok', texto: `${d.empresas} empresas guardadas.` });
        return;
      }
      for (let i = 0; i < 400; i++) {
        await new Promise(r => setTimeout(r, 2000));
        const estado = await prospApi(`/runs/${d.run_id}`);
        const run = estado.run;
        if (!run || run.estado === 'a_correr') {
          if (run?.notas) setFase({ texto: run.notas, aCorrer: true });
          continue;
        }
        setFase(null);
        setMsg({ tipo: run.estado === 'erro' ? 'erro' : 'ok', texto: run.notas || 'Gravação concluída.' });
        onDone?.();
        return;
      }
      setFase({ texto: 'A gravação continua no servidor. O resultado fica no Histórico.', aCorrer: false });
    } catch (e) {
      setFase(null);
      setMsg({ tipo: 'erro', texto: e.message });
    } finally { setBusy(false); }
  };

  const empresas = vistas[pagina] || [];
  const totalPaginas = res?.total_pages || 1;
  const paginasEmFalta = res ? Array.from({ length: totalPaginas }, (_, i) => i + 1).filter(p => !vistas[p]).length : 0;
  const todasAsPaginas = !!(res && paginasEmFalta === 0 && Object.values(vistas).flat().every(e => escolhas[chaveEmp(e)]));
  const todas = empresas.length > 0 && empresas.every(e => escolhas[chaveEmp(e)]);
  const alternar = (e) => setEscolhas(m => {
    const k = chaveEmp(e);
    const n = { ...m };
    if (n[k]) delete n[k]; else n[k] = e;
    return n;
  });
  const alternarPagina = () => setEscolhas(m => {
    const n = { ...m };
    if (todas) empresas.forEach(e => delete n[chaveEmp(e)]);
    else empresas.forEach(e => { n[chaveEmp(e)] = e; });
    return n;
  });
  const pessoasPrevistas = tipos.length ? sel.length * porEmpresa : 0;
  const gastoEmail = tipos.length && dados.email ? pessoasPrevistas * (tarifa?.email ?? 1) : 0;
  const gastoTel = tipos.length && dados.telemovel ? pessoasPrevistas * (tarifa?.telemovel ?? 8) : 0;
  const saldoLead = tarifa?.saldo?.lead;
  const saldoTel = tarifa?.saldo?.telemovel;
  const excessoEmail = saldoLead != null && gastoEmail > saldoLead ? gastoEmail - saldoLead : 0;
  const excessoTel = saldoTel != null && gastoTel > saldoTel ? gastoTel - saldoTel : 0;
  const faltaCreditos = excessoEmail > 0 || excessoTel > 0;
  const rotuloSeccao = { fontSize: 11, fontWeight: 650, letterSpacing: '.06em', textTransform: 'uppercase', color: 'var(--text-dim)' };
  const linhaCredito = (nome, ate, disp, estoura) => (
    <div key={nome} style={{ display: 'grid', gridTemplateColumns: '1fr auto auto', gap: 12, alignItems: 'baseline', fontSize: 13, color: estoura ? '#991b1b' : 'var(--text)' }}>
      <span>{nome}</span>
      <span style={{ fontWeight: 650, fontVariantNumeric: 'tabular-nums' }}>{ate}</span>
      <span style={{ minWidth: 64, textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: estoura ? '#991b1b' : 'var(--text-muted)' }}>{disp}</span>
    </div>
  );
  const paginacao = res && (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap', fontSize: 12, color: 'var(--text-muted)' }}>
      <span>{prospNum(res.total)} na Apollo · página {pagina} de {totalPaginas} · {prospNum(empresas.length)} nesta página · {prospCreditos(res.creditos ?? 0, tarifa?.eur_por_credito)} já gastos</span>
      {todasAsPaginas && res.total > sel.length && <span>{prospNum(res.total - sel.length)} não entram: sem nome ou repetidas.</span>}
      <span style={{ marginLeft: 'auto', display: 'inline-flex', gap: 8, flexWrap: 'wrap' }}>
        {sel.length > 0 && <button type="button" className="btn btn-sm btn-ghost" disabled={busy} onClick={() => setEscolhas({})}>Limpar</button>}
        {totalPaginas > 1 && !todasAsPaginas && (
          <button type="button" className="btn btn-sm" disabled={busy} onClick={seleccionarTodas}>
            {paginasEmFalta ? `Seleccionar todas · ${paginasEmFalta} ${paginasEmFalta === 1 ? 'crédito' : 'créditos'}` : 'Seleccionar todas'}
          </button>
        )}
        <button type="button" className="btn btn-sm" disabled={busy || pagina <= 1} onClick={() => irPagina(pagina - 1)}>Anterior{vistas[pagina - 1] ? '' : pagina > 1 ? ' · 1 crédito' : ''}</button>
        <button type="button" className="btn btn-sm" disabled={busy || pagina >= totalPaginas} onClick={() => irPagina(pagina + 1)}>{vistas[pagina + 1] ? 'Seguinte' : 'Seguinte · 1 crédito'}</button>
      </span>
    </div>
  );
  const barraEmpresas = sel.length > 0 && (
    <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, overflow: 'hidden' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 16, padding: '14px 16px', borderBottom: '1px solid var(--border)' }}>
        <div>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 26, fontWeight: 700, lineHeight: 1, color: 'var(--text)' }}>{prospNum(sel.length)}</div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>{sel.length === 1 ? 'empresa seleccionada' : 'empresas seleccionadas'}</div>
        </div>
        <div style={{ marginLeft: 'auto', display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 6 }}>
          <button type="button" className={faltaCreditos ? 'btn btn-sm' : 'btn btn-sm btn-ai'} disabled={busy || faltaCreditos} onClick={guardar} style={{ cursor: busy || faltaCreditos ? 'not-allowed' : 'pointer' }}>
            {busy ? 'A adicionar…' : faltaCreditos ? 'Saldo insuficiente' : 'Adicionar à base de prospeção'}
          </button>
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))' }}>
        <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <span style={rotuloSeccao}>Cargos</span>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              {APOLLO_TIPOS.map(t => <ProspChip key={t.id} on={tipos.includes(t.id)} label={t.label} title={t.hint} onClick={() => toggle(tipos, setTipos, t.id)} />)}
            </div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <span style={rotuloSeccao}>Contactos por empresa</span>
            <div style={{ display: 'flex', gap: 8 }}>
              {[1, 2, 3, 5].map(n => (
                <button key={n} type="button" onClick={() => setPorEmpresa(n)} style={{
                  minWidth: 40, padding: '8px 12px', borderRadius: 8, cursor: 'pointer', fontFamily: 'inherit', fontSize: 13, fontWeight: 650,
                  border: `1px solid ${porEmpresa === n ? 'var(--ai-500)' : 'var(--border)'}`,
                  background: porEmpresa === n ? 'color-mix(in oklch, var(--ai-500, #3859D0) 12%, #fff)' : '#fff',
                  color: porEmpresa === n ? 'var(--ai-500)' : 'var(--text)',
                }}>{n}</button>
              ))}
            </div>
            <span style={{ fontSize: 12, lineHeight: 1.4, color: 'var(--text-dim)' }}>
              {tipos.length ? `Até ${prospNum(pessoasPrevistas)} contactos. A procura não gasta créditos.` : 'Sem cargo, entram só as empresas e este pedido gasta 0 créditos.'}
            </span>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <span style={rotuloSeccao}>Dados do contacto</span>
            <ProspEscolha on={dados.linkedin} label="LinkedIn" hint="Não gasta créditos." onClick={() => setDados(d => ({ ...d, linkedin: !d.linkedin }))} />
            <ProspEscolha on={dados.email} label="Email" hint="1 crédito por email verified. Só esse entra." onClick={() => setDados(d => ({ ...d, email: !d.email }))} />
            <ProspEscolha on={dados.telemovel} label="Telemóvel" hint="8 créditos por número válido. Chega depois." onClick={() => setDados(d => ({ ...d, telemovel: !d.telemovel }))} />
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8, borderTop: '1px solid var(--border)', paddingTop: 14 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
              <ProspChip on={gestorOn} label="Completar com o Gestor" title="Só quando o NIF é o mesmo." onClick={() => setGestorOn(v => !v)} />
              {gestorOn && GESTOR_CAMPOS.map(c => <ProspChip key={c.id} on={gestorCampos.includes(c.id)} label={c.label} onClick={() => toggle(gestorCampos, setGestorCampos, c.id)} />)}
            </div>
            {gestorOn && <span style={{ fontSize: 12, lineHeight: 1.4, color: 'var(--text-dim)' }}>Preenche campos vazios quando o NIF é o mesmo. Não escreve no Gestor.</span>}
          </div>
        </div>
        <div style={{ padding: 16, background: '#f8fafc', display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr auto auto', gap: 12, fontSize: 10, fontWeight: 650, letterSpacing: '.06em', textTransform: 'uppercase', color: 'var(--text-dim)' }}>
            <span>Créditos</span>
            <span>Até</span>
            <span style={{ textAlign: 'right' }}>Disponíveis</span>
          </div>
          {linhaCredito('Procura', '0', '—', false)}
          {linhaCredito('Email', dados.email && tipos.length ? prospNum(gastoEmail) : '—', saldoLead == null ? '—' : prospNum(saldoLead), excessoEmail > 0)}
          {linhaCredito('Telemóvel', dados.telemovel && tipos.length ? prospNum(gastoTel) : '—', saldoTel == null ? '—' : prospNum(saldoTel), excessoTel > 0)}
          {!tarifa?.saldo && <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Saldo Apollo indisponível. O pedido segue na mesma.</div>}
          {(excessoEmail > 0 || excessoTel > 0) && (
            <div style={{ fontSize: 12, lineHeight: 1.45, color: '#991b1b', background: '#fef2f2', border: '1px solid #fecaca', borderRadius: 8, padding: '10px 12px' }}>
              {excessoEmail > 0 && <div>Email passa o saldo em {prospNum(excessoEmail)} créditos.</div>}
              {excessoTel > 0 && <div>Telemóvel passa o saldo em {prospNum(excessoTel)} créditos.</div>}
              <div>Desliga esses dados ou baixa os contactos por empresa.</div>
            </div>
          )}
          {dados.telemovel && tarifa && !tarifa.telemovel_webhook && (
            <div style={{ fontSize: 12, lineHeight: 1.45, color: '#991b1b' }}>Falta APOLLO_WEBHOOK_TOKEN no servidor para receber o telemóvel.</div>
          )}
        </div>
      </div>
      {res && <div style={{ padding: '12px 16px', borderTop: '1px solid var(--border)' }}>{paginacao}</div>}
    </div>
  );
  const tabela = (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
      {fase && (fase.aCorrer
        ? <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10 }}><ProspACorrer nota={fase.texto} titulo="A ADICIONAR À BASE" /></div>
        : <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: '12px 14px', fontSize: 13, color: 'var(--text)' }}>{fase.texto}</div>
      )}
      {barraEmpresas}
      {res && sel.length === 0 && (
        <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: '12px 14px' }}>
          {progresso ? <div style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 8 }}>{progresso}</div> : null}
          {paginacao}
        </div>
      )}
      {progresso && sel.length > 0 && (
        <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>{progresso}</div>
      )}
      <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, minHeight: 280, overflow: 'auto', containerType: 'inline-size' }}>
      <table style={{ width: 1680, minWidth: '100%', borderCollapse: 'collapse' }}>
        <thead>
          <tr>
            <th style={{ ...prospTh, width: 36 }}>{empresas.length > 0 && <input type="checkbox" checked={todas} onChange={alternarPagina} />}</th>
            <th style={prospTh}>Empresa</th>
            <th style={prospTh}>Website</th>
            <th style={prospTh}>Telefone</th>
            <th style={prospTh}>Morada</th>
            <th style={prospTh}>Código postal</th>
            <th style={prospTh}>Cidade</th>
            <th style={prospTh}>País</th>
            <th style={prospTh}>Sector</th>
            <th style={prospTh}>Empregados</th>
          </tr>
        </thead>
        <tbody>
          {empresas.map((e, i) => (
            <tr key={chaveEmp(e) + i}>
              <td style={prospTd}><input type="checkbox" checked={!!escolhas[chaveEmp(e)]} onChange={() => alternar(e)} /></td>
              <td style={{ ...prospTd, fontWeight: 650 }}>{e.nome}</td>
              <td style={prospTd}>{e.website || e.dominio || '—'}</td>
              <td style={prospTd}>{e.telefone || '—'}</td>
              <td style={prospTd}>{e.morada || '—'}</td>
              <td style={prospTd}>{e.codigo_postal || '—'}</td>
              <td style={prospTd}>{e.cidade || '—'}</td>
              <td style={prospTd}>{e.pais || '—'}</td>
              <td style={prospTd}>{e.industria || '—'}</td>
              <td style={prospTd}>{e.funcionarios ?? '—'}</td>
            </tr>
          ))}
          {!empresas.length && (busy
            ? <ProspCentroTabela colSpan={10}><ProspACorrer nota={progresso || 'A procurar empresas na Apollo.'} titulo="A PROCURAR" /></ProspCentroTabela>
            : <tr><td colSpan={10} style={{ ...prospTd, textAlign: 'center', color: 'var(--text-muted)', padding: 28 }}>Sem resultados.</td></tr>
          )}
        </tbody>
      </table>
      </div>
    </div>
  );
  return (
    <ProspColunas caixa={caixa} resultados={caixa.vista || <>{aviso}{tabela}</>} filtros={
      <>
        <ProspSecao titulo="Onde">
          <ProspPais value={b.pais} onChange={v => setB(p => ({ ...p, pais: v }))} />
          <ProspField label="Localizações" hint="Opcional. Ex.: Porto, Braga"><input style={prospInput} value={b.localizacoes} onChange={s('localizacoes')} /></ProspField>
        </ProspSecao>
        <ProspSecao titulo="Empresa">
          <ProspField label="Sector" hint="Ex.: printing, signage, interior design"><input style={prospInput} value={b.palavras_chave} onChange={s('palavras_chave')} /></ProspField>
          <ProspField label="Nome contém"><input style={prospInput} value={b.nome} onChange={s('nome')} /></ProspField>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <span style={{ fontSize: 12, fontWeight: 650 }}>Empregados</span>
            <ProspGrelha>
              {APOLLO_EMPREGADOS.map(t => <ProspChip key={t.id} on={b.empregados.includes(t.id)} label={t.label} onClick={() => setB(p => ({ ...p, empregados: p.empregados.includes(t.id) ? p.empregados.filter(x => x !== t.id) : [...p.empregados, t.id] }))} />)}
            </ProspGrelha>
          </div>
        </ProspSecao>
        <ProspAviso>Cada página mostra 100 empresas e gasta 1 crédito. Ainda não grava.</ProspAviso>
        <ProspBotao disabled={busy} onClick={() => procurar(1, false)}>{busy && !res ? 'A procurar…' : 'Procurar empresas'}</ProspBotao>
      </>
    } />
  );
}

function ProspImportAudiencias({ lista }) {
  if (lista?.erro) {
    return <div style={{ fontSize: 13, lineHeight: 1.45, color: '#9a3412', background: '#fff7ed', border: '1px solid #fdba74', borderRadius: 8, padding: '10px 12px' }}>A importação ficou gravada. Não foi possível cruzar os contactos com as audiências.</div>;
  }
  if (!Array.isArray(lista) || !lista.length) {
    return <div style={{ fontSize: 13, lineHeight: 1.45, color: 'var(--text-muted)', background: '#f4f7fb', borderRadius: 8, padding: '10px 12px' }}>Nenhum contacto desta importação entra numa audiência definida.</div>;
  }
  const emCampanha = lista.some(a => a.campanhas?.length);
  return (
    <div style={{ fontSize: 13, lineHeight: 1.5, color: emCampanha ? '#9a3412' : 'var(--text)', background: emCampanha ? '#fff7ed' : '#f4f7fb', border: emCampanha ? '1px solid #fdba74' : '1px solid transparent', borderRadius: 8, padding: '10px 12px', display: 'flex', flexDirection: 'column', gap: 8 }}>
      <div style={{ fontWeight: 650 }}>{emCampanha ? 'Estes contactos correspondem a uma audiência ligada a uma campanha.' : 'Estes contactos entram numa audiência definida.'}</div>
      {lista.map(a => (
        <div key={a.id}>
          <strong>{prospNum(a.contactos)}</strong> {Number(a.contactos) === 1 ? 'contacto entra' : 'contactos entram'} na audiência {a.nome}.
          {a.campanhas?.length
            ? a.campanhas.map(c => <div key={c.id}>Campanha {c.nome}{c.workflow === 'activo' ? ` · envio activo${Number.isInteger(c.inscritos) ? ` · ${prospNum(c.inscritos)} ${Number(c.inscritos) === 1 ? 'contacto novo entrou' : 'contactos novos entraram'} na campanha` : ''}` : ''}.</div>)
            : <div>Esta audiência ainda não está ligada a uma campanha.</div>}
        </div>
      ))}
    </div>
  );
}

function prospTemEntradas(e) {
  return !!e?.campanhas?.length;
}

async function prospEnviarEntrada(campanha, decisao) {
  return prospApi('/entrada/decisao', {
    method: 'POST',
    body: { campanha_id: campanha.id, contacto_ids: campanha.contacto_ids, decisao },
  });
}

async function prospFecharEntradas(entradas) {
  const campanhas = entradas?.campanhas || [];
  if (!campanhas.length) return null;
  return prospApi('/entrada/decisao', {
    method: 'POST',
    body: {
      itens: campanhas.map(c => ({ campanha_id: c.id, contacto_ids: c.contacto_ids, decisao: 'so_base' })),
    },
  });
}

function prospTextoEntrada(decisao, nome) {
  if (decisao === 'entrar') return nome ? `Vão receber a campanha ${nome}.` : 'Vão receber a campanha.';
  return nome ? `Ficaram na base e não entram na campanha ${nome}.` : 'Ficaram na base e não entram na campanha.';
}

function prospTextoResultadoEntrada(decisao, nome, resposta) {
  if (decisao === 'entrar' && !Number(resposta?.resultado?.inscritos)) return 'Estes contactos já não correspondem a esta campanha.';
  return prospTextoEntrada(decisao, nome);
}

function prospEntradasSem(entradas, id) {
  const campanhas = (entradas?.campanhas || []).filter(c => c.id !== id);
  if (!campanhas.length) return null;
  const ids = new Set(campanhas.flatMap(c => c.contacto_ids || []));
  return { ...entradas, campanhas, total: ids.size };
}

async function prospFecharDecisoes({ pedido, entradas, setDecisao, setEntradas, setMsg }) {
  const segmento = !!pedido?.total;
  const camps = entradas?.campanhas || [];
  setDecisao(null);
  setEntradas(null);
  try {
    if (camps.length) await prospFecharEntradas(entradas);
  } catch (e) {
    setDecisao(segmento ? pedido : null);
    setEntradas(camps.length ? entradas : null);
    setMsg({ tipo: 'erro', texto: e.message });
    return false;
  }
  const partes = [];
  if (segmento) partes.push(prospTextoDecisao('manter'));
  if (camps.length === 1) partes.push(prospTextoEntrada('so_base', camps[0].nome));
  else if (camps.length > 1) partes.push('Ficaram na base e não entram nas campanhas.');
  if (partes.length) setMsg({ tipo: 'ok', texto: partes.join(' ') });
  return true;
}

function ProspDecisaoSegmento({ pedido, entradas, aDecidir, onEscolher, onEntrada, onFechar }) {
  const camps = entradas?.campanhas || [];
  if (!pedido?.total && !camps.length) return null;
  const n = Number(pedido?.total) || 0;
  const mais = Math.max(0, n - (pedido?.empresas || []).length);
  const estiloBtn = {
    textAlign: 'left', padding: '10px 12px', borderRadius: 8, cursor: aDecidir ? 'default' : 'pointer', fontFamily: 'inherit',
    width: '100%', border: '1px solid #E3E6EB', background: '#fff', color: '#112954',
  };
  const btn = (decisao, label, hint) => (
    <button type="button" disabled={aDecidir} onClick={() => onEscolher(decisao)} style={estiloBtn}>
      <div style={{ fontSize: 13, fontWeight: 650 }}>{label}</div>
      <div style={{ fontSize: 12, lineHeight: 1.4, color: '#64748b', marginTop: 3 }}>{hint}</div>
    </button>
  );
  const titulo = pedido?.total && camps.length
    ? 'Confirma estes contactos antes de seguirem'
    : camps.length === 1
      ? (Number(camps[0].total) === 1 ? `1 contacto vai receber a campanha ${camps[0].nome}` : `${prospNum(camps[0].total)} contactos vão receber a campanha ${camps[0].nome}`)
      : camps.length > 1
        ? `${prospNum(entradas.total)} contactos vão receber campanhas activas`
        : (n === 1 ? '1 empresa já está numa sequência activa' : `${prospNum(n)} empresas já estão numa sequência activa`);
  const intro = camps.length && !pedido?.total
    ? 'Já estão na base. Em cada campanha, escolhe se a recebem ou se ficam só na base. Se fechares, ficam só na base.'
    : pedido?.total && camps.length
      ? 'O resto já ficou gravado. Se fechares, as empresas em sequência mantêm o segmento e os contactos novos ficam só na base.'
      : 'O resto já ficou gravado. Estas empresas mantêm o segmento actual até escolheres. Se fechares, ficam como estão.';
  return ReactDOM.createPortal(
    <div onClick={aDecidir ? undefined : onFechar} style={{ position: 'fixed', inset: 0, background: 'rgba(17,41,84,0.45)', zIndex: 320, display: 'flex', justifyContent: 'center', alignItems: 'flex-start', padding: 24, overflow: 'auto' }}>
      <div onClick={ev => ev.stopPropagation()} role="dialog" aria-label="Entrada em campanha" style={{ width: 'min(560px, 100%)', marginTop: 24, background: '#fff', borderRadius: 12, padding: 20, boxShadow: '0 24px 80px rgba(15,23,42,.28)' }}>
        <div style={{ fontSize: 16, fontWeight: 700, color: '#112954' }}>{titulo}</div>
        <p style={{ fontSize: 13, lineHeight: 1.45, color: '#475569', margin: '8px 0 12px' }}>{intro}</p>
        {!!pedido?.total && (
          <>
            <div style={{ maxHeight: 220, overflow: 'auto', border: '1px solid #ECEFF5', borderRadius: 8, marginBottom: 12 }}>
              {(pedido.empresas || []).map(e => (
                <div key={e.id} style={{ padding: '8px 12px', borderBottom: '1px solid #ECEFF5', fontSize: 13, color: '#112954' }}>
                  <strong>{e.nome}</strong>
                  <div style={{ color: '#64748b', marginTop: 2 }}>{e.segmento || 'Sem segmento'} · {(e.campanhas || []).join(', ')}</div>
                </div>
              ))}
              {mais > 0 && <div style={{ padding: '8px 12px', fontSize: 12, color: '#64748b' }}>e mais {prospNum(mais)}</div>}
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {btn('manter', 'Manter onde estão', 'Não mudam de segmento e não entram na campanha nova.')}
              {btn('mudar_parar', 'Mudar e parar a sequência antiga', 'Passam ao segmento novo. A sequência actual pára. A campanha nova pode inscrevê-los.')}
              {btn('mudar_ambas', 'Mudar e manter as duas', 'Passam ao segmento novo. A sequência actual continua e a nova também os inscreve.')}
            </div>
          </>
        )}
        {camps.map(c => {
          const resto = Math.max(0, Number(c.total) - (c.contactos || []).length);
          const aud = (c.audiencias || []).filter(Boolean).join(', ');
          return (
            <div key={c.id} style={{ marginTop: pedido?.total ? 18 : 0 }}>
              {(pedido?.total || camps.length > 1) && (
                <div style={{ fontSize: 14, fontWeight: 700, color: '#112954', marginBottom: 4 }}>
                  {Number(c.total) === 1 ? '1 contacto' : `${prospNum(c.total)} contactos`} · {c.nome}
                </div>
              )}
              {!!aud && <div style={{ fontSize: 12, color: '#64748b', marginBottom: 8 }}>Audiência {aud}</div>}
              <div style={{ maxHeight: 180, overflow: 'auto', border: '1px solid #ECEFF5', borderRadius: 8, marginBottom: 8 }}>
                {(c.contactos || []).map(p => (
                  <div key={p.id} style={{ padding: '8px 12px', borderBottom: '1px solid #ECEFF5', fontSize: 13, color: '#112954' }}>
                    <strong>{p.nome}</strong>
                    {p.empresa ? <span style={{ color: '#64748b' }}> · {p.empresa}</span> : null}
                  </div>
                ))}
                {resto > 0 && <div style={{ padding: '8px 12px', fontSize: 12, color: '#64748b' }}>e mais {prospNum(resto)}</div>}
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                <button type="button" disabled={aDecidir} onClick={() => onEntrada(c, 'entrar')} style={estiloBtn}>
                  <div style={{ fontSize: 13, fontWeight: 650 }}>Adicionar e entram na campanha</div>
                  <div style={{ fontSize: 12, lineHeight: 1.4, color: '#64748b', marginTop: 3 }}>Ficam na base e vão receber os emails de {c.nome}.</div>
                </button>
                <button type="button" disabled={aDecidir} onClick={() => onEntrada(c, 'so_base')} style={estiloBtn}>
                  <div style={{ fontSize: 13, fontWeight: 650 }}>Adicionar só à base</div>
                  <div style={{ fontSize: 12, lineHeight: 1.4, color: '#64748b', marginTop: 3 }}>Ficam gravados e não entram nesta campanha.</div>
                </button>
              </div>
            </div>
          );
        })}
      </div>
    </div>,
    document.body
  );
}

async function prospEnviarDecisao(pedido, decisao) {
  if (decisao === 'manter') return { decisao: 'manter' };
  return prospApi('/segmento/decisao', {
    method: 'POST',
    body: {
      empresa_ids: pedido.empresa_ids,
      segmento: pedido.segmento,
      segmento_tipo: pedido.segmento_tipo,
      decisao,
      fonte: pedido.fonte || 'import',
    },
  });
}

function prospTextoDecisao(decisao) {
  if (decisao === 'mudar_parar') return 'Segmento actualizado. A sequência antiga parou.';
  if (decisao === 'mudar_ambas') return 'Segmento actualizado. As duas sequências seguem.';
  return 'Essas empresas ficaram com o segmento actual.';
}

function ProspFormFicheiro({ busy, setBusy, setMsg, onDone, marca, caixa, aviso }) {
  const [file, setFile] = React.useState(null);
  const [prev, setPrev] = React.useState(null);
  const [mapping, setMapping] = React.useState({});
  const [pais, setPais] = React.useState('PT');
  const [descricao, setDescricao] = React.useState('');
  const [segmento, setSegmento] = React.useState('');
  const [contagem, setContagem] = React.useState(null);
  const [entradas, setEntradas] = React.useState(null);
  const [decisao, setDecisao] = React.useState(null);
  const [porEntrar, setPorEntrar] = React.useState(null);
  const [aDecidir, setADecidir] = React.useState(false);
  const [aContar, setAContar] = React.useState(false);
  const [pagina, setPagina] = React.useState(0);
  const contagemRef = React.useRef(0);
  const porPagina = 25;

  const carregar = async (f) => {
    setFile(f); setPrev(null); setContagem(null); setEntradas(null); setPagina(0); setMsg(null);
    if (!f) return;
    const form = new FormData(); form.append('pais', pais); form.append('file', f);
    setBusy(true);
    try {
      const d = await prospApi('/import/preview', { method: 'POST', form });
      setPrev(d); setMapping(d.sugestao || {}); setContagem(d.contagem || null);
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setBusy(false); }
  };
  const mapKey = JSON.stringify(mapping);
  React.useEffect(() => {
    if (!file || !prev) return undefined;
    const id = ++contagemRef.current;
    const t = setTimeout(async () => {
      const form = new FormData();
      form.append('mapping', mapKey);
      form.append('pais', pais);
      form.append('file', file);
      setAContar(true);
      try {
        const d = await prospApi('/import/contagem', { method: 'POST', form });
        if (id === contagemRef.current) setContagem(d);
      } catch (e) {
        if (id === contagemRef.current) setMsg({ tipo: 'erro', texto: e.message });
      } finally {
        if (id === contagemRef.current) setAContar(false);
      }
    }, 300);
    return () => clearTimeout(t);
  }, [file, prev, mapKey, pais]);
  const escolherColuna = (coluna, campo) => {
    setMapping(m => {
      const next = {};
      for (const [k, col] of Object.entries(m)) {
        if (col !== coluna && k !== campo) next[k] = col;
      }
      if (campo) next[campo] = coluna;
      return next;
    });
  };
  const importar = async () => {
    const form = new FormData();
    form.append('file', file); form.append('mapping', JSON.stringify(mapping)); form.append('pais', pais);
    if (marca) form.append('marca', marca);
    if (descricao) form.append('descricao', descricao);
    const seg = prospSegPartes(segmento);
    if (seg) { form.append('segmento', seg.segmento); if (seg.segmento_tipo) form.append('segmento_tipo', seg.segmento_tipo); }
    setBusy(true); setMsg(null);
    try {
      const d = await prospApi('/import', { method: 'POST', form });
      setMsg({ tipo: 'ok', texto: `${d.linhas} linhas lidas → ${d.empresas} empresas (${d.empresasNovas} novas, ${d.jaNoGestor} já no Gestor) e ${d.contactos} contactos.` });
      setEntradas(d.audiencias === null ? { erro: true } : (d.audiencias || []));
      setDecisao(d.pendentes?.total ? d.pendentes : null);
      setPorEntrar(prospTemEntradas(d.entradas) ? d.entradas : null);
      setPrev(null); setFile(null); setContagem(null); onDone?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setBusy(false); }
  };
  const escolherDecisao = async (op) => {
    setADecidir(true);
    try {
      await prospEnviarDecisao(decisao, op);
      setMsg({ tipo: 'ok', texto: prospTextoDecisao(op) });
      setDecisao(null);
      onDone?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setADecidir(false); }
  };
  const escolherEntrada = async (campanha, op) => {
    setADecidir(true);
    try {
      const r = await prospEnviarEntrada(campanha, op);
      setPorEntrar(atual => prospEntradasSem(atual, campanha.id));
      setMsg({ tipo: 'ok', texto: prospTextoResultadoEntrada(op, campanha.nome, r) });
      onDone?.();
    } catch (e) { setMsg({ tipo: 'erro', texto: e.message }); }
    finally { setADecidir(false); }
  };
  const campoDaColuna = (coluna) => Object.entries(mapping).find(([, col]) => col === coluna)?.[0] || '';
  const semEmpresaMapeada = !mapping['empresa.nome'];
  const amostra = !prev ? (
    <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, minHeight: 280, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--text-muted)', fontSize: 13, padding: 24, textAlign: 'center' }}>Escolhe um ficheiro. O mapeamento fica em cada coluna, com os valores por baixo.</div>
  ) : (() => {
    const inicio = pagina * porPagina;
    const fatia = prev.amostra.slice(inicio, inicio + porPagina);
    const paginas = Math.max(1, Math.ceil(prev.amostra.length / porPagina));
    const amostraParcial = prev.amostra.length < prev.total;
    const de = prospNum(inicio + 1);
    const ate = prospNum(inicio + fatia.length);
    return (
      <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, overflow: 'auto' }}>
        <div style={{ padding: '12px 14px', fontSize: 13, lineHeight: 1.45 }}>
          <strong>{prev.nome}</strong> · folha {prev.folha} · {amostraParcial ? `amostra das primeiras ${prospNum(prev.amostra.length)} de ${prospNum(prev.total)} linhas` : `${prospNum(prev.total)} linhas`}
          <div style={{ color: 'var(--text-muted)', marginTop: 2 }}>Cada coluna escolhe o campo da base. Cada campo fica numa só coluna. A importação lê as {prospNum(prev.total)} linhas.</div>
        </div>
        <table style={{ borderCollapse: 'collapse', fontSize: 12 }}>
          <thead>
            <tr>
              {prev.cabecalhos.map(h => {
                const campo = campoDaColuna(h);
                return (
                  <th key={h} style={{ ...prospTh, verticalAlign: 'top', minWidth: 156, background: campo ? 'color-mix(in oklch, var(--ai-500) 8%, #fff)' : '#fff' }}>
                    <div style={{ marginBottom: 6 }}>{h}</div>
                    <select value={campo} onChange={ev => escolherColuna(h, ev.target.value)} style={{ ...prospInput, padding: '6px 8px', fontSize: 12, textTransform: 'none', letterSpacing: 0, fontWeight: 500 }}>
                      <option value="">— ignorar —</option>
                      {prev.campos.map(c => <option key={c.key} value={c.key}>{c.label}{c.key === 'empresa.nome' ? ' *' : ''}</option>)}
                    </select>
                  </th>
                );
              })}
            </tr>
          </thead>
          <tbody>
            {fatia.map((r, i) => (
              <tr key={inicio + i}>
                {prev.cabecalhos.map(h => {
                  const campo = campoDaColuna(h);
                  return <td key={h} style={{ ...prospTd, fontSize: 12, whiteSpace: 'nowrap', color: campo ? 'var(--text)' : 'var(--text-muted)' }}>{prospSemAsteriscos(r[h]) || '—'}</td>;
                })}
              </tr>
            ))}
          </tbody>
        </table>
        {paginas > 1 && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 14px', fontSize: 12, color: 'var(--text-muted)' }}>
            <button type="button" className="btn btn-sm" disabled={pagina <= 0} onClick={() => setPagina(p => Math.max(0, p - 1))}>Anterior</button>
            <span>{de}–{ate} de {prospNum(prev.amostra.length)}{amostraParcial ? ' na amostra' : ''}</span>
            <button type="button" className="btn btn-sm" disabled={pagina >= paginas - 1} onClick={() => setPagina(p => Math.min(paginas - 1, p + 1))}>Seguinte</button>
          </div>
        )}
      </div>
    );
  })();
  return (
    <>
    <ProspDecisaoSegmento pedido={decisao} entradas={porEntrar} aDecidir={aDecidir} onEscolher={escolherDecisao} onEntrada={escolherEntrada} onFechar={() => prospFecharDecisoes({ pedido: decisao, entradas: porEntrar, setDecisao, setEntradas: setPorEntrar, setMsg })} />
    <ProspColunas caixa={caixa} resultados={<>{aviso}{entradas && <ProspImportAudiencias lista={entradas} />}{amostra}</>} filtros={
      <>
        <div style={{ fontSize: 12, lineHeight: 1.45, color: 'var(--text-muted)' }}>Cada linha é uma empresa, com contacto se o ficheiro o tiver. O país por omissão só entra quando a linha não traz país. Em Todas, a importação não marca uma marca.</div>
        <div style={prospLinhas}>
          <ProspField label="Ficheiro" hint=".xlsx, .xls ou .csv — até 20 000 linhas"><input type="file" accept=".xlsx,.xls,.csv" onChange={ev => carregar(ev.target.files?.[0] || null)} /></ProspField>
          <ProspField label="País por omissão">
            <select style={prospInput} value={pais} onChange={ev => setPais(ev.target.value)}>{PROSP_PAISES.map(p => <option key={p.value} value={p.value}>{p.label}</option>)}</select>
          </ProspField>
          <ProspField label="Segmento" hint="Fica em todas as empresas deste ficheiro. Serve para filtrar a lista depois.">
            <select style={prospInput} value={segmento} onChange={ev => setSegmento(ev.target.value)}>
              <option value="">Sem segmento</option>
              {PROSP_SEGMENTOS.map(s => <option key={prospSegValor(s.segmento, s.tipo)} value={prospSegValor(s.segmento, s.tipo)}>{prospSegRotulo(s.segmento, s.tipo)}</option>)}
            </select>
          </ProspField>
          <ProspField label="Origem da lista" hint="Ex.: Feira FESPA 2026"><input style={prospInput} value={descricao} onChange={ev => setDescricao(ev.target.value)} /></ProspField>
        </div>
        {prev && (
          <div style={{ fontSize: 13, lineHeight: 1.5, background: semEmpresaMapeada || contagem?.semEmpresa ? '#fff7ed' : '#f4f7fb', borderRadius: 8, padding: '10px 12px' }}>
            <div><strong>{prospNum(contagem?.linhas ?? prev.total)}</strong> linhas no ficheiro{aContar ? ' · a actualizar…' : ''}</div>
            {semEmpresaMapeada
              ? <div>Escolhe a coluna da empresa na tabela.</div>
              : (
                <>
                  <div><strong>{prospNum(contagem?.empresas || 0)}</strong> empresas · <strong>{prospNum(contagem?.contactos || 0)}</strong> contactos</div>
                  {!!contagem?.semEmpresa && <div>{contagem.semEmpresa === 1 ? '1 linha fica de fora por não ter empresa.' : `${prospNum(contagem.semEmpresa)} linhas ficam de fora por não terem empresa.`}</div>}
                </>
              )}
          </div>
        )}
        {prev && <div><button type="button" className="btn btn-ai" disabled={busy || semEmpresaMapeada} onClick={importar}>{busy ? 'A importar…' : `Importar ${prospNum(prev.total)} linhas`}</button></div>}
      </>
    } />
    </>
  );
}

function ProspFormValidar({ busy, onRun, caixa, aviso, resultados, alvo }) {
  const [b, setB] = React.useState({ estado: 'novo', limite: 100, so_por_validar: true });
  return (
    <ProspColunas caixa={caixa} resultados={<>{aviso}{resultados}</>} filtros={
      <>
        <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>
          Verifica o NIF e o telefone da empresa, e o email e o telemóvel de cada contacto. Empresa com um canal válido passa a Validado.
        </div>
        <div style={prospLinhas}>
          <ProspField label="Estado"><select style={prospInput} value={b.estado} onChange={ev => setB(p => ({ ...p, estado: ev.target.value }))}><option value="">Todos</option>{PROSP_ESTADOS.map(e => <option key={e.id} value={e.id}>{e.label}</option>)}</select></ProspField>
          <ProspField label="Quantas empresas" hint="Até 300 por execução"><input type="number" min="1" max="300" style={prospInput} value={b.limite} onChange={ev => setB(p => ({ ...p, limite: ev.target.value }))} /></ProspField>
        </div>
        <ProspEscolha on={b.so_por_validar} label="Só por validar" hint="Ignora empresas que já passaram por esta verificação." onClick={() => setB(p => ({ ...p, so_por_validar: !p.so_por_validar }))} />
        <div><button type="button" className="btn btn-ai" disabled={busy} onClick={() => onRun({ ...b, limite: Number(b.limite) || 100 })}>Validar</button></div>
      </>
    } />
  );
}

// ── Execuções ─────────────────────────────────────────────────────────────────

function ProspExecucoes({ tick, desde, ate, marca }) {
  const [rows, setRows] = React.useState([]);
  const [erro, setErro] = React.useState('');
  const [t, setT] = React.useState(0);
  React.useEffect(() => {
    prospApi('/runs', { query: { desde, ate, marca } }).then(d => { setRows(d.rows); setErro(''); }).catch(e => setErro(e.message));
  }, [tick, t, desde, ate, marca]);
  const aCorrer = rows.some(r => r.estado === 'a_correr');
  React.useEffect(() => {
    if (!aCorrer) return;
    const id = setInterval(() => setT(x => x + 1), 8000);
    return () => clearInterval(id);
  }, [aCorrer]);
  const cor = { a_correr: '#d97706', concluido: '#16a34a', erro: '#b91c1c' };
  return (
    <ProspCard style={{ padding: 0, overflow: 'auto' }}>
      {erro && <div style={{ padding: 12 }}><ProspMsg msg={{ tipo: 'erro', texto: erro }} /></div>}
      <table style={{ width: '100%', borderCollapse: 'collapse' }}>
        <thead><tr>{['#', 'Fonte', 'O quê', 'Estado', 'Empresas', 'Contactos', 'Custo', 'Por', 'Início', 'Resultado'].map(h => <th key={h} style={prospTh}>{h}</th>)}</tr></thead>
        <tbody>
          {rows.map(r => (
            <tr key={r.id}>
              <td style={prospTd}>{r.id}</td>
              <td style={prospTd}>{PROSP_FONTES[r.fonte] || r.fonte}</td>
              <td style={{ ...prospTd, maxWidth: 280 }}>{r.referencia || '—'}</td>
              <td style={{ ...prospTd, color: cor[r.estado], fontWeight: 600, whiteSpace: 'nowrap' }}>{r.estado === 'a_correr' ? 'A correr…' : r.estado === 'erro' ? 'Erro' : 'Concluído'}</td>
              <td style={prospTd}>{r.n_empresas ?? '—'}</td>
              <td style={prospTd}>{r.n_contactos ?? '—'}</td>
              <td style={prospTd}>{prospUsd(r.custo_usd)}</td>
              <td style={{ ...prospTd, fontSize: 12 }}>{r.criado_por || '—'}</td>
              <td style={{ ...prospTd, fontSize: 12, whiteSpace: 'nowrap' }}>{prospData(r.iniciado_em)}</td>
              <td style={{ ...prospTd, fontSize: 12, color: r.estado === 'erro' ? '#b91c1c' : 'var(--text-muted)', maxWidth: 360 }}>{r.notas || ''}</td>
            </tr>
          ))}
          {!rows.length && <tr><td colSpan={10} style={{ ...prospTd, color: 'var(--text-muted)', textAlign: 'center', padding: 30 }}>Ainda sem execuções.</td></tr>}
        </tbody>
      </table>
    </ProspCard>
  );
}

// ── Ecrã ──────────────────────────────────────────────────────────────────────

function prospIsoDia(d) {
  const x = new Date(d);
  if (Number.isNaN(x.getTime())) return '';
  return `${x.getFullYear()}-${String(x.getMonth() + 1).padStart(2, '0')}-${String(x.getDate()).padStart(2, '0')}`;
}

function ProspIcone({ children, onClick, activo, label }) {
  return (
    <button type="button" aria-label={label} onMouseDown={e => e.stopPropagation()} onClick={onClick} style={{
      width: 30, height: 30, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
      border: `1px solid ${activo ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 6,
      background: activo ? 'color-mix(in oklch, var(--ai-500) 10%, #fff)' : '#fff',
      color: activo ? 'var(--ai-500)' : 'var(--text)', cursor: 'pointer', padding: 0,
    }}>{children}</button>
  );
}

function ProspMenu({ items, activo, onOpen }) {
  const [open, setOpen] = React.useState(false);
  const [foco, setFoco] = React.useState(-1);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const onClick = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    document.addEventListener('mousedown', onClick);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('mousedown', onClick); document.removeEventListener('keydown', onKey); };
  }, [open]);
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <ProspIcone label="Menu" activo={open} onClick={() => { setOpen(v => !v); setFoco(-1); onOpen?.(); }}>
        <svg width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"><path d="M2.5 4h11M2.5 8h11M2.5 12h11" /></svg>
      </ProspIcone>
      {open && (
        <div role="menu" style={{
          position: 'absolute', top: 'calc(100% + 6px)', right: 0, zIndex: 70,
          background: '#fff', border: '1px solid var(--border)', borderRadius: 8,
          boxShadow: '0 12px 32px rgba(17,41,84,0.14)', minWidth: 260, padding: 4,
        }}>
          {items.map((it, i) => (
            <button key={it.id} type="button" role="menuitem"
              onClick={() => { setOpen(false); it.onClick(); }}
              onMouseEnter={() => setFoco(i)} onMouseLeave={() => setFoco(-1)}
              style={{
                display: 'flex', alignItems: 'center', gap: 8, width: '100%', textAlign: 'left',
                background: foco === i ? 'color-mix(in oklch, var(--ai-500) 10%, #fff)' : 'transparent',
                color: activo === it.id || foco === i ? 'var(--ai-500)' : 'var(--text)',
                border: 'none', padding: '8px 10px', borderRadius: 6, cursor: 'pointer', fontFamily: 'inherit',
              }}>
              <span style={{ flex: 1, minWidth: 0 }}>
                <span style={{ display: 'block', fontSize: 13, fontWeight: 650 }}>{it.label}</span>
                {it.sub && <span style={{ display: 'block', fontSize: 11, color: 'var(--text-muted)', fontWeight: 400, marginTop: 1 }}>{it.sub}</span>}
              </span>
              {activo === it.id && <span style={{ color: 'var(--ai-500)' }}>✓</span>}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

function ProspBusca({ marca, desde, ate, onOpen, onClose }) {
  const [q, setQ] = React.useState('');
  const [rows, setRows] = React.useState([]);
  const [foco, setFoco] = React.useState(0);
  const [loading, setLoading] = React.useState(false);
  const inputRef = React.useRef(null);
  React.useEffect(() => { inputRef.current?.focus(); }, []);
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [onClose]);
  React.useEffect(() => {
    const termo = q.trim();
    if (termo.length < 2) { setRows([]); setLoading(false); return; }
    let stop = false;
    setLoading(true);
    const t = setTimeout(() => {
      Promise.all([
        prospApi('/empresas', { query: { q: termo, marca, desde, ate, limit: 6, ordem: 'nome' } }),
        prospApi('/contactos', { query: { q: termo, marca, desde, ate, limit: 6, ordem: 'nome' } }),
      ]).then(([emp, pes]) => {
        if (stop) return;
        const empresas = (emp.rows || []).map(r => ({ ...r, tipo: 'empresa' }));
        const contactos = (pes.rows || []).map(r => ({ ...r, tipo: 'contacto' }));
        setRows([...empresas, ...contactos]);
        setFoco(0);
      }).catch(() => { if (!stop) setRows([]); })
        .finally(() => { if (!stop) setLoading(false); });
    }, 180);
    return () => { stop = true; clearTimeout(t); };
  }, [q, marca, desde, ate]);
  const abrir = (r) => {
    if (!r) return;
    onOpen(r.tipo === 'contacto' ? { id: r.empresa_id, nome: r.empresa_nome, pais: r.pais, fonte: r.fonte, estado: r.empresa_estado } : r);
    onClose();
  };
  const onKeyDown = (e) => {
    if (e.key === 'ArrowDown') { e.preventDefault(); setFoco(i => Math.min(rows.length - 1, i + 1)); }
    if (e.key === 'ArrowUp') { e.preventDefault(); setFoco(i => Math.max(0, i - 1)); }
    if (e.key === 'Enter') { e.preventDefault(); abrir(rows[foco]); }
  };
  const termo = q.trim();
  return (
    <div role="dialog" aria-label="Procurar empresas e contactos" onMouseDown={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 9999, background: 'rgba(0,0,0,.78)',
      display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24,
    }}>
      <button type="button" aria-label="Fechar" onMouseDown={e => e.stopPropagation()} onClick={onClose} style={{
        position: 'absolute', top: 18, right: 22, width: 36, height: 36, border: 'none', background: 'transparent',
        color: '#fff', fontSize: 26, lineHeight: 1, cursor: 'pointer', fontFamily: 'inherit',
      }}>×</button>
      <div onMouseDown={e => e.stopPropagation()} style={{ width: 'min(920px, 100%)' }}>
        <style>{'.prosp-procurar::placeholder{color:rgba(255,255,255,.65)}'}</style>
        <div style={{ display: 'flex', alignItems: 'center', gap: 16, borderBottom: '1px solid rgba(255,255,255,.85)', paddingBottom: 8 }}>
          <input ref={inputRef} className="prosp-procurar" value={q} onChange={e => setQ(e.target.value)} onKeyDown={onKeyDown}
            placeholder="Procurar" aria-label="Procurar"
            style={{ flex: 1, height: 48, border: 'none', outline: 'none', background: 'transparent', color: '#fff', fontSize: 22, fontFamily: 'inherit', fontWeight: 400 }} />
          <svg width="22" height="22" viewBox="0 0 16 16" fill="none" stroke="#fff" strokeWidth="1.6" strokeLinecap="round" aria-hidden="true"><circle cx="7" cy="7" r="4.25" /><path d="M10.5 10.5L13.5 13.5" /></svg>
        </div>
        {termo.length >= 2 && (
          <div style={{ marginTop: 8 }}>
            {loading && !rows.length && <div style={{ padding: '12px 4px', fontSize: 14, color: 'rgba(255,255,255,.75)' }}>A procurar…</div>}
            {!loading && !rows.length && <div style={{ padding: '12px 4px', fontSize: 14, color: 'rgba(255,255,255,.75)' }}>Nenhuma empresa nem contacto.</div>}
            {rows.map((r, i) => (
              <button key={`${r.tipo}-${r.id}`} type="button" onMouseEnter={() => setFoco(i)} onClick={() => abrir(r)} style={{
                display: 'flex', width: '100%', textAlign: 'left', gap: 12, alignItems: 'baseline',
                background: i === foco ? 'rgba(255,255,255,.14)' : 'transparent',
                border: 'none', borderRadius: 6, padding: '10px 8px', cursor: 'pointer', fontFamily: 'inherit', color: '#fff',
              }}>
                <span style={{ fontSize: 11, fontWeight: 650, letterSpacing: '.04em', textTransform: 'uppercase', color: 'rgba(255,255,255,.6)', minWidth: 72 }}>{r.tipo === 'contacto' ? 'Contacto' : 'Empresa'}</span>
                <span style={{ fontSize: 16, fontWeight: 600 }}>{r.tipo === 'contacto' ? (prospNomeDe(r) || '—') : (prospSemAsteriscos(r.nome) || '—')}</span>
                <span style={{ fontSize: 13, color: 'rgba(255,255,255,.72)' }}>{r.tipo === 'contacto' ? [r.cargo, r.empresa_nome, r.email].map(prospSemAsteriscos).filter(Boolean).join(' · ') : [r.dominio, r.cidade, r.pais].map(prospSemAsteriscos).filter(Boolean).join(' · ')}</span>
              </button>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

const prospNorm = (s) => String(s || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().replace(/\s+/g, ' ').trim();

function prospOrdemMarca(nomes) {
  const tabs = (window.MKT_BRANDS || [
    { nome: 'Mimaki' }, { nome: 'BIOND' }, { nome: 'Decal' },
  ]).map(b => prospNorm(b.nome || b.name));
  return [...nomes].sort((a, b) => {
    const ia = tabs.indexOf(prospNorm(a));
    const ib = tabs.indexOf(prospNorm(b));
    return (ia < 0 ? 99 : ia) - (ib < 0 ? 99 : ib) || String(a).localeCompare(String(b), 'pt');
  });
}

function prospRotuloContrato(v) {
  const n = prospNorm(v);
  if (n === 'gold') return 'Gold';
  if (n === 'platino') return 'Platino';
  return v || '';
}

function prospEmails(p) {
  return Array.isArray(p?.emails) ? p.emails.filter(Boolean) : [];
}

function prospIdPartner(p) {
  return `${p.id}|${p.marca || ''}`;
}

const PROSP_ZONAS = {
  PT: ['Açores', 'Aveiro', 'Beja', 'Braga', 'Bragança', 'Castelo Branco', 'Coimbra', 'Évora', 'Faro', 'Guarda', 'Leiria', 'Lisboa', 'Madeira', 'Portalegre', 'Porto', 'Santarém', 'Setúbal', 'Viana do Castelo', 'Vila Real', 'Viseu'],
  ES: ['Andalucía', 'Aragón', 'Asturias', 'Canarias', 'Cantabria', 'Castilla y León', 'Castilla-La Mancha', 'Cataluña', 'Ceuta', 'Comunidad de Madrid', 'Comunidad Valenciana', 'Extremadura', 'Galicia', 'Illes Balears', 'La Rioja', 'Melilla', 'Navarra', 'País Vasco (Euskadi)', 'Región de Murcia'],
};
const PROSP_MARCAS_MERCADO = ['Mimaki', 'BIOND', 'Decal', 'AllDecor', 'Sensek', 'NetScreen'];

function ProspMercadoCats({ items, value, onChange }) {
  return (
    <div style={{ display: 'flex', gap: 12 }}>
      {items.map(k => {
        const on = value === k.id;
        return (
          <button key={k.id} type="button" onClick={() => onChange(k.id)} style={{ flex: '1 1 0', textAlign: 'left', background: '#fff', border: `1px solid ${on ? k.accent : 'var(--border)'}`, borderRadius: 8, padding: '12px 16px 0', cursor: 'pointer', fontFamily: 'inherit', display: 'flex', flexDirection: 'column', gap: 4, overflow: 'hidden' }}>
            <div style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: '0.10em', textTransform: 'uppercase', color: on ? k.accent : 'var(--text-muted)', fontFamily: 'var(--font-mono)' }}>{k.label}</div>
            <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'var(--font-display)', color: k.accent, lineHeight: 1, paddingBottom: 10 }}>{prospNum(k.n)}</div>
            <div style={{ height: 3, background: 'var(--bg-sunken)', overflow: 'hidden' }}><div style={{ height: '100%', width: on ? '100%' : '0%', background: k.accent }} /></div>
          </button>
        );
      })}
    </div>
  );
}

function ProspZonaBtn({ zona, on, admin, mostrarMarca, mostrarEquipa, onClick }) {
  return (
    <button type="button" onClick={onClick} disabled={!admin} title={zona.nivel === 'pais' ? 'País inteiro' : (zona.detalhe || 'Zona inteira')} style={{
      textAlign: 'left', borderRadius: 8, padding: '7px 10px', maxWidth: 360, fontFamily: 'inherit', color: 'var(--text)',
      border: `1px solid ${on ? 'var(--ai-500)' : 'var(--border)'}`,
      background: on ? 'color-mix(in oklch, var(--ai-500, #3859D0) 10%, #fff)' : '#fff',
      cursor: admin ? 'pointer' : 'default',
    }}>
      <div style={{ fontSize: 12.5, fontWeight: 650 }}>{zona.zona}{zona.pais ? ` · ${zona.pais}` : ''}</div>
      <div style={{ fontSize: 11, lineHeight: 1.35, color: 'var(--text-muted)', marginTop: 2 }}>{zona.nivel === 'pais' ? 'País inteiro' : (zona.detalhe || 'Zona inteira')}</div>
      {(mostrarMarca || mostrarEquipa) && (
        <div style={{ fontSize: 10, letterSpacing: '.04em', textTransform: 'uppercase', color: 'var(--text-dim)', marginTop: 4 }}>{[mostrarMarca ? zona.marca : '', mostrarEquipa ? zona.equipa_code : ''].filter(Boolean).join(' · ')}</div>
      )}
    </button>
  );
}

function prospPessoasDe(rows) {
  const mapa = new Map();
  rows.forEach(r => {
    if (!mapa.has(r.pessoa_nome)) mapa.set(r.pessoa_nome, { nome: r.pessoa_nome, email: '', equipas: new Set(), zs: [] });
    const p = mapa.get(r.pessoa_nome);
    if (r.colaborador_email) p.email = r.colaborador_email;
    if (r.equipa_code) p.equipas.add(r.equipa_code);
    p.zs.push(r);
  });
  return [...mapa.values()].map(p => ({
    nome: p.nome,
    email: p.email,
    equipas: [...p.equipas],
    zs: [...p.zs].sort((a, b) => a.zona.localeCompare(b.zona, 'pt') || String(a.marca).localeCompare(String(b.marca), 'pt')),
  })).sort((a, b) => a.nome.localeCompare(b.nome, 'pt'));
}

function prospRankMarca(nome) {
  const i = PROSP_MARCAS_MERCADO.findIndex(m => prospNorm(m) === prospNorm(nome));
  return i < 0 ? 99 : i;
}

function ProspMercados({ marca, marcaLabel, filtroSlot, admin }) {
  const [cat, setCat] = React.useState('equipas');
  const [pais, setPais] = React.useState('');
  const [marcaLocal, setMarcaLocal] = React.useState('');
  const [q, setQ] = React.useState('');
  const [territorios, setTerritorios] = React.useState([]);
  const [partners, setPartners] = React.useState([]);
  const [paisesCat, setPaisesCat] = React.useState([{ iso: 'PT', nome: 'Portugal' }, { iso: 'ES', nome: 'Espanha' }]);
  const [locais, setLocais] = React.useState([]);
  const [concelhosSel, setConcelhosSel] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [erro, setErro] = React.useState('');
  const [aviso, setAviso] = React.useState('');
  const [edicao, setEdicao] = React.useState(null);
  const [aGravar, setAGravar] = React.useState(false);
  const [confirmar, setConfirmar] = React.useState(false);

  const carregar = React.useCallback(() => {
    setLoading(true);
    return Promise.all([prospApi('/mercados/territorios'), prospApi('/mercados/partners')])
      .then(([t, p]) => {
        setTerritorios(t.rows || []);
        setPartners(p.rows || []);
        if (t.paises?.length) setPaisesCat(t.paises);
        setErro('');
      })
      .catch(e => setErro(e.message))
      .finally(() => setLoading(false));
  }, []);
  React.useEffect(() => { carregar(); }, [carregar]);
  React.useEffect(() => { setEdicao(null); setConfirmar(false); }, [marca, cat]);
  React.useEffect(() => {
    if (!edicao || edicao.tipo !== 'zona' || !edicao.pais || !edicao.zona || (edicao.pais !== 'PT' && edicao.pais !== 'ES')) { setLocais([]); return undefined; }
    let stop = false;
    const detalhe = edicao.detalhe;
    prospApi('/mercados/locais', { query: { pais: edicao.pais, zona: edicao.zona } })
      .then(d => {
        if (stop) return;
        const nomes = d.rows || [];
        const det = prospNorm(detalhe);
        setLocais(nomes);
        setConcelhosSel(nomes.filter(n => det.includes(prospNorm(n))));
      })
      .catch(() => { if (!stop) setLocais([]); });
    return () => { stop = true; };
  }, [edicao?.tipo, edicao?.id, edicao?.pais, edicao?.zona]);

  const marcaUsada = marcaLabel || marcaLocal;
  const nomePais = (code) => paisesCat.find(p => p.iso === code)?.nome || (code === 'PT' ? 'Portugal' : code === 'ES' ? 'Espanha' : code);
  const paisInteiro = (code) => code && code !== 'PT' && code !== 'ES';
  const qn = prospNorm(q);
  const baseTerr = React.useMemo(() => territorios.filter(r => {
    if (marcaUsada && prospNorm(r.marca) !== prospNorm(marcaUsada)) return false;
    if (pais && r.pais !== pais) return false;
    if (qn && ![r.pessoa_nome, r.zona, r.detalhe, r.equipa_code, r.colaborador_email, r.marca].some(v => prospNorm(v).includes(qn))) return false;
    return true;
  }), [territorios, marcaUsada, pais, qn]);
  const pessoas = React.useMemo(() => prospPessoasDe(baseTerr), [baseTerr]);
  const equipas = React.useMemo(() => {
    const mapa = new Map();
    baseTerr.forEach(r => {
      const code = r.equipa_code || 'Sem equipa';
      if (!mapa.has(code)) mapa.set(code, []);
      mapa.get(code).push(r);
    });
    return [...mapa.entries()].map(([code, zs]) => {
      const marcas = [...new Set(zs.map(z => z.marca))];
      const paises = [...new Set(zs.map(z => z.pais))];
      const partidas = [];
      const porZona = new Map();
      zs.forEach(z => {
        const k = `${z.pais}|${z.zona}`;
        if (!porZona.has(k)) porZona.set(k, []);
        if (!porZona.get(k).includes(z.pessoa_nome)) porZona.get(k).push(z.pessoa_nome);
      });
      porZona.forEach((nomes, k) => { if (nomes.length > 1) partidas.push({ zona: k.split('|')[1], nomes }); });
      return { code, marcas, paises, pessoas: prospPessoasDe(zs), partidas, nZonas: zs.length };
    }).sort((a, b) => prospRankMarca(a.marcas[0]) - prospRankMarca(b.marcas[0]) || a.code.localeCompare(b.code, 'pt'));
  }, [baseTerr]);
  const baseP = React.useMemo(() => partners.filter(p => {
    if (marcaUsada && prospNorm(p.marca) !== prospNorm(marcaUsada)) return false;
    if (pais && p.pais !== pais) return false;
    if (qn && ![p.nome, p.territorio, p.segmento, p.contrato, p.marca, ...(prospEmails(p))].some(v => prospNorm(v).includes(qn))) return false;
    return true;
  }), [partners, marcaUsada, pais, qn]);
  const gruposPartner = React.useMemo(() => {
    const mapa = new Map();
    baseP.forEach(p => {
      const marcaNome = p.marca || 'Sem marca';
      if (!mapa.has(marcaNome)) mapa.set(marcaNome, []);
      mapa.get(marcaNome).push(p);
    });
    return prospOrdemMarca([...mapa.keys()]).map(nome => {
      const rows = mapa.get(nome).slice().sort((a, b) => String(a.pais).localeCompare(String(b.pais)) || a.nome.localeCompare(b.nome, 'pt'));
      const porPais = new Map();
      rows.forEach(r => {
        if (!porPais.has(r.pais)) porPais.set(r.pais, []);
        porPais.get(r.pais).push(r);
      });
      return { nome, paises: [...porPais.entries()] };
    });
  }, [baseP]);

  const paisesFiltro = React.useMemo(() => {
    const codes = new Set(['PT', 'ES', ...territorios.map(r => r.pais), ...partners.map(p => p.pais)]);
    const rank = (c) => `${c === 'PT' ? '0' : c === 'ES' ? '1' : '2'}${nomePais(c)}`;
    return [...codes].filter(Boolean).sort((a, b) => rank(a).localeCompare(rank(b), 'pt')).map(c => ({ value: c, label: nomePais(c) }));
  }, [territorios, partners, paisesCat]);
  const marcasOpcoes = React.useMemo(() => {
    const nomes = new Set([...territorios.map(r => r.marca), ...partners.map(p => p.marca)].filter(Boolean));
    PROSP_MARCAS_MERCADO.forEach(m => nomes.add(m));
    return prospOrdemMarca([...nomes]);
  }, [territorios, partners]);

  const abrirZona = (r, ancora) => {
    if (!admin) return;
    setAviso(''); setConfirmar(false); setErro('');
    setEdicao({
      tipo: 'zona', id: r.id, ancora, marca: r.marca, pais: r.pais, zona: r.zona, detalhe: r.detalhe || '',
      pessoa_nome: r.pessoa_nome, colaborador_email: r.colaborador_email || '', equipa_code: r.equipa_code || '',
    });
  };
  const novaZona = (pessoa, equipaCode, ancora) => {
    if (!admin) return;
    setAviso(''); setConfirmar(false); setErro('');
    const amostra = pessoa?.zs?.[0];
    const paisIni = pais || amostra?.pais || 'PT';
    setEdicao({
      tipo: 'zona', id: null, ancora: ancora || '',
      marca: marcaUsada || amostra?.marca || 'Mimaki',
      pais: paisIni,
      zona: paisInteiro(paisIni) ? (nomePais(paisIni) === paisIni ? (amostra?.zona || '') : nomePais(paisIni)) : '',
      detalhe: '',
      pessoa_nome: pessoa?.nome || '',
      colaborador_email: pessoa?.email || '',
      equipa_code: equipaCode || pessoa?.equipas?.[0] || '',
    });
  };
  const abrirPartner = (r) => {
    if (!admin || !r.marca_id) return;
    setAviso(''); setConfirmar(false); setErro('');
    setEdicao({
      tipo: 'partner', id: r.marca_id, nome: r.nome, marca: r.marca || '', pais: r.pais,
      territorio: r.territorio || '', contrato: r.contrato || '', segmento: r.segmento || '',
    });
  };
  const setCampo = (k, v) => { setConfirmar(false); setEdicao(p => (p ? { ...p, [k]: v } : p)); };
  const alternarConcelho = (nome) => {
    setConcelhosSel(prev => {
      const next = prev.includes(nome) ? prev.filter(x => x !== nome) : [...prev, nome].sort((a, b) => a.localeCompare(b, 'pt'));
      setCampo('detalhe', next.join(', '));
      return next;
    });
  };
  const zonasDePais = (paisCode) => PROSP_ZONAS[paisCode] || [];
  const alternarZonaPartner = (zona) => {
    const lista = zonasDePais(edicao?.pais);
    const actuais = String(edicao?.territorio || '').split(',').map(s => s.trim()).filter(Boolean);
    const conhecidas = new Set(lista);
    const escolhidas = actuais.filter(z => conhecidas.has(z));
    const outras = actuais.filter(z => !conhecidas.has(z));
    const next = escolhidas.includes(zona) ? escolhidas.filter(z => z !== zona) : [...escolhidas, zona];
    setCampo('territorio', [...outras, ...next].join(', '));
  };
  const gravar = async () => {
    if (!edicao) return;
    setAGravar(true); setErro(''); setAviso('');
    try {
      if (edicao.tipo === 'partner') {
        await prospApi(`/mercados/partners/${edicao.id}`, { method: 'PATCH', body: { territorio: edicao.territorio, contrato: edicao.contrato, segmento: edicao.segmento } });
        setAviso('Território do partner actualizado.');
      } else {
        const body = {
          marca: edicao.marca, pais: edicao.pais, zona: edicao.zona, detalhe: edicao.detalhe,
          pessoa_nome: edicao.pessoa_nome, colaborador_email: edicao.colaborador_email, equipa_code: edicao.equipa_code,
        };
        await prospApi(edicao.id ? `/mercados/territorios/${edicao.id}` : '/mercados/territorios', { method: edicao.id ? 'PATCH' : 'POST', body });
        setAviso(edicao.id ? 'Território actualizado.' : 'Território criado.');
      }
      setEdicao(null);
      await carregar();
    } catch (e) { setErro(e.message); }
    finally { setAGravar(false); }
  };
  const retirar = async () => {
    if (!edicao?.id || edicao.tipo !== 'zona') return;
    if (!confirmar) { setConfirmar(true); return; }
    setAGravar(true); setErro('');
    try {
      await prospApi(`/mercados/territorios/${edicao.id}`, { method: 'DELETE' });
      setEdicao(null); setConfirmar(false);
      setAviso('Zona retirada.');
      await carregar();
    } catch (e) { setErro(e.message); }
    finally { setAGravar(false); }
  };

  const zonasDoPais = PROSP_ZONAS[edicao?.pais] || [];
  const edicaoPais = edicao && paisInteiro(edicao.pais);
  const formulario = edicao && edicao.tipo === 'zona' && (
    <div style={{ marginTop: 12, padding: 12, borderRadius: 8, background: '#f8fafc', border: '1px solid var(--border)', display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ fontWeight: 650 }}>{edicao.id ? `${edicao.pessoa_nome} · ${edicao.zona || (edicaoPais ? 'país' : 'zona')}` : (edicaoPais ? 'Novo país' : 'Nova zona')}</div>
      <ProspGrelha>
        <ProspField label="Comercial"><input style={prospInput} list="prosp-comerciais" value={edicao.pessoa_nome} onChange={e => setCampo('pessoa_nome', e.target.value)} /></ProspField>
        <ProspField label="Email"><input style={prospInput} value={edicao.colaborador_email} onChange={e => setCampo('colaborador_email', e.target.value)} /></ProspField>
        <ProspField label="Equipa"><input style={prospInput} list="prosp-equipas" value={edicao.equipa_code} onChange={e => setCampo('equipa_code', e.target.value)} /></ProspField>
        <ProspField label="Marca">
          <select style={prospInput} value={edicao.marca} onChange={e => setCampo('marca', e.target.value)}>
            {PROSP_MARCAS_MERCADO.map(m => <option key={m} value={m}>{m}</option>)}
          </select>
        </ProspField>
        <ProspField label="País">
          <select style={prospInput} value={edicao.pais} onChange={e => {
            const code = e.target.value;
            setConcelhosSel([]);
            setEdicao(p => ({
              ...p,
              pais: code,
              zona: PROSP_ZONAS[code] ? (PROSP_ZONAS[code].includes(p.zona) ? p.zona : '') : nomePais(code),
              detalhe: '',
            }));
          }}>
            {paisesCat.map(p => <option key={p.iso} value={p.iso}>{p.nome}</option>)}
          </select>
        </ProspField>
        {zonasDoPais.length > 0 && (
          <ProspField label="Zona">
            <select style={prospInput} value={edicao.zona} onChange={e => { setCampo('zona', e.target.value); setCampo('detalhe', ''); setConcelhosSel([]); }}>
              <option value="">Escolher…</option>
              {zonasDoPais.map(z => <option key={z} value={z}>{z}</option>)}
            </select>
          </ProspField>
        )}
      </ProspGrelha>
      {edicaoPais ? (
        <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>O país inteiro fica com este comercial. As empresas e os contactos desse país passam a estar indexados a esta equipa.</div>
      ) : (
      <div>
        <div style={{ fontSize: 12, fontWeight: 650, marginBottom: 6 }}>Concelhos</div>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 8 }}>Nenhum seleccionado cobre a zona inteira. Os seleccionados ficam só com este comercial.</div>
        {locais.length ? (
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {locais.map(nome => {
              const on = concelhosSel.includes(nome);
              return (
                <button key={nome} type="button" onClick={() => alternarConcelho(nome)} style={{
                  border: `1px solid ${on ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 999, padding: '4px 10px', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12,
                  background: on ? 'color-mix(in oklch, var(--ai-500, #3859D0) 12%, #fff)' : '#fff', color: on ? 'var(--ai-500)' : 'var(--text)',
                }}>{nome}</button>
              );
            })}
          </div>
        ) : <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{edicao.zona ? 'O índice não tem concelhos para esta zona. A cobertura é a zona inteira.' : 'Escolhe a zona para ver os concelhos.'}</div>}
      </div>
      )}
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
        <button type="button" className="btn btn-sm btn-ai" disabled={aGravar} onClick={gravar}>{aGravar ? 'A gravar…' : 'Guardar'}</button>
        {edicao.id && <button type="button" className="btn btn-sm" disabled={aGravar} onClick={retirar}>{confirmar ? 'Confirmar e retirar' : (edicaoPais ? 'Retirar país' : 'Retirar zona')}</button>}
        <button type="button" className="btn btn-sm btn-ghost" disabled={aGravar} onClick={() => { setEdicao(null); setConfirmar(false); }}>Cancelar</button>
      </div>
    </div>
  );
  const formAqui = (ancora) => (edicao?.tipo === 'zona' && edicao.ancora === ancora ? formulario : null);

  const blocoPessoa = (pessoa, equipaCode, ancoraBase) => {
    const ancora = `${ancoraBase}|${pessoa.nome}`;
    return (
      <div key={ancora} style={{ padding: '14px 16px', borderTop: '1px solid var(--border)' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, alignItems: 'flex-start' }}>
          <div>
            <div style={{ fontWeight: 650 }}>{pessoa.nome}</div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>{pessoa.email || 'Sem email no Gestor'}</div>
          </div>
          {admin && <button type="button" className="btn btn-sm btn-ghost" onClick={() => novaZona(pessoa, equipaCode, ancora)}>{pessoa.zs.length && pessoa.zs.every(z => z.nivel === 'pais') ? '+ País' : '+ Zona'}</button>}
        </div>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 10 }}>
          {pessoa.zs.filter(z => !equipaCode || z.equipa_code === equipaCode).map(z => (
            <ProspZonaBtn key={z.id} zona={z} admin={admin} on={edicao?.tipo === 'zona' && edicao.id === z.id}
              mostrarMarca={!marcaUsada && new Set(pessoa.zs.map(x => x.marca)).size > 1}
              mostrarEquipa={!equipaCode && pessoa.equipas.length > 1}
              onClick={() => abrirZona(z, ancora)} />
          ))}
        </div>
        {formAqui(ancora)}
      </div>
    );
  };

  const vazio = (texto) => (
    <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: 28, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>{texto}</div>
  );

  const painelEquipas = loading && !territorios.length ? vazio('A carregar…') : !equipas.length ? vazio(q ? 'Nenhuma equipa corresponde à procura.' : 'Sem equipas com estes filtros.') : (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      {formAqui('')}
      {equipas.map(eq => (
        <section key={eq.code} style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, overflow: 'hidden' }}>
          <header style={{ padding: '14px 16px', display: 'flex', justifyContent: 'space-between', gap: 12, alignItems: 'center' }}>
            <div>
              <div style={{ fontSize: 15, fontWeight: 700, fontFamily: 'var(--font-display)' }}>{prospEquipa(eq.code)}</div>
              <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 3 }}>
                {[eq.marcas.join(', '), eq.paises.map(nomePais).join(', '), `${eq.pessoas.length} ${eq.pessoas.length === 1 ? 'comercial' : 'comerciais'}`, eq.pessoas.every(p => p.zs.every(z => z.nivel === 'pais')) ? `${eq.nZonas} ${eq.nZonas === 1 ? 'país' : 'países'}` : `${eq.nZonas} ${eq.nZonas === 1 ? 'zona' : 'zonas'}`].join(' · ')}
              </div>
            </div>
          </header>
          {eq.partidas.length > 0 && (
            <div style={{ padding: '0 16px 12px', fontSize: 12, color: 'var(--text-muted)' }}>
              Zonas partilhadas: {eq.partidas.map(z => `${z.zona} (${z.nomes.join(', ')})`).join(' · ')}
            </div>
          )}
          {eq.pessoas.map(p => blocoPessoa(p, eq.code, `eq:${eq.code}`))}
        </section>
      ))}
    </div>
  );

  const painelComerciais = loading && !territorios.length ? vazio('A carregar…') : !pessoas.length ? vazio(q ? 'Nenhum comercial corresponde à procura.' : 'Sem comerciais com estes filtros.') : (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: 12 }}>
      {edicao?.tipo === 'zona' && edicao.ancora === '' && <div style={{ gridColumn: '1 / -1' }}>{formulario}</div>}
      {pessoas.map(p => {
        const ancora = `ps:${p.nome}`;
        const aberto = edicao?.tipo === 'zona' && edicao.ancora === ancora;
        return (
          <section key={p.nome} style={{ gridColumn: aberto ? '1 / -1' : undefined, background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: 14 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, alignItems: 'flex-start' }}>
              <div>
                <div style={{ fontWeight: 650 }}>{p.nome}</div>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }}>{p.email || 'Sem email no Gestor'}</div>
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 8 }}>
                  {p.equipas.map(code => <span key={code} style={{ fontSize: 10, fontWeight: 650, letterSpacing: '.04em', textTransform: 'uppercase', color: '#0891b2', background: '#ecfeff', borderRadius: 999, padding: '3px 8px' }}>{code}</span>)}
                </div>
              </div>
              {admin && <button type="button" className="btn btn-sm btn-ghost" onClick={() => novaZona(p, p.equipas[0] || '', ancora)}>{p.zs.length && p.zs.every(z => z.nivel === 'pais') ? '+ País' : '+ Zona'}</button>}
            </div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 12 }}>
              {p.zs.map(z => (
                <ProspZonaBtn key={z.id} zona={z} admin={admin} on={edicao?.tipo === 'zona' && edicao.id === z.id}
                  mostrarMarca={!marcaUsada}
                  mostrarEquipa={p.equipas.length > 1}
                  onClick={() => abrirZona(z, ancora)} />
              ))}
            </div>
            {formAqui(ancora)}
          </section>
        );
      })}
    </div>
  );

  const formPartner = (r) => edicao?.tipo === 'partner' && edicao.id === r.marca_id && (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 12 }} onClick={e => e.stopPropagation()}>
      {zonasDePais(edicao.pais).length ? (
        <div>
          <div style={{ fontSize: 12, fontWeight: 650, marginBottom: 6 }}>Zonas</div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {zonasDePais(edicao.pais).map(zona => {
              const on = String(edicao.territorio || '').split(',').map(s => s.trim()).includes(zona);
              return (
                <button key={zona} type="button" onClick={() => alternarZonaPartner(zona)} style={{
                  border: `1px solid ${on ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 999, padding: '4px 10px', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12,
                  background: on ? 'color-mix(in oklch, var(--ai-500, #3859D0) 12%, #fff)' : '#fff', color: on ? 'var(--ai-500)' : 'var(--text)',
                }}>{zona}</button>
              );
            })}
          </div>
        </div>
      ) : (
        <ProspField label="Território"><input style={prospInput} value={edicao.territorio} onChange={e => setCampo('territorio', e.target.value)} /></ProspField>
      )}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
        <ProspField label="Contrato"><input style={prospInput} value={edicao.contrato} onChange={e => setCampo('contrato', e.target.value)} placeholder="Gold, Platino…" /></ProspField>
        <ProspField label="Segmento"><input style={prospInput} value={edicao.segmento} onChange={e => setCampo('segmento', e.target.value)} /></ProspField>
      </div>
      <div style={{ display: 'flex', gap: 8 }}>
        <button type="button" className="btn btn-sm btn-ai" disabled={aGravar} onClick={gravar}>{aGravar ? 'A gravar…' : 'Guardar'}</button>
        <button type="button" className="btn btn-sm btn-ghost" disabled={aGravar} onClick={() => setEdicao(null)}>Cancelar</button>
      </div>
    </div>
  );

  const painelPartners = loading && !partners.length ? vazio('A carregar…') : !gruposPartner.length ? vazio(q ? 'Nenhum partner corresponde à procura.' : 'Sem partners com estes filtros.') : (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      {gruposPartner.map(g => (
        <section key={g.nome} style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div style={{ fontSize: 11, fontWeight: 650, letterSpacing: '.06em', textTransform: 'uppercase', color: 'var(--text-dim)' }}>{g.nome}</div>
          {g.paises.map(([paisCode, rows]) => (
            <div key={paisCode} style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{nomePais(paisCode)}</div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 10 }}>
                {rows.map(r => {
                  const aberto = edicao?.tipo === 'partner' && edicao.id === r.marca_id;
                  const emails = prospEmails(r);
                  return (
                    <div key={r.marca_id || prospIdPartner(r)} onClick={() => abrirPartner(r)} style={{ gridColumn: aberto ? '1 / -1' : undefined, background: '#fff', border: `1px solid ${aberto ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 10, padding: 14, cursor: admin && r.marca_id ? 'pointer' : 'default' }}>
                      <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'flex-start' }}>
                        <div style={{ fontWeight: 650 }}>{r.nome}</div>
                        {r.contrato ? <span style={{ fontSize: 10, fontWeight: 650, letterSpacing: '.04em', textTransform: 'uppercase', color: '#7c3aed', background: '#f5f3ff', borderRadius: 999, padding: '3px 8px', flexShrink: 0 }}>{prospRotuloContrato(r.contrato)}</span> : null}
                      </div>
                      <div style={{ fontSize: 13, marginTop: 8, lineHeight: 1.4 }}>{r.territorio || 'Sem território definido'}</div>
                      {r.segmento ? <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 6, lineHeight: 1.4 }}>{r.segmento}</div> : null}
                      {emails.length > 0 && <div style={{ fontSize: 11, color: 'var(--text-dim)', marginTop: 8 }}>{emails.join(' · ')}</div>}
                      {formPartner(r)}
                    </div>
                  );
                })}
              </div>
            </div>
          ))}
        </section>
      ))}
    </div>
  );

  const notas = {
    equipas: 'Em Portugal e Espanha, define o distrito ou a comunidade. Sem concelhos, a zona fica inteira. Fora da Ibéria, o país inteiro fica com o comercial e as empresas entram por esse país.',
    comerciais: 'Os mesmos territórios, a partir de cada comercial. Em Portugal e Espanha podes limitar por concelho. Fora da Ibéria, a cobertura é o país.',
    partners: 'Escolhe as zonas do partner. Não recebem empresas da prospeção.',
  };
  const barra = (
    <>
      {!marca && (
        <ProspDrop label="Marca" value={marcaUsada} onChange={setMarcaLocal} options={[{ value: '', label: 'Todas' }, ...marcasOpcoes.map(m => ({ value: m, label: m }))]} />
      )}
      <ProspDrop label="País" value={pais} onChange={setPais} options={[{ value: '', label: 'Todos' }, ...paisesFiltro]} />
      <input value={q} onChange={e => setQ(e.target.value)} placeholder="Procurar comercial, zona ou partner" style={{ border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', fontSize: 12, background: '#fff', color: 'var(--text)', minWidth: 220, fontFamily: 'inherit' }} />
    </>
  );

  return (
    <>
      {filtroSlot && ReactDOM.createPortal(barra, filtroSlot)}
      <datalist id="prosp-comerciais">{[...new Set(territorios.map(r => r.pessoa_nome))].map(n => <option key={n} value={n} />)}</datalist>
      <datalist id="prosp-equipas">{[...new Set(territorios.map(r => r.equipa_code).filter(Boolean))].map(n => <option key={n} value={n} />)}</datalist>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        {erro && <ProspMsg msg={{ tipo: 'erro', texto: erro }} />}
        {aviso && <ProspMsg msg={{ tipo: 'ok', texto: aviso }} />}
        <ProspMercadoCats value={cat} onChange={(id) => { setCat(id); setAviso(''); }} items={[
          { id: 'equipas', label: 'Equipas', n: equipas.length, accent: '#0891b2' },
          { id: 'comerciais', label: 'Comerciais', n: pessoas.length, accent: '#3859D0' },
          { id: 'partners', label: 'Partners', n: baseP.length, accent: '#7c3aed' },
        ]} />
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
          <div style={{ fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.4 }}>{notas[cat]}</div>
          {admin && cat !== 'partners' && <button type="button" className="btn btn-sm btn-ai" onClick={() => novaZona(null, '', '')}>Novo território</button>}
        </div>
        {cat === 'equipas' && painelEquipas}
        {cat === 'comerciais' && painelComerciais}
        {cat === 'partners' && painelPartners}
      </div>
    </>
  );
}

function ProspCarteira({ marca, filtroSlot, admin, onAplicada }) {
  const [pais, setPais] = React.useState('');
  const [dados, setDados] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [erro, setErro] = React.useState('');
  const [aviso, setAviso] = React.useState('');
  const [tick, setTick] = React.useState(0);
  const [aGestor, setAGestor] = React.useState(false);
  const [confirmarGestor, setConfirmarGestor] = React.useState(false);
  const [aMaps, setAMaps] = React.useState('');
  const [runs, setRuns] = React.useState([]);
  const [escolhas, setEscolhas] = React.useState({});
  const [aGravar, setAGravar] = React.useState(false);
  const [confirmarMaps, setConfirmarMaps] = React.useState(false);
  const [equipaSel, setEquipaSel] = React.useState('');
  const [comercialSel, setComercialSel] = React.useState('');
  const [livro, setLivro] = React.useState(null);
  const [livroPag, setLivroPag] = React.useState(1);
  const [livroLoading, setLivroLoading] = React.useState(false);
  const [associar, setAssociar] = React.useState(null);
  const [associarOn, setAssociarOn] = React.useState(false);
  const [soSem, setSoSem] = React.useState(true);
  const [recalcular, setRecalcular] = React.useState(false);
  const [aAssociar, setAAssociar] = React.useState(false);
  const [confirmarAssociar, setConfirmarAssociar] = React.useState(false);
  const activasKey = (dados?.activas || []).map(a => `${a.id}:${a.estado}:${a.pendente}`).join(',');

  React.useEffect(() => { setConfirmarGestor(false); setConfirmarMaps(false); }, [pais, marca]);
  React.useEffect(() => {
    let stop = false;
    setLoading(true);
    prospApi('/carteira', { query: { pais, marca: marca || undefined } })
      .then(d => { if (!stop) { setDados(d); setErro(''); } })
      .catch(e => { if (!stop) setErro(e.message); })
      .finally(() => { if (!stop) setLoading(false); });
    return () => { stop = true; };
  }, [pais, marca, tick]);

  React.useEffect(() => {
    const ids = (dados?.activas || []).map(a => a.id);
    if (!ids.length) { setRuns([]); return undefined; }
    let stop = false;
    let timer = null;
    const ler = async () => {
      try {
        const lista = [];
        for (const id of ids) {
          const d = await prospApi(`/runs/${id}`);
          lista.push(d.run);
        }
        if (stop) return;
        setRuns(lista);
        setEscolhas(prev => {
          const next = { ...prev };
          for (const run of lista) {
            const preview = run.parametros?.preview || [];
            const actual = next[run.id];
            if (actual && (Object.keys(actual).length || !preview.length)) continue;
            const sel = {};
            if (run.parametros?.modo !== 'nome') {
              for (const p of preview) {
                if (p.confirmado && (p.morada || p.codigo_postal || p.cidade)) sel[p.id] = true;
              }
            }
            next[run.id] = sel;
          }
          return next;
        });
        if (lista.some(r => r.estado === 'a_correr')) timer = setTimeout(ler, 3000);
      } catch (e) { if (!stop) setErro(e.message); }
    };
    ler();
    return () => { stop = true; if (timer) clearTimeout(timer); };
  }, [activasKey]);

  React.useEffect(() => { setEquipaSel(''); setComercialSel(''); setLivro(null); setLivroPag(1); }, [pais, marca]);
  React.useEffect(() => {
    if (!equipaSel) { setLivro(null); return undefined; }
    let stop = false;
    setLivroLoading(true);
    prospApi('/carteira/livro', { query: { pais, marca: marca || undefined, equipa: equipaSel, comercial: comercialSel || undefined, page: livroPag } })
      .then(d => { if (!stop) setLivro(d); })
      .catch(e => { if (!stop) setErro(e.message); })
      .finally(() => { if (!stop) setLivroLoading(false); });
    return () => { stop = true; };
  }, [equipaSel, comercialSel, livroPag, pais, marca, tick]);
  React.useEffect(() => {
    if (!associarOn) return undefined;
    let stop = false;
    setAssociar(null);
    prospApi('/reindexar', { query: { pais, marca: marca || undefined, so_sem_equipa: soSem ? '1' : '', recalcular: recalcular ? '1' : '' } })
      .then(d => { if (!stop) setAssociar(d); })
      .catch(e => { if (!stop) setErro(e.message); });
    return () => { stop = true; };
  }, [associarOn, soSem, recalcular, pais, marca, tick]);

  const aplicarGestor = async () => {
    setAGestor(true); setAviso('');
    try {
      const d = await prospApi('/carteira/gestor', { method: 'POST', body: { pais: pais || null, marca: marca || undefined } });
      setAviso(`${prospNum(d.gravadas)} empresas ficaram com cidade, código postal ou zona do Gestor. Associa as equipas mais abaixo.`);
      setConfirmarGestor(false);
      setTick(t => t + 1);
      onAplicada?.();
    } catch (e) { setErro(e.message); }
    finally { setAGestor(false); }
  };

  const pesquisarMaps = async (modo) => {
    setAMaps(modo); setAviso(''); setErro('');
    try {
      const d = await prospApi('/carteira/maps', { method: 'POST', body: { pais: pais || null, marca: marca || undefined, modo } });
      const n = (d.runs || []).reduce((s, r) => s + r.empresas, 0);
      setAviso(`Pesquisa de ${prospNum(n)} empresas no Google Maps. A morada só entra depois de confirmares.`);
      setTick(t => t + 1);
    } catch (e) { setErro(e.message); }
    finally { setAMaps(''); }
  };

  const gravarMaps = async () => {
    setAGravar(true); setAviso('');
    try {
      let n = 0;
      for (const run of runs) {
        const ids = Object.keys(escolhas[run.id] || {}).filter(id => escolhas[run.id][id]).map(Number);
        if (!ids.length) continue;
        const d = await prospApi('/carteira/maps/gravar', { method: 'POST', body: { run_id: run.id, ids } });
        n += d.gravadas || 0;
      }
      setAviso(`${prospNum(n)} moradas gravadas nas fichas que estavam vazias. Associa as equipas mais abaixo.`);
      setConfirmarMaps(false);
      setEscolhas({});
      setTick(t => t + 1);
      onAplicada?.();
    } catch (e) { setErro(e.message); }
    finally { setAGravar(false); }
  };

  const aplicarAssociar = async () => {
    setAAssociar(true); setAviso('');
    try {
      const d = await prospApi('/reindexar', { method: 'POST', body: { pais: pais || null, marca: marca || undefined, so_sem_equipa: soSem, recalcular } });
      setAviso(`${prospNum(d.aplicadas)} empresas actualizadas. ${prospNum(d.contactos)} contactos seguem essas empresas.`);
      setConfirmarAssociar(false);
      setTick(t => t + 1);
      onAplicada?.();
    } catch (e) { setErro(e.message); }
    finally { setAAssociar(false); }
  };

  const logicaEquipa = (code) => (String(code || '').startsWith('DECAL') ? 'Consumíveis Decal e BionD' : String(code || '').startsWith('MIMAKI') ? 'Equipamentos Mimaki' : '');
  const grupos = React.useMemo(() => {
    const mapa = new Map();
    for (const r of dados?.linhas || []) {
      if (!r.equipa) continue;
      if (!mapa.has(r.equipa)) mapa.set(r.equipa, []);
      mapa.get(r.equipa).push(r);
    }
    return [...mapa.entries()];
  }, [dados]);
  const semLinha = (dados?.linhas || []).find(r => !r.equipa);
  const aMudar = (associar?.novas?.empresas || 0) + (associar?.mudam?.empresas || 0) + (associar?.perdem?.empresas || 0);

  const barra = (
    <ProspDrop label="País" value={pais} onChange={setPais} options={[{ value: '', label: 'Todos' }, { value: 'PT', label: 'Portugal' }, { value: 'ES', label: 'Espanha' }]} />
  );
  const selecionadas = runs.reduce((s, run) => s + Object.values(escolhas[run.id] || {}).filter(Boolean).length, 0);
  const toggle = (runId, id) => setEscolhas(prev => ({ ...prev, [runId]: { ...(prev[runId] || {}), [id]: !prev[runId]?.[id] } }));

  return (
    <>
      {filtroSlot && ReactDOM.createPortal(barra, filtroSlot)}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        {erro && <ProspMsg msg={{ tipo: 'erro', texto: erro }} />}
        {aviso && <ProspMsg msg={{ tipo: 'ok', texto: aviso }} />}
        {loading && !dados && <div style={{ display: 'flex', alignItems: 'center', gap: 10, fontSize: 13, color: 'var(--text-muted)' }}><ProspSpin />A calcular…</div>}
        {dados && (
          <>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.45, maxWidth: 760 }}>
              {prospNum(dados.com_equipa)} empresas têm equipa ({prospNum(dados.contactos - dados.contactos_sem_equipa)} contactos) e {prospNum(dados.sem_equipa)} estão sem equipa ({prospNum(dados.contactos_sem_equipa)} contactos). A mesma empresa pode estar na Decal e na Mimaki. Decal trabalha consumíveis Decal e BionD. Mimaki trabalha equipamentos Mimaki.
            </div>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              {grupos.map(([code, pessoas]) => {
                const on = equipaSel === code;
                const empresas = pessoas.reduce((s, r) => s + r.empresas, 0);
                return (
                  <button key={code} type="button" onClick={() => { setEquipaSel(on ? '' : code); setComercialSel(''); setLivroPag(1); }} style={{
                    textAlign: 'left', border: `1px solid ${on ? '#0f766e' : 'var(--border)'}`, borderRadius: 8, padding: '10px 12px', background: '#fff', cursor: 'pointer', fontFamily: 'inherit', minWidth: 160,
                  }}>
                    <div style={{ fontSize: 13, fontWeight: 700 }}>{prospEquipa(code)}</div>
                    <div style={{ fontSize: 11, color: '#0f766e', marginTop: 3 }}>{logicaEquipa(code)}</div>
                    <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>{prospNum(empresas)} empresas</div>
                  </button>
                );
              })}
              <button type="button" onClick={() => { setEquipaSel(equipaSel === '__sem__' ? '' : '__sem__'); setComercialSel(''); setLivroPag(1); }} style={{
                textAlign: 'left', border: `1px solid ${equipaSel === '__sem__' ? '#9f1239' : 'var(--border)'}`, borderRadius: 8, padding: '10px 12px', background: '#fff', cursor: 'pointer', fontFamily: 'inherit', minWidth: 160,
              }}>
                <div style={{ fontSize: 13, fontWeight: 700 }}>Sem equipa</div>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>{prospNum(semLinha?.empresas || dados.sem_equipa)} empresas · {prospNum(semLinha?.contactos || dados.contactos_sem_equipa)} contactos</div>
              </button>
            </div>
            {equipaSel && equipaSel !== '__sem__' && (
              <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                {(grupos.find(([code]) => code === equipaSel)?.[1] || []).map(r => {
                  const id = r.comercial || '__sem__';
                  const on = comercialSel === id;
                  return (
                    <button key={id} type="button" onClick={() => { setComercialSel(on ? '' : id); setLivroPag(1); }} style={{
                      border: `1px solid ${on ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 999, padding: '5px 10px', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12,
                      background: on ? 'color-mix(in oklch, var(--ai-500, #3859D0) 12%, #fff)' : '#fff', color: on ? 'var(--ai-500)' : 'var(--text)',
                    }}>{r.comercial || 'Sem comercial'} · {prospNum(r.empresas)}</button>
                  );
                })}
              </div>
            )}
            {livroLoading && <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: 'var(--text-muted)' }}><ProspSpin />A abrir a carteira…</div>}
            {livro && (
              <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, overflowX: 'auto' }}>
                {livro.logica && <div style={{ padding: '10px 12px', fontSize: 12, color: '#0f766e', borderBottom: '1px solid var(--border)' }}>{livro.logica}. Os contactos desta lista seguem esta lógica.</div>}
                <table style={{ width: 980, minWidth: '100%', borderCollapse: 'collapse' }}>
                  <thead><tr>{['Empresa', 'País', 'Cidade', 'Zona', 'Contactos'].map(h => <th key={h} style={prospTh}>{h}</th>)}</tr></thead>
                  <tbody>
                    {livro.empresas.map(e => (
                      <tr key={e.id} className="prosp-row">
                        <td style={{ ...prospTd, fontWeight: 650 }}>{e.nome}</td>
                        <td style={prospTd}>{e.pais || '—'}</td>
                        <td style={prospTd}>{e.cidade || '—'}</td>
                        <td style={prospTd}>{e.zona || '—'}</td>
                        <td style={prospTd}>{(e.contactos || []).length ? (e.contactos || []).map(c => prospNomeDe(c) || prospSemAsteriscos(c.email) || prospSemAsteriscos(c.cargo)).filter(Boolean).join(', ') : '—'}</td>
                      </tr>
                    ))}
                    {!livro.empresas.length && <tr><td colSpan={5} style={{ ...prospTd, textAlign: 'center', color: 'var(--text-muted)', padding: 24 }}>Sem empresas nesta selecção.</td></tr>}
                  </tbody>
                </table>
                {livro.total > livro.empresas.length && (
                  <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, padding: 10, fontSize: 12, color: 'var(--text-muted)' }}>
                    <span>{prospNum((livro.page - 1) * 60 + 1)}–{prospNum((livro.page - 1) * 60 + livro.empresas.length)} de {prospNum(livro.total)}</span>
                    <span style={{ display: 'flex', gap: 8 }}>
                      <button type="button" className="btn btn-sm btn-ghost" disabled={livro.page <= 1} onClick={() => setLivroPag(p => Math.max(1, p - 1))}>Anterior</button>
                      <button type="button" className="btn btn-sm btn-ghost" disabled={livro.page * 60 >= livro.total} onClick={() => setLivroPag(p => p + 1)}>Seguinte</button>
                    </span>
                  </div>
                )}
              </div>
            )}
            <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--text)' }}>Completar moradas</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.45, maxWidth: 760 }}>
              O Gestor preenche cidade, código postal e zona quando o domínio já existe nas chaves, e só se a ficha estiver vazia. O Google Maps procura a empresa pelo nome e pelo website, um lugar de cada vez, sem decisores e sem leitura de emails. A rua só é gravada depois de confirmares.
            </div>
            <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
                <div>
                  <div style={{ fontSize: 14, fontWeight: 700 }}>Gestor, pelo domínio</div>
                  <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>{prospNum(dados.gestor)} empresas sem localização já têm cidade ou código postal no Gestor.</div>
                </div>
                {admin ? (
                  <div style={{ display: 'flex', gap: 8 }}>
                    <button type="button" className="btn btn-sm btn-ai" disabled={aGestor || !dados.gestor} onClick={() => (confirmarGestor ? aplicarGestor() : setConfirmarGestor(true))}>
                      {aGestor ? 'A gravar…' : confirmarGestor ? `Confirmar ${prospNum(dados.gestor)}` : 'Preencher a partir do Gestor'}
                    </button>
                    {confirmarGestor && !aGestor && <button type="button" className="btn btn-sm btn-ghost" onClick={() => setConfirmarGestor(false)}>Cancelar</button>}
                  </div>
                ) : <span style={{ fontSize: 13, color: 'var(--text-muted)' }}>Aplicar fica com um administrador.</span>}
              </div>
              {!!dados.gestor_linhas.length && (
                <div style={{ overflowX: 'auto' }}>
                  <table style={{ width: 760, minWidth: '100%', borderCollapse: 'collapse' }}>
                    <thead><tr>{['Empresa', 'País', 'Domínio', 'Cidade', 'Código postal', 'Zona', 'Contactos'].map(h => <th key={h} style={prospTh}>{h}</th>)}</tr></thead>
                    <tbody>
                      {dados.gestor_linhas.slice(0, 40).map(r => (
                        <tr key={r.id} className="prosp-row">
                          <td style={{ ...prospTd, fontWeight: 650 }}>{r.nome}</td>
                          <td style={prospTd}>{r.pais || '—'}</td>
                          <td style={prospTd}>{r.dominio || '—'}</td>
                          <td style={prospTd}>{r.cidade || '—'}</td>
                          <td style={prospTd}>{r.codigo_postal || '—'}</td>
                          <td style={prospTd}>{r.zona || '—'}</td>
                          <td style={prospTd}>{prospNum(r.contactos)}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                  {dados.gestor > dados.gestor_linhas.length && <div style={{ fontSize: 12, color: 'var(--text-muted)', padding: '8px 2px' }}>A lista mostra {prospNum(dados.gestor_linhas.length)} de {prospNum(dados.gestor)}.</div>}
                </div>
              )}
            </div>
            <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
              {[
                { modo: 'dominio', titulo: 'Google Maps, com website', n: dados.maps_dominio, texto: 'O lugar só vem seleccionado se o website for o mesmo domínio.' },
                { modo: 'nome', titulo: 'Google Maps, só pelo nome', n: dados.maps_nome, texto: 'Nada vem seleccionado. Confirmas uma a uma.' },
              ].map(c => (
                <div key={c.modo} style={{ flex: '1 1 280px', background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: 16 }}>
                  <div style={{ fontSize: 14, fontWeight: 700 }}>{c.titulo}</div>
                  <div style={{ fontSize: 22, fontWeight: 700, color: '#0f766e', fontFamily: 'var(--font-display)', marginTop: 6 }}>{prospNum(c.n)}</div>
                  <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.45, marginTop: 6 }}>{c.texto} Até 500 por pesquisa. As que o Gestor já resolve não entram.</div>
                  {admin ? (
                    <button type="button" className="btn btn-sm btn-ai" style={{ marginTop: 12 }} disabled={!!aMaps || !c.n} onClick={() => pesquisarMaps(c.modo)}>
                      {aMaps === c.modo ? 'A lançar…' : `Pesquisar ${prospNum(Math.min(c.n, 500))}`}
                    </button>
                  ) : <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 12 }}>Pesquisar fica com um administrador.</div>}
                </div>
              ))}
            </div>
            {runs.map(run => {
              const preview = run.parametros?.preview || [];
              const gravados = new Set(run.parametros?.gravados || []);
              const linhas = preview.filter(p => !gravados.has(p.id) && !gravados.has(Number(p.id)));
              return (
                <div key={run.id} style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: 16, display: 'flex', flexDirection: 'column', gap: 10 }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
                    <div>
                      <div style={{ fontSize: 14, fontWeight: 700 }}>{run.referencia || 'Google Maps'}</div>
                      <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>{run.estado === 'a_correr' ? 'A pesquisar…' : (run.notas || run.estado)}</div>
                    </div>
                    {run.estado === 'a_correr' && <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: 'var(--text-muted)' }}><ProspSpin />A pesquisar</div>}
                  </div>
                  {!!linhas.length && run.estado !== 'a_correr' && (
                    <div style={{ overflowX: 'auto' }}>
                      <table style={{ width: 1100, minWidth: '100%', borderCollapse: 'collapse' }}>
                        <thead><tr>{['', 'Empresa', 'Lugar', 'Morada', 'Cidade', 'Código postal', 'Resultado'].map(h => <th key={h || 'sel'} style={prospTh}>{h}</th>)}</tr></thead>
                        <tbody>
                          {linhas.map(p => (
                            <tr key={p.id} className="prosp-row">
                              <td style={prospTd}>
                                <input type="checkbox" disabled={!!p.sem_resultado || !(p.morada || p.codigo_postal || p.cidade)} checked={!!escolhas[run.id]?.[p.id]} onChange={() => toggle(run.id, p.id)} />
                              </td>
                              <td style={{ ...prospTd, fontWeight: 650 }}>{p.nome}</td>
                              <td style={prospTd}>{p.lugar || '—'}</td>
                              <td style={prospTd}>{p.morada || '—'}</td>
                              <td style={prospTd}>{p.cidade || '—'}</td>
                              <td style={prospTd}>{p.codigo_postal || '—'}</td>
                              <td style={prospTd}>{p.sem_resultado ? 'Sem resultado' : p.confirmado ? 'Mesmo website' : 'Por confirmar'}</td>
                            </tr>
                          ))}
                        </tbody>
                      </table>
                    </div>
                  )}
                </div>
              );
            })}
            {admin && selecionadas > 0 && (
              <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
                <button type="button" className="btn btn-sm btn-ai" disabled={aGravar} onClick={() => (confirmarMaps ? gravarMaps() : setConfirmarMaps(true))}>
                  {aGravar ? 'A gravar…' : confirmarMaps ? `Confirmar ${prospNum(selecionadas)} moradas` : `Gravar ${prospNum(selecionadas)} moradas`}
                </button>
                {confirmarMaps && !aGravar && <button type="button" className="btn btn-sm btn-ghost" onClick={() => setConfirmarMaps(false)}>Cancelar</button>}
              </div>
            )}
            <div style={{ background: '#fff', border: '1px solid var(--border)', borderRadius: 10, padding: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
                <div>
                  <div style={{ fontSize: 14, fontWeight: 700 }}>Associar às equipas</div>
                  <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4, maxWidth: 640 }}>Depois das moradas, volta a ligar as empresas aos territórios. Uma zona já gravada mantém-se, salvo se pedires o recálculo.</div>
                </div>
                <button type="button" className="btn btn-sm" onClick={() => { setAssociarOn(v => !v); setConfirmarAssociar(false); }}>{associarOn ? 'Fechar' : 'Ver o que mudaria'}</button>
              </div>
              {associarOn && (
                <>
                  <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
                    <button type="button" onClick={() => setSoSem(v => !v)} style={{
                      border: `1px solid ${soSem ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 6, padding: '6px 10px', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12, fontWeight: 650,
                      background: soSem ? 'color-mix(in oklch, var(--ai-500, #3859D0) 12%, #fff)' : '#fff', color: soSem ? 'var(--ai-500)' : 'var(--text)',
                    }}>Só sem equipa</button>
                    <label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontSize: 13 }}>
                      <input type="checkbox" checked={recalcular} onChange={ev => setRecalcular(ev.target.checked)} />
                      Recalcular zonas já gravadas
                    </label>
                  </div>
                  {!associar && <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: 'var(--text-muted)' }}><ProspSpin />A calcular…</div>}
                  {associar && (
                    <>
                      <div style={{ fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.45 }}>
                        {prospNum(associar.novas.empresas)} passam a ter equipa, {prospNum(associar.mudam.empresas)} mudam, {prospNum(associar.perdem.empresas)} ficam sem equipa e {prospNum(associar.ficam.empresas)} ficam iguais. {prospNum(associar.fora.empresas)} ficam de fora, {prospNum(associar.fora.sem_local)} sem localização.
                      </div>
                      {admin ? (
                        <div style={{ display: 'flex', gap: 8 }}>
                          <button type="button" className="btn btn-sm btn-ai" disabled={aAssociar || !aMudar} onClick={() => (confirmarAssociar ? aplicarAssociar() : setConfirmarAssociar(true))}>
                            {aAssociar ? 'A associar…' : confirmarAssociar ? `Confirmar ${prospNum(aMudar)} empresas` : (recalcular ? 'Recalcular zonas e atribuir' : 'Associar')}
                          </button>
                          {confirmarAssociar && !aAssociar && <button type="button" className="btn btn-sm btn-ghost" onClick={() => setConfirmarAssociar(false)}>Cancelar</button>}
                        </div>
                      ) : <span style={{ fontSize: 13, color: 'var(--text-muted)' }}>Associar fica com um administrador.</span>}
                      {!!associar.linhas.length && (
                        <div style={{ overflowX: 'auto' }}>
                          <table style={{ width: 980, minWidth: '100%', borderCollapse: 'collapse' }}>
                            <thead><tr>{['Empresa', 'Zona', 'Equipa', 'Comercial', 'Contactos'].map(h => <th key={h} style={prospTh}>{h}</th>)}</tr></thead>
                            <tbody>
                              {associar.linhas.slice(0, 40).map(r => (
                                <tr key={r.id} className="prosp-row">
                                  <td style={{ ...prospTd, fontWeight: 650 }}>{r.nome}</td>
                                  <td style={prospTd}>{r.zona_proxima || r.zona || '—'}</td>
                                  <td style={prospTd}>{(r.equipas_proximas || []).map(prospEquipa).join(', ') || '—'}</td>
                                  <td style={prospTd}>{(r.comerciais_proximos || []).join(', ') || '—'}</td>
                                  <td style={prospTd}>{prospNum(r.contactos)}</td>
                                </tr>
                              ))}
                            </tbody>
                          </table>
                        </div>
                      )}
                    </>
                  )}
                </>
              )}
            </div>
          </>
        )}
      </div>
    </>
  );
}

function ProspNovoContacto({ marca, marcaLabel, onClose, onFeito }) {
  const vazioEmp = { nome: '', pais: 'PT', website: '', nif: '', telefone: '', morada: '', codigo_postal: '', cidade: '' };
  const [nome, setNome] = React.useState('');
  const [cargo, setCargo] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [telemovel, setTelemovel] = React.useState('');
  const [linkedin, setLinkedin] = React.useState('');
  const [segmento, setSegmento] = React.useState('');
  const [modo, setModo] = React.useState('existente');
  const [q, setQ] = React.useState('');
  const [resultados, setResultados] = React.useState([]);
  const [escolhida, setEscolhida] = React.useState(null);
  const [empresa, setEmpresa] = React.useState(vazioEmp);
  const [confirmar, setConfirmar] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const [erro, setErro] = React.useState('');
  const [decisao, setDecisao] = React.useState(null);
  const [porEntrar, setPorEntrar] = React.useState(null);
  const [gravado, setGravado] = React.useState(null);
  const [aDecidir, setADecidir] = React.useState(false);

  const fecharDecisao = async () => {
    const ok = await prospFecharDecisoes({
      pedido: decisao,
      entradas: porEntrar,
      setDecisao,
      setEntradas: setPorEntrar,
      setMsg: (m) => setErro(m?.tipo === 'erro' ? m.texto : ''),
    });
    if (ok && gravado) onFeito(gravado);
  };

  React.useEffect(() => {
    const onKey = (e) => {
      if (e.key !== 'Escape') return;
      if (decisao || porEntrar) { fecharDecisao(); return; }
      onClose();
    };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [onClose, decisao, porEntrar, gravado]);
  React.useEffect(() => {
    if (modo !== 'existente') return undefined;
    const termo = q.trim();
    if (termo.length < 2) { setResultados([]); return undefined; }
    let stop = false;
    const t = setTimeout(() => {
      prospApi('/empresas', { query: { q: termo, limit: 8, ordem: 'nome' } })
        .then(d => { if (!stop) setResultados(d.rows || []); })
        .catch(() => { if (!stop) setResultados([]); });
    }, 180);
    return () => { stop = true; clearTimeout(t); };
  }, [q, modo]);

  const gravar = async (usarExistente) => {
    setErro('');
    if (nome.trim().length < 2) { setErro('Indica o nome do contacto.'); return; }
    if (modo === 'existente' && !escolhida) { setErro('Escolhe a empresa.'); return; }
    if (modo === 'nova' && !usarExistente && empresa.nome.trim().length < 2) { setErro('Indica o nome da empresa.'); return; }
    const seg = prospSegPartes(segmento);
    const body = {
      contacto: { nome: nome.trim(), cargo: cargo.trim(), email: email.trim(), telemovel: telemovel.trim(), linkedin: linkedin.trim() },
      marca: marca || undefined,
      segmento: seg?.segmento,
      segmento_tipo: seg?.segmento_tipo,
    };
    if (modo === 'existente') body.empresa_id = escolhida.id;
    else if (usarExistente && confirmar) { body.empresa_id = confirmar.id; body.confirmar = true; }
    else body.empresa = empresa;
    setBusy(true);
    try {
      const d = await prospApi('/contactos', { method: 'POST', body });
      if (d.confirmar) { setConfirmar(d.empresa); return; }
      if (d.pendentes?.total || prospTemEntradas(d.entradas)) {
        setGravado(d);
        setDecisao(d.pendentes?.total ? d.pendentes : null);
        setPorEntrar(prospTemEntradas(d.entradas) ? d.entradas : null);
        return;
      }
      onFeito(d);
    } catch (e) { setErro(e.message); }
    finally { setBusy(false); }
  };

  const campoEmp = (key, label) => (
    <ProspField label={label}>
      <input style={prospInput} value={empresa[key]} onChange={ev => { setConfirmar(null); setEmpresa(p => ({ ...p, [key]: ev.target.value })); }} />
    </ProspField>
  );

  const escolherDecisao = async (op) => {
    setADecidir(true); setErro('');
    try {
      await prospEnviarDecisao(decisao, op);
      setDecisao(null);
      if (!prospTemEntradas(porEntrar) && gravado) onFeito(gravado);
    } catch (e) { setErro(e.message); }
    finally { setADecidir(false); }
  };
  const escolherEntrada = async (campanha, op) => {
    setADecidir(true); setErro('');
    try {
      await prospEnviarEntrada(campanha, op);
      const resto = prospEntradasSem(porEntrar, campanha.id);
      setPorEntrar(resto);
      if (!decisao?.total && !resto && gravado) onFeito(gravado);
    } catch (e) { setErro(e.message); }
    finally { setADecidir(false); }
  };

  return (
    <div onClick={() => (decisao || porEntrar ? fecharDecisao() : onClose())} style={{ position: 'fixed', inset: 0, zIndex: 80, background: 'rgba(17,41,84,0.35)', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', padding: '48px 16px', overflowY: 'auto' }}>
      <ProspDecisaoSegmento pedido={decisao} entradas={porEntrar} aDecidir={aDecidir} onEscolher={escolherDecisao} onEntrada={escolherEntrada} onFechar={fecharDecisao} />
      <div onClick={ev => ev.stopPropagation()} style={{ width: 'min(720px, 100%)', background: '#fff', borderRadius: 12, border: '1px solid var(--border)', boxShadow: '0 18px 48px rgba(17,41,84,0.18)', padding: 20, display: 'flex', flexDirection: 'column', gap: 16 }}>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 18, fontWeight: 700, fontFamily: 'var(--font-display)' }}>Novo contacto</div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>{marcaLabel ? `Marca ${marcaLabel}` : 'Sem marca. A empresa nova fica visível em Todas.'}</div>
          </div>
          <button type="button" className="btn btn-sm btn-ghost" onClick={() => (decisao || porEntrar ? fecharDecisao() : onClose())}>Fechar</button>
        </div>
        {erro && <ProspMsg msg={{ tipo: 'erro', texto: erro }} />}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <ProspField label="Nome *"><input style={prospInput} value={nome} onChange={ev => setNome(ev.target.value)} /></ProspField>
          <ProspField label="Cargo"><input style={prospInput} value={cargo} onChange={ev => setCargo(ev.target.value)} /></ProspField>
          <ProspField label="Email"><input style={prospInput} value={email} onChange={ev => setEmail(ev.target.value)} /></ProspField>
          <ProspField label="Telemóvel"><input style={prospInput} value={telemovel} onChange={ev => setTelemovel(ev.target.value)} /></ProspField>
          <ProspField label="LinkedIn"><input style={prospInput} value={linkedin} onChange={ev => setLinkedin(ev.target.value)} placeholder="https://www.linkedin.com/in/…" /></ProspField>
          <ProspField label="Segmento" hint="Fica na empresa. Uma leitura posterior não o substitui.">
            <select style={prospInput} value={segmento} onChange={ev => setSegmento(ev.target.value)}>
              <option value="">Sem segmento</option>
              {PROSP_SEGMENTOS.map(s => <option key={prospSegValor(s.segmento, s.tipo)} value={prospSegValor(s.segmento, s.tipo)}>{prospSegRotulo(s.segmento, s.tipo)}</option>)}
            </select>
          </ProspField>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          {[{ id: 'existente', label: 'Empresa existente' }, { id: 'nova', label: 'Empresa nova' }].map(op => (
            <button key={op.id} type="button" onClick={() => { setModo(op.id); setConfirmar(null); setErro(''); }} style={{
              flex: 1, border: `1px solid ${modo === op.id ? 'var(--ai-500)' : 'var(--border)'}`, borderRadius: 6,
              background: modo === op.id ? 'color-mix(in oklch, var(--ai-500) 12%, #fff)' : '#fff',
              color: modo === op.id ? 'var(--ai-500)' : 'var(--text)', padding: '8px 10px', cursor: 'pointer', fontSize: 13, fontWeight: 650, fontFamily: 'inherit',
            }}>{op.label}</button>
          ))}
        </div>
        {modo === 'existente' ? (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <ProspField label="Procurar empresa">
              <input style={prospInput} value={q} onChange={ev => { setQ(ev.target.value); setEscolhida(null); }} placeholder="Nome, domínio ou NIF" />
            </ProspField>
            {escolhida && <div style={{ fontSize: 13 }}><strong>{escolhida.nome}</strong>{escolhida.cidade ? ` · ${escolhida.cidade}` : ''}{escolhida.pais ? ` · ${escolhida.pais}` : ''}</div>}
            {!!resultados.length && !escolhida && (
              <div style={{ border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' }}>
                {resultados.map(r => (
                  <button key={r.id} type="button" onClick={() => { setEscolhida(r); setQ(r.nome); setResultados([]); }} style={{
                    display: 'block', width: '100%', textAlign: 'left', background: '#fff', border: 'none', borderBottom: '1px solid var(--border)',
                    padding: '8px 12px', cursor: 'pointer', fontFamily: 'inherit',
                  }}>
                    <span style={{ fontSize: 13, fontWeight: 650 }}>{r.nome}</span>
                    <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{[r.cidade, r.pais, r.dominio].filter(Boolean).length ? ` · ${[r.cidade, r.pais, r.dominio].filter(Boolean).join(' · ')}` : ''}</span>
                  </button>
                ))}
              </div>
            )}
          </div>
        ) : (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            {campoEmp('nome', 'Empresa *')}
            <ProspField label="País">
              <select style={prospInput} value={empresa.pais} onChange={ev => { setConfirmar(null); setEmpresa(p => ({ ...p, pais: ev.target.value })); }}>
                {PROSP_PAISES.map(p => <option key={p.value} value={p.value}>{p.label}</option>)}
              </select>
            </ProspField>
            {campoEmp('website', 'Website')}
            {campoEmp('nif', 'NIF')}
            {campoEmp('telefone', 'Telefone')}
            {campoEmp('cidade', 'Cidade')}
            {campoEmp('codigo_postal', 'Código postal')}
            <div style={{ gridColumn: '1 / -1' }}>{campoEmp('morada', 'Morada')}</div>
          </div>
        )}
        {confirmar && (
          <div style={{ padding: 12, borderRadius: 8, background: '#f8fafc', border: '1px solid var(--border)', fontSize: 13, lineHeight: 1.45 }}>
            Já existe <strong>{confirmar.nome}</strong>{confirmar.cidade ? ` · ${confirmar.cidade}` : ''}{confirmar.pais ? ` · ${confirmar.pais}` : ''}{confirmar.dominio ? ` · ${confirmar.dominio}` : ''}. O contacto fica nesta ficha.
            {confirmar.arquivado ? ' A empresa está arquivada: o contacto só aparece em Arquivadas até a restaurares.' : ''}
          </div>
        )}
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
          <button type="button" className="btn" onClick={onClose}>Cancelar</button>
          {confirmar
            ? <button type="button" className="btn btn-ai" disabled={busy} onClick={() => gravar(true)}>{busy ? 'A gravar…' : 'Usar esta empresa'}</button>
            : <button type="button" className="btn btn-ai" disabled={busy} onClick={() => gravar(false)}>{busy ? 'A gravar…' : 'Gravar contacto'}</button>}
        </div>
      </div>
    </div>
  );
}

function MktProspeccaoScreen() {
  const brandApi = window.useMktBrand ? window.useMktBrand() : { brand: 'todas', setBrand: () => {} };
  const brand = brandApi.brand || 'todas';
  const setBrand = brandApi.setBrand || (() => {});
  const marca = brand !== 'todas' ? brand : '';
  const [tab, setTab] = React.useState('base');
  const [fonte, setFonte] = React.useState('apollo');
  const [canalAberto, setCanalAberto] = React.useState(false);
  const [rede, setRede] = React.useState('facebook');
  const [empresa, setEmpresa] = React.useState(null);
  const [resumo, setResumo] = React.useState(null);
  const [erro, setErro] = React.useState('');
  window.useMktZoneLoading(resumo == null && !erro);
  const [tick, setTick] = React.useState(0);
  const [vendedores, setVendedores] = React.useState([]);
  const [busca, setBusca] = React.useState(false);
  const [novo, setNovo] = React.useState(false);
  const [f, setF] = React.useState({ estado: '', pais: '', fonte: '', equipa: '', comercial: '', zona: '', segmento: '', com_email: '', com_telefone: '', ordem: 'recentes' });
  const [segmentosLista, setSegmentosLista] = React.useState([]);
  const [semSegmento, setSemSegmento] = React.useState(null);
  const [listas, setListas] = React.useState(null);
  const [vista, setVista] = React.useState('empresas');
  const [cFiltro, setCFiltro] = React.useState('');
  const [filtroMercados, setFiltroMercados] = React.useState(null);
  const [filtroCarteira, setFiltroCarteira] = React.useState(null);
  const [periodo, setPeriodo] = React.useState(() => {
    const today = new Date();
    return { preset: 'all', start: new Date(today.getFullYear(), 0, 1), end: today };
  });
  const intervalo = periodo.preset === 'all' ? {} : { desde: prospIsoDia(periodo.start), ate: prospIsoDia(periodo.end) };
  const fecharBusca = React.useCallback(() => setBusca(false), []);

  React.useEffect(() => {
    prospApi('/resumo', { query: { marca, ...intervalo } }).then(d => { setResumo(d); setErro(''); }).catch(e => setErro(e.message));
  }, [tick, marca, intervalo.desde, intervalo.ate]);
  React.useEffect(() => { prospApi('/vendedores').then(d => setVendedores(d.rows)).catch(() => {}); }, []);
  React.useEffect(() => {
    if (tab !== 'base' && tab !== 'contactos') return;
    prospApi('/segmentos').then(d => { setSegmentosLista(d.rows || []); setSemSegmento(d.sem || null); }).catch(() => {});
  }, [tab, tick]);
  React.useEffect(() => {
    if (!f.equipa || f.equipa === '__sem__') return;
    const ok = marca === 'mimaki' ? f.equipa.startsWith('MIMAKI') : marca === 'decal' ? f.equipa.startsWith('DECAL') : true;
    if (!ok) setF(p => ({ ...p, equipa: '', comercial: '', zona: '' }));
  }, [marca]);

  const admin = !!resumo?.admin;
  const mudarTab = (id, listasInicio) => {
    setEmpresa(null); setBusca(false); setTab(id);
    setListas(id === 'listas' ? (listasInicio || null) : null);
    if (id !== 'pesquisa') setCanalAberto(false);
    if (id === 'contactos') {
      setVista('contactos');
      if (tab !== 'contactos') setF(p => (p.ordem === 'recentes' ? { ...p, ordem: 'nome' } : p));
    }
    if (id === 'base') setVista('empresas');
  };
  const escolherFonte = (id) => {
    const next = id === 'redes' ? rede : id;
    setFonte(next);
    if (['facebook', 'instagram', 'tiktok'].includes(next)) setRede(next);
  };
  React.useEffect(() => {
    if (resumo && !resumo.admin && (tab === 'pesquisa' || tab === 'listas')) setTab('base');
  }, [resumo, tab]);
  const marcasNav = [{ id: 'todas', nome: 'Todas' }, ...((window.MKT_BRANDS || [
    { id: 'mimaki', nome: 'Mimaki' }, { id: 'biond', nome: 'BIOND' }, { id: 'decal', nome: 'Decal' },
    { id: 'alldecor', nome: 'AllDecor' }, { id: 'sensek', nome: 'Sensek' }, { id: 'netscreen', nome: 'NetScreen' },
  ]).filter(b => b.id !== 'todas'))];
  const tabBtn = (b) => {
    const active = b.id === brand;
    return (
      <button key={b.id} type="button" onClick={() => 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',
      }}>{b.nome || b.name}</button>
    );
  };
  const Periodo = window.BriefingDateRangePicker;
  const marcaLabel = marca ? (marcasNav.find(b => b.id === brand)?.nome || marca) : '';
  const sair = () => { setBusca(false); setEmpresa(null); setTab('base'); };
  const canalId = ['facebook', 'instagram', 'tiktok'].includes(fonte) ? 'redes' : fonte;
  const segmentos = empresa
    ? [{ label: 'Prospeção', onClick: sair }, { label: empresa.nome }]
    : tab === 'pesquisa'
      ? [{ label: 'Prospeção', onClick: sair }, { label: canalAberto ? (PROSP_FONTES_PESQUISA.find(p => p.id === canalId)?.label || 'Pesquisar') : 'Pesquisar' }, ...(canalAberto && PROSP_REDES.find(r => r.id === fonte) ? [{ label: PROSP_REDES.find(r => r.id === fonte).label }] : [])]
      : tab === 'execucoes'
        ? [{ label: 'Prospeção', onClick: sair }, { label: 'Histórico' }]
        : tab === 'mercados'
          ? [{ label: 'Prospeção', onClick: sair }, { label: 'Mercados' }]
          : tab === 'carteira'
            ? [{ label: 'Prospeção', onClick: sair }, { label: 'Carteira' }]
            : tab === 'listas'
              ? [{ label: 'Prospeção', onClick: sair }, { label: 'Listas de enrichment' }]
              : null;
  const equipasFiltro = (resumo?.equipas || []).filter(e => (marca === 'mimaki' ? e.code.startsWith('MIMAKI') : marca === 'decal' ? e.code.startsWith('DECAL') : true));
  const comerciaisFiltro = (f.equipa && f.equipa !== '__sem__' ? equipasFiltro.filter(e => e.code === f.equipa) : equipasFiltro)
    .flatMap(e => (e.comerciais || []).map(c => ({ nome: c.nome, empresas: c.empresas, equipa: e.code })))
    .filter((c, i, arr) => arr.findIndex(x => x.nome === c.nome) === i);
  const vistas = [
    { id: 'base', label: 'Empresas', sub: 'Lista de empresas já recolhidas' },
    { id: 'contactos', label: 'Contactos', sub: 'Pessoas ligadas às empresas' },
    ...(admin ? [
      { id: 'listas', label: 'Listas de enrichment', sub: 'Empresas e contactos a enriquecer' },
      { id: 'pesquisa', label: 'Pesquisar', sub: 'Apollo, Google Maps, Web Scrapping ou ficheiro' },
      { id: 'ficheiro', label: 'Importar ficheiro', sub: 'Excel ou CSV para a base de prospeção' },
    ] : []),
    { id: 'mercados', label: 'Mercados', sub: 'Territórios de equipas, comerciais e partners' },
    { id: 'carteira', label: 'Carteira', sub: 'Empresas e contactos por equipa' },
    { id: 'execucoes', label: 'Histórico', sub: 'Pesquisas e importações já feitas' },
  ];
  const menu = (
    <ProspMenu activo={empresa ? '' : (fonte === 'ficheiro' && tab === 'pesquisa' ? 'ficheiro' : tab)} onOpen={() => setBusca(false)} items={[
      { id: 'novo', label: 'Novo contacto', sub: 'Pessoa numa empresa existente ou nova', onClick: () => { setBusca(false); setNovo(true); } },
      ...vistas.map(t => ({
        ...t,
        onClick: () => {
          if (t.id === 'ficheiro') {
            setFonte('ficheiro');
            setCanalAberto(true);
            mudarTab('pesquisa');
            return;
          }
          mudarTab(t.id);
        },
      })),
    ]} />
  );
  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0, background: 'var(--bg)' }}>
      <div style={{ background: 'var(--bg-elev)', borderBottom: '1px solid var(--border)', padding: '20px 40px 0', flexShrink: 0 }}>
        <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.07em', color: 'var(--text-muted)', textTransform: 'uppercase', marginBottom: 6, fontFamily: 'var(--font-mono)' }}>
          MARKETING · PROSPEÇÃO
        </div>
        <h1 style={{ margin: 0, fontSize: 21, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display)', letterSpacing: '-0.01em', lineHeight: 1.2 }}>
          Prospeção
        </h1>
        <div style={{ height: 1, background: 'var(--border)', margin: '16px -40px 0' }} />
        <div style={{ display: 'flex', gap: 0, overflowX: 'auto' }}>{marcasNav.map(tabBtn)}</div>
      </div>

      <div className="scrollbar" style={{ overflowY: 'auto', flex: 1, minHeight: 0, padding: '28px 40px 64px', background: 'var(--bg)', display: 'flex', flexDirection: 'column', gap: 18 }}>
        {erro && <ProspMsg msg={{ tipo: 'erro', texto: erro }} />}
        {!empresa && (
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
            <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
              {(tab === 'base' || tab === 'contactos') && (
                <>
                  <ProspDrop label="Estado" value={f.estado} onChange={v => setF(p => ({ ...p, estado: v }))} options={[
                    { value: '', label: 'Todos' },
                    ...PROSP_ESTADOS.map(e => ({ value: e.id, label: e.label })),
                    { value: '__arquivadas__', label: `Arquivadas${resumo?.arquivadas ? ` (${prospNum(tab === 'contactos' ? resumo.arquivadas.contactos : resumo.arquivadas.empresas)})` : ''}` },
                  ]} />
                  <ProspDrop label="País" value={f.pais} onChange={v => setF(p => ({ ...p, pais: v }))} options={[{ value: '', label: 'Todos' }, ...(resumo?.paises || []).map(p => ({ value: p.pais, label: `${p.pais} · ${prospNum(p.n)}` }))]} />
                  <ProspDrop label="Fonte" value={f.fonte} onChange={v => setF(p => ({ ...p, fonte: v }))} options={[{ value: '', label: 'Todas' }, ...['apollo', 'apify', 'pagina', 'import', 'excel'].map(k => ({ value: k, label: PROSP_FONTES[k] }))]} />
                  <ProspDrop label="Segmento" value={f.segmento || ''} onChange={v => setF(p => ({ ...p, segmento: v }))} options={[
                    { value: '', label: 'Todos' },
                    { value: '__sem__', label: `Sem segmento${semSegmento ? ` (${prospNum(tab === 'contactos' ? semSegmento.contactos : semSegmento.empresas)})` : ''}` },
                    ...segmentosLista.map(s => ({ value: prospSegValor(s.segmento, s.segmento_tipo), label: `${prospSegRotulo(s.segmento, s.segmento_tipo)} (${prospNum(tab === 'contactos' ? s.contactos : s.empresas)})` })),
                  ]} />
                  <ProspDrop label="Equipa" value={f.equipa} onChange={v => setF(p => ({ ...p, equipa: v, comercial: '', zona: '' }))} options={[
                    { value: '', label: 'Todas' },
                    ...equipasFiltro.map(e => ({ value: e.code, label: `${prospEquipa(e.code)} (${prospNum(e.empresas)})` })),
                    { value: '__sem__', label: `Sem equipa (${prospNum(resumo?.sem_equipa?.empresas || 0)})` },
                  ]} />
                  {f.zona && <button type="button" onClick={() => setF(p => ({ ...p, zona: '' }))} style={{ border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', background: '#fff', fontSize: 12, fontFamily: 'inherit', cursor: 'pointer', color: 'var(--text)' }}>{f.zona} ×</button>}
                  <ProspDrop label="Comercial" value={f.comercial} onChange={v => setF(p => ({ ...p, comercial: v, zona: '' }))} options={[
                    { value: '', label: 'Todos' },
                    ...comerciaisFiltro.map(c => ({ value: c.nome, label: f.equipa && f.equipa !== '__sem__' ? `${c.nome} (${prospNum(c.empresas)})` : `${c.nome} · ${prospEquipa(c.equipa)}` })),
                  ]} />
                  {tab === 'base' && <ProspDrop label="Contacto" value={f.com_email === '1' ? 'email' : f.com_telefone === '1' ? 'telefone' : ''} onChange={v => setF(p => ({ ...p, com_email: v === 'email' ? '1' : '', com_telefone: v === 'telefone' ? '1' : '' }))} options={[{ value: '', label: 'Todos' }, { value: 'email', label: 'Com email' }, { value: 'telefone', label: 'Com telefone' }]} />}
                  {tab === 'contactos' && <ProspDrop label="Contacto" value={cFiltro} onChange={setCFiltro} options={[{ value: '', label: 'Todos' }, { value: 'email', label: 'Com email' }, { value: 'telemovel', label: 'Com telemóvel' }, { value: 'ambos', label: 'Com email e telemóvel' }, { value: 'nenhum', label: 'Sem email nem telemóvel' }]} />}
                  <ProspDrop label="Ordem" value={f.ordem} onChange={v => setF(p => ({ ...p, ordem: v }))} options={tab === 'contactos' ? [{ value: 'recentes', label: 'Recentes' }, { value: 'nome', label: 'Nome' }] : [{ value: 'recentes', label: 'Recentes' }, { value: 'actualizadas', label: 'Actualizadas' }, { value: 'nome', label: 'Nome' }, { value: 'score', label: 'Score' }]} />
                  {Periodo && <Periodo value={periodo} onChange={setPeriodo} />}
                </>
              )}
              {tab === 'execucoes' && Periodo && <Periodo value={periodo} onChange={setPeriodo} />}
              {tab === 'mercados' && <div ref={setFiltroMercados} style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }} />}
              {tab === 'carteira' && <div ref={setFiltroCarteira} style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }} />}
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginLeft: 'auto' }}>
              <ProspIcone label="Procurar empresas e contactos" activo={busca} onClick={() => setBusca(v => !v)}>
                <svg width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"><circle cx="7" cy="7" r="4.25" /><path d="M10.5 10.5L13.5 13.5" /></svg>
              </ProspIcone>
              {menu}
            </div>
          </div>
        )}
        {!empresa && <ProspKpis resumo={resumo} tab={tab} admin={admin} onIr={mudarTab} />}
        {segmentos && (
          <ProspTrilho segmentos={segmentos} extra={empresa ? menu : null} nota={empresa && (
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontSize: 12, color: 'var(--text-muted)' }}>
              {empresa.pais && <span style={{ color: 'var(--ai-500)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', fontSize: 10, fontFamily: 'var(--font-mono)' }}>{empresa.pais}</span>}
              {empresa.fonte && <span>{PROSP_FONTES[empresa.fonte] || empresa.fonte}</span>}
              {empresa.estado && <ProspBadge estado={empresa.estado} />}
            </span>
          )} />
        )}
        {empresa && <ProspFicha id={empresa.id} admin={admin} vendedores={vendedores} onClose={() => setEmpresa(null)} onChanged={() => setTick(t => t + 1)} onLoaded={(e) => setEmpresa(prev => (prev && prev.id === e.id ? { ...prev, ...e } : prev))} />}
        {!empresa && tab === 'base' && <ProspBase resumo={resumo} admin={admin} vendedores={vendedores} marca={marca} desde={intervalo.desde} ate={intervalo.ate} f={f} setF={setF} vista="empresas" cFiltro={cFiltro} onVista={(id) => mudarTab(id === 'contactos' ? 'contactos' : 'base')} onCFiltro={setCFiltro} onOpen={setEmpresa} onChanged={() => setTick(t => t + 1)} onLista={(inicio) => mudarTab('listas', inicio)} />}
        {!empresa && tab === 'contactos' && <ProspBase resumo={resumo} admin={admin} vendedores={vendedores} marca={marca} desde={intervalo.desde} ate={intervalo.ate} f={f} setF={setF} vista="contactos" cFiltro={cFiltro} onVista={(id) => mudarTab(id === 'contactos' ? 'contactos' : 'base')} onCFiltro={setCFiltro} onOpen={setEmpresa} onChanged={() => setTick(t => t + 1)} onLista={(inicio) => mudarTab('listas', inicio)} />}
        {!empresa && tab === 'listas' && admin && <ProspListas inicio={listas} onChanged={() => setTick(t => t + 1)} />}
        {!empresa && tab === 'mercados' && <ProspMercados marca={marca} marcaLabel={marcaLabel} filtroSlot={filtroMercados} admin={admin} />}
        {!empresa && tab === 'carteira' && <ProspCarteira marca={marca} filtroSlot={filtroCarteira} admin={admin} onAplicada={() => setTick(t => t + 1)} />}
        {!empresa && tab === 'pesquisa' && admin && <ProspPesquisa fonte={fonte} onFonte={escolherFonte} onLancada={() => setTick(t => t + 1)} onOpen={setEmpresa} onAberto={setCanalAberto} marca={marca} marcaLabel={marcaLabel} />}
        {!empresa && tab === 'execucoes' && <ProspExecucoes tick={tick} desde={intervalo.desde} ate={intervalo.ate} marca={marca} />}
      </div>
      {busca && <ProspBusca marca={marca} desde={intervalo.desde} ate={intervalo.ate} onOpen={(r) => { setTab('base'); setEmpresa(r); }} onClose={fecharBusca} />}
      {novo && <ProspNovoContacto marca={marca} marcaLabel={marcaLabel} onClose={() => setNovo(false)} onFeito={(d) => { setNovo(false); setBusca(false); setTab('base'); setVista('empresas'); setEmpresa({ id: d.empresa_id, nome: d.empresa_nome }); setTick(t => t + 1); }} />}
    </div>
  );
}

window.MktProspeccaoScreen = MktProspeccaoScreen;
