/* screen_marketing_sdr.jsx
   Marketing · SDR — Supervisão Digi AI + Version Registry (Fase 1).
   Anatomia alinhada com Briefings / Campanhas / Produção.
   Expõe window.MktLeadsScreen (nome legacy — wrapper.jsx).
*/

async function campApiCall(url, options = {}) {
  let res;
  try {
    res = await fetch(url, { headers: { 'Content-Type': 'application/json' }, ...options });
  } catch (e) {
    throw new Error(`Erro de rede: ${e.message}`);
  }
  if (!res.ok) {
    let body = {};
    try { body = await res.json(); } catch {}
    throw new Error(body.error || `HTTP ${res.status}`);
  }
  return res.json();
}

const SdrAPI = {
  dashboard: (qs) => campApiCall(`/api/marketing/sdr/dashboard?${qs}`),
  conversas: (qs) => campApiCall(`/api/marketing/sdr/conversas?${qs}`),
  conversa:  (id) => campApiCall(`/api/marketing/sdr/conversas/${encodeURIComponent(id)}`),
  flag:      (id, body) => campApiCall(`/api/marketing/sdr/conversas/${encodeURIComponent(id)}/flag`, {
    method: 'POST', body: JSON.stringify(body || {}),
  }),
  patchCrm:  (id, body) => campApiCall(`/api/marketing/sdr/conversas/${encodeURIComponent(id)}/crm`, {
    method: 'PATCH', body: JSON.stringify(body || {}),
  }),
  criarContacto: (id) => campApiCall(`/api/marketing/sdr/conversas/${encodeURIComponent(id)}/criar-contacto`, { method: 'POST', body: '{}' }),
  health:    ()   => campApiCall('/api/marketing/sdr/config-health'),
  campanhas: (qs) => campApiCall(`/api/marketing/sdr/campanhas-ativas?${qs}`),
  brands:    ()   => campApiCall('/api/marketing/brands'),
  relatorios: ()  => campApiCall('/api/marketing/sdr/relatorios?limit=20'),
  relatorio: (id) => campApiCall(`/api/marketing/sdr/relatorios/${encodeURIComponent(id)}`),
  gerarRelatorio: () => campApiCall('/api/marketing/sdr/relatorios/gerar', { method: 'POST', body: '{}' }),
  frameworks: () => campApiCall('/api/marketing/sdr/frameworks/feedback'),
  gerarFrameworks: () => campApiCall('/api/marketing/sdr/frameworks/feedback/gerar', { method: 'POST', body: '{}' }),
  patchFramework: (id, body) => campApiCall(`/api/marketing/sdr/frameworks/feedback/${id}`, {
    method: 'PATCH', body: JSON.stringify(body || {}),
  }),
  versionImpact: (file, container) => campApiCall(`/api/marketing/sdr/versions/${encodeURIComponent(file)}/impact${container ? `?container=${encodeURIComponent(container)}` : ''}`),
  reconciliar: () => campApiCall('/api/marketing/sdr/reconciliar', { method: 'POST', body: '{}' }),
  campanha: (id) => campApiCall(`/api/marketing/sdr/campanhas/${encodeURIComponent(id)}`),
  comerciais: () => campApiCall('/api/marketing/sdr/comerciais'),
  markExpected: () => campApiCall('/api/marketing/sdr/config-health/mark-expected', { method: 'POST', body: '{}' }),
  painel: (qs) => campApiCall(`/api/marketing/sdr/painel?${qs}`),
  overview: (qs) => campApiCall(`/api/marketing/sdr/overview?${qs}`),
  fila: (qs) => campApiCall(`/api/marketing/sdr/fila?${qs}`),
  cobertura: (qs) => campApiCall(`/api/marketing/sdr/cobertura-fichas?${qs}`),
  revisao: (id, body) => campApiCall(`/api/marketing/sdr/conversas/${encodeURIComponent(id)}/revisao`, {
    method: 'POST', body: JSON.stringify(body || {}),
  }),
};

const SDR_THEME = {
  height: '100%', display: 'flex', flexDirection: 'column',
  '--bg': '#f8fafc', '--bg-elev': '#ffffff', '--bg-hover': '#f1f5f9', '--bg-sunken': '#e8edf5',
  '--border': '#dde3ef', '--border-strong': '#bec9de',
  '--text': '#112954', '--text-muted': '#4a5e7a', '--text-dim': '#6b7fa3',
  '--ai-500': '#3859D0',
};

const SDR_TABS = [
  { id: 'overview',  label: 'Visão geral' },
  { id: 'fila',      label: 'Fila de revisão' },
  { id: 'conversas', label: 'Conversas' },
  { id: 'campanhas', label: 'Campanhas & Fichas' },
  { id: 'prompts',   label: 'Prompts & Melhorias' },
];

const SDR_PUBLICOS = [
  { id: 'todas', label: 'Todas' },
  { id: 'clientes', label: 'Clientes' },
  { id: 'colaboradores', label: 'Colaboradores' },
  { id: 'board', label: 'Board' },
  { id: 'dev', label: 'Dev' },
  { id: 'comercial', label: 'Comercial' },
  { id: 'sat', label: 'SAT' },
];
const SDR_AMBIENTES = [
  { id: 'producao', label: 'Produção' },
  { id: 'staging', label: 'Staging' },
  { id: 'ambos', label: 'Ambos' },
];
const SDR_CAMPOS_FALTA = {
  nome: 'Nome', empresa: 'Empresa', email: 'Email', timing: 'Timing', volume: 'Volume',
  equipamento: 'Equipamento', dor: 'Dor', decisor: 'Decisor', orcamento: 'Orçamento',
  aceita_demo: 'Aceita demo', campanha: 'Campanha',
};

const SDR_PERIODS = [
  { id: 'last_7d',    label: 'Últimos 7 dias' },
  { id: 'last_30d',   label: 'Últimos 30 dias' },
  { id: 'this_month', label: 'Este mês' },
  { id: 'last_month', label: 'Mês passado' },
  { id: 'last_90d',   label: 'Últimos 90 dias' },
  { id: 'this_year',  label: 'Este ano' },
  { id: 'all',        label: 'Todo o período' },
];

const SDR_BRAND_ORDER = ['mimaki','biond','decal','alldecor','sensek','netscreen','digidelta'];

const CLASSIF_CFG = {
  HOT:             { label: 'HOT',             color: 'var(--danger, #ef4444)',  bg: 'color-mix(in oklch, var(--danger, #ef4444) 12%, transparent)' },
  QUALIFICADO:     { label: 'Qualificado',     color: 'var(--success, #22c55e)', bg: 'color-mix(in oklch, var(--success, #22c55e) 12%, transparent)' },
  NURTURE:         { label: 'Nurture',         color: 'var(--warning, #d97706)', bg: 'color-mix(in oklch, var(--warning, #d97706) 12%, transparent)' },
  NAO_QUALIFICADO: { label: 'Não qualificado', color: 'var(--text-dim)',         bg: 'var(--bg-sunken)' },
};

const SDR_STATUS_CFG = {
  pendente:     { label: 'Pendente',      color: 'var(--text-dim)',         bg: 'var(--bg-sunken)' },
  em_contacto:  { label: 'Em contacto',   color: 'var(--ai-500)',           bg: 'color-mix(in oklch, var(--ai-500) 12%, transparent)' },
  qualificado:  { label: 'Qualificado',   color: 'var(--success, #22c55e)', bg: 'color-mix(in oklch, var(--success, #22c55e) 12%, transparent)' },
  sem_resposta: { label: 'Sem resposta',  color: 'var(--warning, #d97706)', bg: 'color-mix(in oklch, var(--warning, #d97706) 12%, transparent)' },
  rejeitado:    { label: 'Rejeitado',     color: 'var(--danger, #ef4444)',  bg: 'color-mix(in oklch, var(--danger, #ef4444) 12%, transparent)' },
  convertido:   { label: 'Convertido',    color: 'var(--success, #22c55e)', bg: 'color-mix(in oklch, var(--success, #22c55e) 12%, transparent)' },
};

const FLAG_TIPOS = [
  { value: 'tom',              label: 'Tom de comunicação' },
  { value: 'fora_framework',   label: 'Fora da Framework' },
  { value: 'info_incorrecta',  label: 'Informação incorrecta' },
  { value: 'nao_coberto',      label: 'Situação não coberta' },
  { value: 'preco_indevido',   label: 'Preço indevido' },
  { value: 'demasiado_longo',  label: 'Resposta demasiado longa' },
  { value: 'lingua_errada',    label: 'Língua errada' },
  { value: 'outro',            label: 'Outro' },
];
const flagTipoLabel = (v) => (FLAG_TIPOS.find(t => t.value === v) || {}).label || v;

const FW_STATUS_LABEL = { pending_review: 'Pendente', incorporated: 'Incorporado', ignored: 'Ignorado' };

const thSt = {
  textAlign: 'left', padding: '8px 12px',
  fontSize: 10, fontFamily: 'var(--font-display)', fontWeight: 600,
  letterSpacing: '0.10em', textTransform: 'uppercase',
  color: 'var(--text-muted)', whiteSpace: 'nowrap',
};
const tdSt = { padding: '10px 12px', overflow: 'hidden' };

function sdrRelTime(iso) {
  if (!iso) return '—';
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return '—';
  const diff = Math.floor((Date.now() - d.getTime()) / 60000);
  if (diff < 1) return 'agora';
  if (diff < 60) return `há ${diff}m`;
  if (diff < 1440) return `há ${Math.floor(diff / 60)}h`;
  return `há ${Math.floor(diff / 1440)}d`;
}

function sdrDate(v) {
  if (!v) return '';
  const s = String(v).slice(0, 10);
  const [y, m, d] = s.split('-');
  return d ? `${d}/${m}/${y}` : s;
}

function sdrPhone(visitorId) {
  if (!visitorId) return '';
  const parts = String(visitorId).split('_');
  return parts.length > 1 ? parts.slice(1).join('_') : visitorId;
}

function sdrSsGet(k, def) {
  try { return sessionStorage.getItem(`sdr-v2-${k}`) || def; } catch { return def; }
}
function sdrSsSet(k, v) {
  try { sessionStorage.setItem(`sdr-v2-${k}`, v); } catch {}
}

function sdrMs(v) {
  const n = Number(v);
  if (!Number.isFinite(n)) return '—';
  if (n < 1000) return `${Math.round(n)} ms`;
  return `${(n / 1000).toFixed(1)} s`;
}
function sdrUsd(v) {
  const n = Number(v);
  if (!Number.isFinite(n)) return '—';
  return `$${n.toFixed(n >= 1 ? 2 : 3)}`;
}
function SdrAmbBadge({ value }) {
  const prod = value === 'producao';
  const stg = value === 'staging';
  const label = prod ? 'Produção' : stg ? 'Staging' : (value || '—');
  const color = prod ? '#15803d' : stg ? '#b45309' : 'var(--text-muted)';
  return (
    <span style={{ fontSize: 10, fontWeight: 700, letterSpacing: '.04em', padding: '2px 7px', borderRadius: 99, fontFamily: 'var(--font-mono)', color, background: 'var(--bg-sunken)', whiteSpace: 'nowrap' }}>{label}</span>
  );
}
function SdrOpCard({ label, value, sub, accent, onClick }) {
  return (
    <button type="button" onClick={onClick} disabled={!onClick} style={{ textAlign: 'left', padding: 14, border: '1px solid var(--border)', borderRadius: 10, background: 'var(--bg-elev)', minWidth: 0, cursor: onClick ? 'pointer' : 'default', color: 'inherit', font: 'inherit' }}>
      <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '.04em', textTransform: 'uppercase' }}>{label}</div>
      <div style={{ fontSize: 26, fontWeight: 650, letterSpacing: '-0.03em', color: accent || 'var(--text)', marginTop: 4, fontFamily: 'var(--font-display)' }}>{value}</div>
      {sub ? <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4 }}>{sub}</div> : null}
    </button>
  );
}
function SdrVisaoGeral({ painel, onSp, onCampo, onAlerta }) {
  if (!painel) return <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>A carregar…</div>;
  const k = painel.kpis || {};
  const clientes = (painel.funil_clientes || []).length > 0;
  const barra = (rows) => (rows || []).slice(0, 8).map(r => {
    const max = Math.max(...(rows || []).map(x => Number(x.n) || 0), 1);
    return (
      <div key={r.key} style={{ display: 'grid', gridTemplateColumns: '110px 1fr 36px', gap: 8, alignItems: 'center', marginBottom: 6, fontSize: 12 }}>
        <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.key}</span>
        <span style={{ height: 8, borderRadius: 99, background: 'var(--bg-sunken)' }}><span style={{ display: 'block', height: 8, borderRadius: 99, width: `${Math.round(100 * (Number(r.n) || 0) / max)}%`, background: 'var(--ai-500)' }} /></span>
        <span style={{ textAlign: 'right', fontFamily: 'var(--font-mono)' }}>{r.n}</span>
      </div>
    );
  });
  return (
    <>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))', gap: 10 }}>
        <SdrOpCard label="Conversas" value={k.conversas ?? 0} sub={`${k.conversas_activas_hoje || 0} activas hoje`} />
        <SdrOpCard label="Mensagens" value={(k.mensagens_lead || 0) + (k.mensagens_digi || 0)} sub={`${k.mensagens_lead || 0} do lead · ${k.mensagens_digi || 0} da Digi`} />
        <SdrOpCard label="Tempo de resposta" value={sdrMs(k.tempo_resposta_p50_ms)} sub={`p95 ${sdrMs(k.tempo_resposta_p95_ms)}`} />
        <SdrOpCard label="Custo" value={sdrUsd(k.custo_usd)} sub={`${sdrUsd(k.custo_por_conversa)} por conversa`} />
        <SdrOpCard label="Erros" value={k.erros ?? 0} accent={(k.erros_24h || 0) > 0 ? 'var(--danger, #ef4444)' : 'var(--text)'} sub={(k.erros_24h || 0) > 0 ? `${k.erros_24h} nas últimas 24 h` : 'nenhum nas últimas 24 h'} onClick={() => onAlerta && onAlerta({ destino: 'conversas', filtro: 'com_erro' })} />
      </div>
      {clientes && (
        <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 2fr) minmax(220px, 1fr)', gap: 12 }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))', gap: 8 }}>
            {(painel.funil_clientes || []).map(e => (
              <SdrOpCard key={e.id} label={e.label} value={e.n} sub={e.pct_anterior == null ? 'Clientes' : `${e.pct_anterior}% da anterior`} />
            ))}
          </div>
          <div style={{ padding: 14, border: '1px solid var(--border)', borderRadius: 10, background: 'var(--bg-elev)' }}>
            <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '.04em', textTransform: 'uppercase' }}>Qualidade · Clientes</div>
            <div style={{ fontSize: 26, fontWeight: 650, marginTop: 4 }}>{k.qualidade_media ?? '—'}</div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{k.conformidade_media ?? '—'}% conformidade · {k.n_criticas || 0} críticas</div>
            <div style={{ fontSize: 12, marginTop: 8 }}>{k.qualificadas ?? 0} qualificadas · {k.hot ?? 0} HOT · {k.demos_aceites ?? 0} demos</div>
          </div>
        </div>
      )}
      <div style={{ overflowX: 'auto' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
          <thead>
            <tr style={{ borderBottom: '1px solid var(--border)', textAlign: 'left' }}>
              {['SP', 'Sessões', 'Runs', 'Custo', 'p50', 'Erros', 'Produção', 'Staging', 'Qualidade'].map(h => <th key={h} style={{ ...thSt, whiteSpace: 'nowrap' }}>{h}</th>)}
            </tr>
          </thead>
          <tbody>
            {(painel.por_sp || []).map(sp => (
              <tr key={sp.sp_name} className="sdr-row" onClick={() => onSp && onSp(sp.sp_name)} style={{ borderBottom: '1px solid var(--border)', cursor: 'pointer' }}>
                <td style={tdSt}>{sp.sp_name}</td>
                <td style={tdSt}>{sp.sessoes}</td>
                <td style={tdSt}>{sp.runs}</td>
                <td style={tdSt}>{sdrUsd(sp.custo)}</td>
                <td style={tdSt}>{sdrMs(sp.p50)}</td>
                <td style={{ ...tdSt, color: sp.erros > 0 ? 'var(--danger, #ef4444)' : 'inherit' }}>{sp.erros}</td>
                <td style={{ ...tdSt, fontFamily: 'var(--font-mono)', fontSize: 11 }}>{(sp.sha_producao || '').slice(0, 7) || '—'}</td>
                <td style={{ ...tdSt, fontFamily: 'var(--font-mono)', fontSize: 11 }}>
                  {(sp.sha_staging || '').slice(0, 7) || '—'}
                  {sp.divergente ? <div style={{ color: 'var(--warning, #d97706)' }}>divergente</div> : null}
                </td>
                <td style={tdSt}>{sp.sp_name === 'SP_CLIENTES.md' ? (sp.qualidade ?? '—') : '—'}</td>
              </tr>
            ))}
          </tbody>
        </table>
        {(painel.por_sp || []).length === 0 && <SdrEmpty title="Sem sessões neste filtro." />}
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        <SdrCard title="Por ambiente">{barra(painel.por_ambiente)}</SdrCard>
        <SdrCard title="Por marca">{barra(painel.por_marca)}</SdrCard>
        <SdrCard title="Por canal">{barra(painel.por_canal)}</SdrCard>
        <SdrCard title="Por país e língua">
          {barra(painel.por_pais)}
          <div style={{ fontSize: 11, color: 'var(--text-dim)', margin: '8px 0 4px' }}>Língua</div>
          {barra(painel.por_lingua)}
        </SdrCard>
      </div>
      <SdrCard title="Alertas">
        {(painel.alertas || []).length === 0
          ? <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>Sem alertas neste filtro.</div>
          : (painel.alertas || []).map(a => (
            <button type="button" key={a.id} onClick={() => onAlerta && onAlerta(a)} style={{ display: 'block', width: '100%', textAlign: 'left', background: 'none', border: 'none', borderBottom: '1px solid var(--border)', padding: '8px 0', cursor: 'pointer', color: 'var(--text)', font: 'inherit', fontSize: 13 }}>{a.label}</button>
          ))}
      </SdrCard>
      {clientes && (
        <SdrCard title={`Campos em falta · ${painel.campos_em_falta?.base || 0} conversas com 3 ou mais mensagens`}>
          {(painel.campos_em_falta?.campos || []).map(c => (
            <button type="button" key={c.id} onClick={() => onCampo && onCampo(c.id)} style={{ display: 'grid', gridTemplateColumns: '120px 1fr 48px', gap: 8, alignItems: 'center', width: '100%', background: 'none', border: 'none', padding: '4px 0', cursor: 'pointer', color: 'var(--text)', font: 'inherit', fontSize: 12 }}>
              <span>{SDR_CAMPOS_FALTA[c.id] || c.id}</span>
              <span style={{ height: 8, borderRadius: 99, background: 'var(--bg-sunken)' }}><span style={{ display: 'block', height: 8, borderRadius: 99, width: `${c.pct || 0}%`, background: (c.pct || 0) > 70 ? 'var(--danger, #ef4444)' : 'var(--warning, #d97706)' }} /></span>
              <span style={{ textAlign: 'right', fontFamily: 'var(--font-mono)' }}>{c.pct == null ? '—' : `${c.pct}%`}</span>
            </button>
          ))}
        </SdrCard>
      )}
      <SdrCard title="Série diária">
        <div style={{ display: 'flex', gap: 18, flexWrap: 'wrap', fontSize: 12, color: 'var(--text-muted)' }}>
          <div>Conversas<SdrSparkline values={(painel.serie || []).map(x => x.conversas)} /></div>
          <div>Erros<SdrSparkline values={(painel.serie || []).map(x => x.erros)} color="var(--danger, #ef4444)" /></div>
          <div>Qualificadas<SdrSparkline values={(painel.serie || []).map(x => x.qualificadas)} color="var(--success, #15803d)" /></div>
        </div>
      </SdrCard>
    </>
  );
}

function SdrSparkline({ values, color }) {
  const nums = (values || []).map(Number).filter(Number.isFinite);
  if (nums.length < 2) return null;
  const max = Math.max(...nums, 1);
  const min = Math.min(...nums, 0);
  const w = 88, h = 22;
  const pts = nums.map((v, i) => {
    const x = (i / (nums.length - 1)) * w;
    const y = h - ((v - min) / (max - min || 1)) * (h - 2) - 1;
    return `${x},${y}`;
  }).join(' ');
  return (
    <svg width={w} height={h} style={{ display: 'block', marginTop: 6 }}>
      <polyline fill="none" stroke={color || 'var(--ai-500)'} strokeWidth="1.5" points={pts} />
    </svg>
  );
}

const SdrStatusBadge = ({ kind, value }) => {
  if (!value) return <span style={{ color: 'var(--text-dim)', fontSize: 11 }}>—</span>;
  const cfg = kind === 'classif' ? CLASSIF_CFG[value]
    : kind === 'flag' ? { label: flagTipoLabel(value), color: 'var(--warning, #d97706)', bg: 'color-mix(in oklch, var(--warning, #d97706) 12%, transparent)' }
    : SDR_STATUS_CFG[value];
  const fallback = { label: value, color: 'var(--text-muted)', bg: 'var(--bg-sunken)' };
  const c = cfg || fallback;
  return (
    <span style={{
      display: 'inline-block', fontSize: 11, fontWeight: 600,
      padding: '3px 9px', borderRadius: 99,
      color: c.color, background: c.bg,
      fontFamily: 'var(--font-mono, monospace)', whiteSpace: 'nowrap',
    }}>{c.label}</span>
  );
};

const SdrToast = ({ msg, type }) => {
  if (!msg) return null;
  const bg = type === 'error' ? 'var(--danger, #dc2626)' : type === 'info' ? 'var(--warning, #d97706)' : 'var(--success, #15803d)';
  return (
    <div style={{
      position: 'fixed', bottom: 24, right: 24, zIndex: 9999,
      padding: '12px 20px', borderRadius: 8, fontSize: 13, fontWeight: 500,
      background: bg, color: 'var(--bg-elev, #fff)', boxShadow: '0 4px 16px color-mix(in oklch, var(--text) 20%, transparent)',
      fontFamily: 'var(--font-body, Inter, sans-serif)',
    }}>{msg}</div>
  );
};

const SdrDropdown = ({ label, value, options, onChange, disabled }) => {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const onClick = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onClick);
    return () => document.removeEventListener('mousedown', onClick);
  }, [open]);
  const current = options.find(o => o.value === value) || options[0];
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button type="button" aria-label={label} aria-haspopup="listbox" aria-expanded={open} onClick={() => !disabled && setOpen(v => !v)} disabled={disabled} style={{
        background: 'var(--bg-elev)', color: disabled ? 'var(--text-dim)' : 'var(--text)',
        border: '1px solid var(--border)', borderRadius: 6,
        padding: '6px 10px', fontSize: 11.5,
        display: 'inline-flex', alignItems: 'center', gap: 8,
        cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.55 : 1,
        fontFamily: 'inherit',
      }}>
        <span style={{ color: 'var(--text-dim)', fontSize: 10, textTransform: 'uppercase', letterSpacing: '.06em', fontFamily: 'var(--font-mono)' }}>{label}</span>
        <span style={{ fontWeight: 500 }}>{current?.label || '—'}</span>
        <span style={{ color: 'var(--text-muted)', fontSize: 9 }}>▾</span>
      </button>
      {open && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 4px)', left: 0, zIndex: 50,
          background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 6,
          boxShadow: '0 8px 24px color-mix(in oklch, var(--text) 12%, transparent)', minWidth: 180, padding: 4, maxHeight: 280, overflowY: 'auto',
        }}>
          {options.map(o => (
            <button type="button" role="option" aria-selected={o.value === value} key={o.value} onClick={() => { onChange(o.value); setOpen(false); }} style={{
              display: 'block', width: '100%', textAlign: 'left',
              background: o.value === value ? 'color-mix(in oklch, var(--ai-500) 12%, transparent)' : 'transparent',
              color: o.value === value ? 'var(--ai-500)' : 'var(--text)',
              border: 'none', padding: '7px 10px', borderRadius: 4,
              fontSize: 12, fontWeight: o.value === value ? 600 : 500,
              cursor: 'pointer', fontFamily: 'inherit',
            }}>{o.label}</button>
          ))}
        </div>
      )}
    </div>
  );
};

const SdrDateRangePicker = ({ value, onChange }) => {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const onClick = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onClick);
    return () => document.removeEventListener('mousedown', onClick);
  }, [open]);
  const current = SDR_PERIODS.find(p => p.id === value) || SDR_PERIODS[1];
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button type="button" onClick={() => setOpen(v => !v)} style={{
        background: 'var(--bg-elev)', color: 'var(--text)',
        border: '1px solid var(--border)', borderRadius: 6,
        padding: '6px 10px', fontSize: 11.5,
        display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer', fontFamily: 'inherit',
      }}>
        <span style={{ color: 'var(--text-dim)', fontSize: 10, textTransform: 'uppercase', letterSpacing: '.06em', fontFamily: 'var(--font-mono)' }}>Período</span>
        <span style={{ fontWeight: 500 }}>{current.label}</span>
        <span style={{ color: 'var(--text-muted)', fontSize: 9 }}>▾</span>
      </button>
      {open && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 4px)', right: 0, zIndex: 50,
          background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 6,
          boxShadow: '0 8px 24px color-mix(in oklch, var(--text) 12%, transparent)', minWidth: 180, padding: 4,
        }}>
          {SDR_PERIODS.map(p => (
            <button type="button" key={p.id} onClick={() => { onChange(p.id); setOpen(false); }} style={{
              display: 'block', width: '100%', textAlign: 'left',
              background: p.id === value ? 'color-mix(in oklch, var(--ai-500) 12%, transparent)' : 'transparent',
              color: p.id === value ? 'var(--ai-500)' : 'var(--text)',
              border: 'none', padding: '7px 10px', borderRadius: 4,
              fontSize: 12, fontWeight: p.id === value ? 600 : 500, cursor: 'pointer', fontFamily: 'inherit',
            }}>{p.label}</button>
          ))}
        </div>
      )}
    </div>
  );
};

const SdrBanner = ({ kpi, onGo }) => {
  const [seed] = React.useState(Math.random);
  const hour = new Date().getHours();
  const rawName = (window.currentUser && (window.currentUser.nome_apresentar || window.currentUser.nome)) || '';
  const first = rawName.split(' ')[0] || '';
  const n = first ? first.charAt(0).toUpperCase() + first.slice(1).toLowerCase() : 'Olá';
  const pl = (k, s, p) => k === 1 ? s : p;

  const review = parseInt(kpi?.n_para_revisao || 0);
  const hot    = parseInt(kpi?.n_hot || 0);
  const qual   = parseInt(kpi?.qualificados || 0);
  const total  = parseInt(kpi?.total_conversas || 0);
  const diverg = parseInt(kpi?.n_divergentes || 0);

  const { heading, body, suggestion } = React.useMemo(() => {
    let pool;
    if (review > 0) pool = [
      `${n}, tens ${review} ${pl(review, 'conversa sinalizada', 'conversas sinalizadas')} para rever.`,
      `${n}, ${review} ${pl(review, 'interacção espera', 'interacções esperam')} revisão humana.`,
    ];
    else if (hot > 0) pool = [
      `${n}, ${hot} ${pl(hot, 'lead HOT está', 'leads HOT estão')} no funil. Confirma o follow-up.`,
      `${n}, há ${hot} ${pl(hot, 'lead quente', 'leads quentes')} — vale a pena olhar.`,
    ];
    else if (diverg > 0) pool = [
      `${n}, ${diverg} ${pl(diverg, 'ficheiro carregado diverge', 'ficheiros carregados divergem')} da versão esperada.`,
    ];
    else if (total > 0) pool = [
      `${n}, ${total} ${pl(total, 'conversa no período', 'conversas no período')} · ${qual} ${pl(qual, 'qualificada', 'qualificadas')}.`,
      `${n}, a Digi AI está a trabalhar. Pipeline estável neste período.`,
    ];
    else {
      const h = hour < 12 ? 'Bom dia' : hour < 19 ? 'Boa tarde' : 'Boa noite';
      pool = [`${h}${n !== 'Olá' ? `, ${n}` : ''}. Ainda sem conversas neste período.`];
    }
    const heading = pool[Math.floor(seed * pool.length)];
    const partes = [];
    if (review) partes.push(`${review} ${pl(review, 'conversa à espera', 'conversas à espera')} de revisão.`);
    if (hot && !review) partes.push(`${hot} HOT no período.`);
    if (qual && !review) partes.push(`${qual} ${pl(qual, 'lead qualificado', 'leads qualificados')}.`);
    if (!partes.length) partes.push('A qualidade das respostas e a conformidade com as Frameworks aparecem aqui à medida que a Digi AI conversa.');
    let suggestion = null;
    if (review > 0) suggestion = { text: `${review} ${pl(review, 'conversa sinalizada', 'conversas sinalizadas')} — abre a lista filtrada.`, action: 'Ver sinalizadas', go: 'review' };
    else if (hot > 0) suggestion = { text: `${hot} ${pl(hot, 'lead HOT', 'leads HOT')} no período.`, action: 'Ver HOT', go: 'hot' };
    else if (diverg > 0) suggestion = { text: 'Há ficheiros com SHA diferente do esperado.', action: 'Ver Health', go: 'health' };
    return { heading, body: partes.join(' '), suggestion };
  }, [kpi, seed]);

  return (
    <div style={{ flexShrink: 0, padding: '10px 0 6px' }}>
      <div style={{ fontSize: 22, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display)', marginBottom: 6, letterSpacing: '-0.02em' }}>{heading}</div>
      <div style={{ fontSize: 13, color: 'var(--text-muted)', lineHeight: 1.75 }}>{body}</div>
      {suggestion && (
        <div style={{ marginTop: 12, display: 'flex', alignItems: 'center', gap: 12, padding: '10px 14px', borderRadius: 8, background: 'color-mix(in oklch, var(--ai-500) 6%, transparent)', border: '1px solid color-mix(in oklch, var(--ai-500) 20%, transparent)' }}>
          <span style={{ fontSize: 12, color: 'var(--ai-500)', flex: 1 }}>{suggestion.text}</span>
          <button type="button" className="btn btn-xs btn-ai" onClick={() => onGo && onGo(suggestion.go)}>{suggestion.action}</button>
        </div>
      )}
    </div>
  );
};

const SdrKPIs = ({ items, activeId, onFilter }) => (
  <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
    {items.map(k => {
      const isActive = !k.noClick && activeId === k.id;
      return (
        <div key={k.id}
          onClick={() => { if (k.noClick) return; onFilter && onFilter(isActive ? null : k.id); }}
          style={{
            flex: '1 1 0', minWidth: 130,
            background: 'var(--bg-elev)',
            border: `1px solid ${isActive ? k.accent : 'var(--border)'}`,
            borderRadius: 8, padding: '12px 16px 0',
            display: 'flex', flexDirection: 'column', gap: 4, overflow: 'hidden',
            cursor: k.noClick ? 'default' : 'pointer',
            transition: 'border-color 0.15s',
          }}>
          <div style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--text-muted)', fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap' }}>{k.label}</div>
          <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'var(--font-display)', color: k.accent, lineHeight: 1, paddingBottom: 4 }}>{k.value}</div>
          {k.sub && <div style={{ fontSize: 11, color: 'var(--text-muted)', paddingBottom: 4 }}>{k.sub}</div>}
          <div style={{ height: 3, background: 'var(--bg-sunken)', marginLeft: -16, marginRight: -16 }}>
            <div style={{ height: '100%', width: `${(k.fill || 0) * 100}%`, background: k.accent, transition: 'width 0.4s' }} />
          </div>
        </div>
      );
    })}
  </div>
);

const SdrEmpty = ({ title, hint, onRetry }) => (
  <div style={{ padding: '48px 0', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
    <div style={{ fontSize: 13, color: 'var(--text-muted)', textAlign: 'center' }}>{title}</div>
    {hint && <div style={{ fontSize: 12, color: 'var(--text-dim)', textAlign: 'center', maxWidth: 480 }}>{hint}</div>}
    {onRetry && <button type="button" className="btn btn-xs" onClick={onRetry}>Tentar outra vez</button>}
  </div>
);

const SdrDistCard = ({ title, rows, color }) => {
  const max = Math.max(1, ...(rows || []).map(r => r.n));
  return (
    <div style={{ background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 8, padding: '14px 16px', flex: '1 1 240px', minWidth: 220 }}>
      <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', letterSpacing: '0.08em', color: 'var(--text-dim)', textTransform: 'uppercase', marginBottom: 10 }}>{title}</div>
      {!(rows || []).length ? (
        <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>Sem dados</div>
      ) : (rows || []).map(r => (
        <div key={r.key} style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
          <div style={{ width: 110, fontSize: 11.5, color: 'var(--text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.label}</div>
          <div style={{ flex: 1, height: 6, background: 'var(--bg-sunken)', borderRadius: 99, overflow: 'hidden' }}>
            <div style={{ width: `${(r.n / max) * 100}%`, height: '100%', background: color || 'var(--ai-500)', borderRadius: 99 }} />
          </div>
          <div style={{ width: 28, textAlign: 'right', fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-muted)' }}>{r.n}</div>
        </div>
      ))}
    </div>
  );
};

const SdrFlagModal = ({ open, onConfirm, onClose, bulkCount }) => {
  const [tipo, setTipo] = React.useState('fora_framework');
  const [nota, setNota] = React.useState('');
  if (!open) return null;
  const node = (
    <div style={{ position: 'fixed', inset: 0, zIndex: 10000, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'color-mix(in oklch, var(--text) 45%, transparent)' }}
      onClick={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div style={{ background: 'var(--bg-elev)', borderRadius: 14, width: 440, boxShadow: '0 24px 64px color-mix(in oklch, var(--text) 18%, transparent)', overflow: 'hidden' }}>
        <div style={{ padding: '20px 24px 16px', borderBottom: '1px solid var(--border)' }}>
          <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display)' }}>
            {bulkCount > 1 ? `Sinalizar ${bulkCount} conversas` : 'Sinalizar para revisão'}
          </div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>A Digi AI (ou um humano) vai marcar esta conversa para análise.</div>
        </div>
        <div style={{ padding: '16px 24px', display: 'flex', flexDirection: 'column', gap: 12 }}>
          <label style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.06em', textTransform: 'uppercase' }}>Tipo de desvio</label>
          <select value={tipo} onChange={e => setTipo(e.target.value)}
            style={{ padding: '8px 10px', borderRadius: 8, border: '1px solid var(--border)', fontSize: 13, fontFamily: 'inherit', color: 'var(--text)', background: 'var(--bg-sunken)' }}>
            {FLAG_TIPOS.map(t => <option key={t.value} value={t.value}>{t.label}</option>)}
          </select>
          <textarea value={nota} onChange={e => setNota(e.target.value)} rows={3} placeholder="Nota opcional — o que saiu do padrão?"
            style={{ width: '100%', padding: '8px 12px', borderRadius: 8, border: '1px solid var(--border)', fontSize: 13, fontFamily: 'inherit', resize: 'vertical', boxSizing: 'border-box', color: 'var(--text)', background: 'var(--bg-sunken)' }} />
        </div>
        <div style={{ padding: '0 24px 20px', display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <button type="button" onClick={onClose} className="btn">Cancelar</button>
          <button type="button" className="btn btn-ai" onClick={() => { onConfirm({ tipo_desvio: tipo, nota }); setNota(''); }}>Sinalizar</button>
        </div>
      </div>
    </div>
  );
  return ReactDOM.createPortal(node, document.body);
};

const SdrConfirmModal = ({ open, title, body, confirmLabel, onConfirm, onClose }) => {
  if (!open) return null;
  const node = (
    <div style={{ position: 'fixed', inset: 0, zIndex: 10000, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'color-mix(in oklch, var(--text) 45%, transparent)' }}
      onClick={e => { if (e.target === e.currentTarget) onClose && onClose(); }}>
      <div style={{ background: 'var(--bg-elev)', borderRadius: 14, width: 420, boxShadow: '0 24px 64px color-mix(in oklch, var(--text) 18%, transparent)', overflow: 'hidden' }}>
        <div style={{ padding: '20px 24px 16px', borderBottom: '1px solid var(--border)' }}>
          <div style={{ fontSize: 15, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display)' }}>{title || 'Confirmar'}</div>
          {body && <div style={{ fontSize: 13, color: 'var(--text-muted)', marginTop: 8, lineHeight: 1.5 }}>{body}</div>}
        </div>
        <div style={{ padding: '16px 24px 20px', display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <button type="button" onClick={onClose} className="btn">Cancelar</button>
          <button type="button" className="btn btn-ai" onClick={onConfirm}>{confirmLabel || 'Confirmar'}</button>
        </div>
      </div>
    </div>
  );
  return ReactDOM.createPortal(node, document.body);
};

const SdrHeader = ({ title, contextLine, pct, tab, setTab, back, extra, tabs, filters }) => (
  <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 · SDR
    </div>
    <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
        {back && (
          <button type="button" onClick={back} className="btn" style={{ height: 30, padding: '0 12px', fontSize: 12 }}>← Voltar</button>
        )}
        <div>
          <h1 style={{ margin: 0, fontSize: 21, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display)', letterSpacing: '-0.01em', lineHeight: 1.2 }}>
            {title}
          </h1>
          {contextLine && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 6, flexWrap: 'wrap' }}>
              <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>{contextLine}</span>
              {pct != null && (
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  <div style={{ width: 60, height: 4, borderRadius: 99, background: 'var(--border)', overflow: 'hidden' }}>
                    <div style={{ width: `${pct}%`, height: '100%', borderRadius: 99, background: 'var(--success, #22c55e)', transition: 'width 0.4s ease' }} />
                  </div>
                  <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>{pct}% qualificadas</span>
                </div>
              )}
            </div>
          )}
        </div>
      </div>
      {extra}
    </div>
    <div style={{ height: 1, background: 'var(--border)', margin: '16px -40px 0' }} />
    {!back && filters}
    {!back && (
      <div style={{ display: 'flex', gap: 0, overflowX: 'auto', alignItems: 'stretch' }}>
        {(tabs || SDR_TABS).map(t => (
          <button type="button" key={t.id} onClick={() => setTab(t.id)} style={{
            background: 'none', border: 'none', outline: 'none',
            borderBottom: `2px solid ${tab === t.id ? 'var(--ai-500)' : 'transparent'}`,
            color: tab === t.id ? 'var(--text)' : 'var(--text-muted)',
            fontSize: 13, fontWeight: tab === t.id ? 600 : 500,
            fontFamily: 'var(--font-display)', letterSpacing: '.01em',
            padding: '10px 18px 12px', cursor: 'pointer', whiteSpace: 'nowrap',
          }}>{t.label}</button>
        ))}
      </div>
    )}
  </div>
);

const SdrCard = ({ title, children }) => (
  <div style={{ background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 8, padding: '14px 16px' }}>
    <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', letterSpacing: '0.08em', color: 'var(--text-dim)', textTransform: 'uppercase', marginBottom: 10 }}>{title}</div>
    {children}
  </div>
);

const SdrKV = ({ label, value }) => (
  <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, padding: '4px 0', fontSize: 12.5 }}>
    <span style={{ color: 'var(--text-muted)' }}>{label}</span>
    <span style={{ color: 'var(--text)', fontWeight: 500, textAlign: 'right' }}>{value == null || value === '' ? '—' : String(value)}</span>
  </div>
);

function SdrFichaModal({ md, titulo }) {
  const [open, setOpen] = React.useState(false);
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open]);
  return (
    <div style={{ marginTop: 8 }}>
      <button type="button" className="btn btn-xs" onClick={() => setOpen(true)}>Ver ficha</button>
      {open && ReactDOM.createPortal(
        <div style={{ position: 'fixed', inset: 0, zIndex: 10000, background: 'color-mix(in oklch, var(--text) 45%, transparent)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
          onClick={e => { if (e.target === e.currentTarget) setOpen(false); }}>
          <div style={{ background: 'var(--bg-elev)', borderRadius: 12, width: 'min(760px, 92vw)', maxHeight: '80vh', overflow: 'auto', padding: 20 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 12 }}>
              <strong>{titulo || 'Ficha'}</strong>
              <button type="button" className="btn btn-xs" onClick={() => setOpen(false)}>Fechar</button>
            </div>
            <pre style={{ whiteSpace: 'pre-wrap', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text)' }}>{md}</pre>
          </div>
        </div>,
        document.body
      )}
    </div>
  );
}

function SdrChecklist({ data, sessionId, readOnly, busy, onToast, onSaved }) {
  const latest = data?.conversation_quality?.latest;
  const regras = data?.rubric?.regras || [];
  const desc = Object.fromEntries(regras.map(r => [r.id, r.descricao]));
  const items = Array.isArray(latest?.checklist_json) ? latest.checklist_json : [];
  const [notas, setNotas] = React.useState({});
  const [acordos, setAcordos] = React.useState({});
  const [extraRegra, setExtraRegra] = React.useState('');
  const [extraMsg, setExtraMsg] = React.useState('');
  const [resposta, setResposta] = React.useState('');
  const [respostaMsg, setRespostaMsg] = React.useState('');
  const [enviar, setEnviar] = React.useState(true);
  const [naOpen, setNaOpen] = React.useState(false);
  if (!latest) return null;
  const ordem = { falhou: 0, cumpriu: 1, na: 2 };
  const sorted = [...items].sort((a, b) => (ordem[a.estado] ?? 9) - (ordem[b.estado] ?? 9));
  const visiveis = sorted.filter(it => naOpen || it.estado !== 'na');
  const digiMsgs = (Array.isArray(data.session?.messages) ? data.session.messages : [])
    .map((m, i) => ({ i, m }))
    .filter(x => x.m.role === 'assistant' || x.m.role === 'digi');
  const guardar = async () => {
    const itens = Object.keys(acordos).map(regra_id => ({
      regra_id,
      acordo: acordos[regra_id],
      msg_idx: items.find(it => it.regra_id === regra_id)?.msg_idx ?? null,
      nota: notas[regra_id] || null,
    }));
    try {
      await SdrAPI.revisao(sessionId, {
        conversation_quality_id: latest.id,
        itens,
        regra_extra: extraRegra ? { regra_id: extraRegra, msg_idx: extraMsg === '' ? null : parseInt(extraMsg, 10), nota: notas.__extra || null } : undefined,
        resposta_correcta: resposta.trim() ? { msg_idx: respostaMsg === '' ? null : parseInt(respostaMsg, 10), texto: resposta.trim() } : undefined,
        enviar_melhoria: enviar,
        marcar_revisto: true,
      });
      onToast && onToast('Revisão guardada');
      onSaved && onSaved();
    } catch (e) {
      onToast && onToast(e.message, 'error');
    }
  };
  return (
    <SdrCard title={`Checklist · ${latest.score_global ?? '—'} · ${latest.conformidade_pct ?? '—'}%`}>
      <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 8 }}>{latest.resumo || 'Avaliação da conversa contra o SP Clientes.'}</div>
      {visiveis.map(it => (
        <div key={it.regra_id + String(it.msg_idx)} style={{ padding: '8px 0', borderTop: '1px solid var(--border)', fontSize: 12 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8 }}>
            <strong style={{ color: it.estado === 'falhou' ? (it.severidade === 'critica' ? 'var(--danger, #ef4444)' : 'var(--warning, #d97706)') : 'var(--text)' }}>{it.regra_id}</strong>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-dim)' }}>{it.estado}{it.msg_idx != null ? ` · msg ${it.msg_idx}` : ''}</span>
          </div>
          <div style={{ color: 'var(--text-muted)', marginTop: 2 }}>{desc[it.regra_id] || it.evidencia || ''}</div>
          {it.evidencia && <div style={{ marginTop: 2 }}>{it.evidencia}</div>}
          {!readOnly && it.estado === 'falhou' && (
            <div style={{ display: 'flex', gap: 6, marginTop: 6, flexWrap: 'wrap' }}>
              <button type="button" className="btn btn-xs" onClick={() => setAcordos(a => ({ ...a, [it.regra_id]: true }))}>Concordo</button>
              <button type="button" className="btn btn-xs" onClick={() => setAcordos(a => ({ ...a, [it.regra_id]: false }))}>Discordo</button>
              {acordos[it.regra_id] != null && <span style={{ fontSize: 11 }}>{acordos[it.regra_id] ? 'acordo' : 'desacordo'}</span>}
              <input value={notas[it.regra_id] || ''} onChange={e => setNotas(n => ({ ...n, [it.regra_id]: e.target.value }))} placeholder="Nota" style={{ flex: 1, minWidth: 120, padding: '4px 6px', border: '1px solid var(--border)', borderRadius: 6, fontSize: 11 }} />
            </div>
          )}
        </div>
      ))}
      <button type="button" className="btn btn-xs" style={{ marginTop: 8 }} onClick={() => setNaOpen(v => !v)}>{naOpen ? 'Esconder não aplicáveis' : 'Mostrar não aplicáveis'}</button>
      {!readOnly && (
        <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 6 }}>
          <div style={{ fontSize: 11, color: 'var(--text-dim)' }}>Adicionar regra violada</div>
          <select aria-label="Regra violada" value={extraRegra} onChange={e => setExtraRegra(e.target.value)} style={{ padding: '6px 8px', borderRadius: 6, border: '1px solid var(--border)' }}>
            <option value="">—</option>
            {regras.map(r => <option key={r.id} value={r.id}>{r.id}</option>)}
          </select>
          <select aria-label="Mensagem da Digi" value={extraMsg} onChange={e => setExtraMsg(e.target.value)} style={{ padding: '6px 8px', borderRadius: 6, border: '1px solid var(--border)' }}>
            <option value="">Mensagem</option>
            {digiMsgs.map((x, n) => <option key={x.i} value={n}>Digi #{n}</option>)}
          </select>
          <div style={{ fontSize: 11, color: 'var(--text-dim)' }}>Resposta correcta</div>
          <select aria-label="Mensagem a corrigir" value={respostaMsg} onChange={e => setRespostaMsg(e.target.value)} style={{ padding: '6px 8px', borderRadius: 6, border: '1px solid var(--border)' }}>
            <option value="">Mensagem</option>
            {digiMsgs.map((x, n) => <option key={'r' + x.i} value={n}>Digi #{n}</option>)}
          </select>
          <textarea value={resposta} onChange={e => setResposta(e.target.value)} rows={3} placeholder="O que a Digi devia ter respondido" style={{ width: '100%', boxSizing: 'border-box', padding: 8, borderRadius: 6, border: '1px solid var(--border)', fontSize: 12 }} />
          <label style={{ display: 'flex', gap: 6, alignItems: 'center', fontSize: 12 }}>
            <input type="checkbox" checked={enviar} onChange={e => setEnviar(e.target.checked)} />
            Enviar para melhoria do prompt
          </label>
          <button type="button" className="btn btn-xs btn-ai" disabled={busy} onClick={guardar}>Guardar e marcar revisto</button>
        </div>
      )}
    </SdrCard>
  );
}

function sdrTextoMensagem(raw) {
  const text = String(raw || '');
  const m = text.match(/^\[TEMPLATE:([^\]]+)\]$/);
  if (!m) return text;
  const nome = m[1].replace(/_/g, ' ');
  return { template: nome };
}

const SdrConversaView = ({ sessionId, onBack, onToast, embedded, readOnly }) => {
  const [data, setData] = React.useState(null);
  const [err, setErr] = React.useState('');
  const [flagOpen, setFlagOpen] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [confirm, setConfirm] = React.useState(null);
  const [comerciais, setComerciais] = React.useState([]);

  const load = React.useCallback(() => {
    setErr('');
    SdrAPI.conversa(sessionId)
      .then(setData)
      .catch(e => setErr(e.message));
  }, [sessionId]);
  React.useEffect(() => { load(); }, [load]);
  React.useEffect(() => {
    SdrAPI.comerciais().then(d => setComerciais(d.rows || [])).catch(() => {});
  }, []);

  const s = data?.session || {};
  const ce = data?.contacto || null;
  const sessMsgs = Array.isArray(s.messages) ? s.messages : [];
  const historico = Array.isArray(data?.historico) ? data.historico : [];
  const msgs = historico.length > sessMsgs.length ? historico : sessMsgs;
  const nAssist = (list) => list.filter(m => m.role === 'assistant' || m.role === 'digi').length;
  const offsetAssist = msgs === historico ? Math.max(0, nAssist(historico) - nAssist(sessMsgs)) : 0;
  const name = s.lead_name_wa || ce?.nome || s.lead_company_wa || sPhoneLabel(s.visitor_id);
  function sPhoneLabel(id) { return sdrPhone(id) || id; }

  const doFlag = async (payload) => {
    setBusy(true);
    try {
      await SdrAPI.flag(sessionId, payload);
      setFlagOpen(false);
      onToast && onToast('Conversa sinalizada');
      load();
    } catch (e) {
      onToast && onToast(e.message, 'error');
    } finally { setBusy(false); }
  };
  const doUnflag = async (id) => {
    setBusy(true);
    try {
      await SdrAPI.flag(sessionId, { unflag: true, quality_id: id });
      onToast && onToast('Marcada como revista');
      load();
    } catch (e) {
      onToast && onToast(e.message, 'error');
    } finally { setBusy(false); }
  };

  return (
    <div data-theme="light" style={embedded ? undefined : SDR_THEME}>
      {!embedded && (
      <SdrHeader
        title={name}
        contextLine={[s.ambiente === 'staging' ? 'Staging' : s.ambiente === 'producao' ? 'Produção' : null, s.sp_name, s.sp_origem === 'inferido' ? 'histórico' : null, s.wa_numero ? `WA ${s.wa_numero}` : null, (data?.runs || []).find(r => r.sp_sha) ? `SP ${String((data.runs || []).find(r => r.sp_sha).sp_sha).slice(0, 7)}` : null].filter(Boolean).join(' · ')}
        back={onBack}
        extra={readOnly ? null : (
          <button type="button" className="btn btn-ai" disabled={busy} onClick={() => setFlagOpen(true)}>Sinalizar para revisão</button>
        )}
      />
      )}
      <div className="scrollbar" style={embedded ? { background: 'transparent' } : { flex: 1, minHeight: 0, overflowY: 'auto', padding: '24px 40px 48px', background: 'var(--bg)' }}>
        {err && <div style={{ color: 'var(--danger)', fontSize: 12, marginBottom: 12 }}>{err}</div>}
        {!data && !err && <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>A carregar…</div>}
        {data && (
          <div style={{ display: 'flex', gap: 20, alignItems: 'flex-start', flexWrap: 'wrap' }}>
            <div style={{ flex: '1 1 420px', minWidth: 320, display: 'flex', flexDirection: 'column', gap: 10 }}>
              <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', letterSpacing: '0.08em', color: 'var(--text-dim)' }}>TRANSCRIÇÃO · {msgs.length} msgs</div>
              {msgs.length === 0 && <SdrEmpty title="Sem mensagens nesta sessão." />}
              {(() => {
                const runsAsc = [...(data.runs || [])].slice().reverse();
                const falhasChk = (data.conversation_quality?.latest?.checklist_json || []).filter(it => it.estado === 'falhou');
                let aiIdx = 0;
                return msgs.map((m, i) => {
                const isUser = (m.role || '') === 'user';
                const isHuman = (m.role || '') === 'human';
                const digiIndex = isUser || isHuman ? null : aiIdx++;
                const idxAuditoria = digiIndex == null ? null : digiIndex - offsetAssist;
                const run = idxAuditoria != null && idxAuditoria >= 0 ? runsAsc[idxAuditoria] : null;
                const falhasMsg = idxAuditoria == null || idxAuditoria < 0 ? [] : falhasChk.filter(it => it.msg_idx === idxAuditoria);
                const nossa = !isUser;
                return (
                  <div key={i} style={{ display: 'flex', justifyContent: nossa ? 'flex-end' : 'flex-start' }}>
                    <div style={{
                      maxWidth: 'min(82%, 440px)', padding: '10px 12px', fontSize: 13, lineHeight: 1.55,
                      background: isUser ? 'var(--bg-elev)' : 'color-mix(in oklch, var(--ai-500) 16%, var(--bg-elev))',
                      border: `1px solid ${falhasMsg.length ? (falhasMsg.some(f => f.severidade === 'critica') ? 'var(--danger, #ef4444)' : 'var(--warning, #d97706)') : 'var(--border)'}`,
                      borderRadius: isUser ? '4px 16px 16px 16px' : '16px 4px 16px 16px',
                      color: 'var(--text)',
                    }}>
                      <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', marginBottom: 4, display: 'flex', gap: 8, alignItems: 'center' }}>
                        <span>{isUser ? 'Lead' : isHuman ? 'Humano' : 'Digi AI'}{m.created_at ? ` · ${sdrRelTime(m.created_at)}` : ''}{m.estado ? ` · ${m.estado}` : ''}</span>
                        {falhasMsg.length > 0 && (
                          <span title={falhasMsg.map(f => `${f.regra_id}: ${f.evidencia || ''}`).join('\n')} style={{ color: 'var(--danger, #ef4444)', fontWeight: 700 }}>{falhasMsg.map(f => f.regra_id).join(' ')}</span>
                        )}
                        {!isUser && run && run.score_global != null && (
                          <span style={{
                            padding: '1px 6px', borderRadius: 99, fontSize: 10, fontWeight: 700,
                            color: run.score_global >= 70 ? 'var(--success, #22c55e)' : run.score_global >= 50 ? 'var(--warning, #d97706)' : 'var(--danger, #ef4444)',
                            background: 'var(--bg-sunken)',
                          }}>{run.score_global}</span>
                        )}
                      </div>
                      {(() => { const t = sdrTextoMensagem(m.content || m.text || ''); return t && t.template ? <span style={{ fontSize: 11, color: 'var(--text-muted)' }}>Template enviado · {t.template}</span> : (m.content || m.text || ''); })()}
                    </div>
                  </div>
                );
                });
              })()}
            </div>
            <div style={{ flex: '0 1 340px', minWidth: 280, display: 'flex', flexDirection: 'column', gap: 12 }}>
              <SdrChecklist data={data} sessionId={sessionId} readOnly={readOnly} busy={busy} onToast={onToast} onSaved={load} />
              {data.ficha && (
                <SdrCard title="Ficha usada">
                  <SdrKV label="Campanha" value={data.ficha.titulo} />
                  <SdrKV label="Versão" value={data.ficha.version != null ? `v${data.ficha.version}` : null} />
                  <SdrKV label="Match" value={data.ficha.match_tipo} />
                  {data.ficha.md && <SdrFichaModal md={data.ficha.md} titulo={data.ficha.titulo} />}
                </SdrCard>
              )}
              {data.colisao && (
                <div style={{ fontSize: 12, color: 'var(--warning, #b45309)', background: 'color-mix(in oklch, #d97706 10%, var(--bg-elev))', border: '1px solid color-mix(in oklch, #d97706 30%, var(--border))', borderRadius: 8, padding: '8px 10px' }}>
                  Esta conversa de produção pode conter mensagens de staging anteriores à separação dos números.
                </div>
              )}
              <SdrCard title="Campos de qualificação">
                {(data.campos || []).map(c => (
                  <div key={c.id} style={{ display: 'flex', justifyContent: 'space-between', gap: 8, padding: '4px 0', fontSize: 12, borderBottom: '1px solid var(--border)' }}>
                    <span style={{ color: 'var(--text-muted)' }}>{c.label}</span>
                    <span style={{ textAlign: 'right', color: c.em_falta ? '#b91c1c' : 'var(--text)', background: c.em_falta ? 'color-mix(in oklch, #ef4444 10%, transparent)' : 'transparent', borderRadius: 4, padding: '0 4px' }}>{c.em_falta ? 'em falta' : String(c.valor)}</span>
                  </div>
                ))}
              </SdrCard>
              <SdrCard title="Qualificação">
                <SdrKV label="Classificação" value={s.classification} />
                <div style={{ padding: '4px 0' }}><SdrStatusBadge kind="classif" value={s.classification} /></div>
                <SdrKV label="Score" value={s.lead_score} />
                <SdrKV label="Volume m²/mês" value={s.volume_m2_mes} />
                <SdrKV label="Timing" value={s.timing_bucket} />
                <SdrKV label="Dor" value={s.pain_identified} />
                <SdrKV label="Aceita demo" value={s.aceita_demo == null ? null : (s.aceita_demo ? 'Sim' : 'Não')} />
                <SdrKV label="Orçamento" value={s.budget_range} />
                <SdrKV label="Decisor" value={s.decisor_role || s.cargo_declarado} />
                <SdrKV label="Equipamento" value={s.equipment_current} />
                <SdrKV label="Objecção" value={s.objecao_principal} />
                <SdrKV label="Recomendação" value={s.recomendacao_comercial} />
              </SdrCard>
              <SdrCard title="Origem">
                <SdrKV label="Campanha" value={s.campaign_name} />
                <SdrKV label="Canal" value={s.origin_channel} />
                <SdrKV label="País / língua" value={[s.origin_country, s.origin_language].filter(Boolean).join(' · ')} />
                <SdrKV label="Ad" value={s.ad_context && (s.ad_context.headline || s.ad_context.body)} />
              </SdrCard>
              {!readOnly && <SdrCard title="CRM">
                {ce ? (
                  <>
                    <SdrKV label="Nome" value={ce.nome} />
                    <SdrKV label="Empresa" value={ce.empresa} />
                    <SdrKV label="Email" value={ce.email} />
                    <SdrKV label="Score CRM" value={ce.lead_score} />
                    <div style={{ padding: '6px 0' }}><SdrStatusBadge kind="sdr" value={ce.sdr_status} /></div>
                    <SdrDropdown label="Estado" value={ce.sdr_status || 'pendente'}
                      options={Object.keys(SDR_STATUS_CFG).map(v => ({ value: v, label: SDR_STATUS_CFG[v].label }))}
                      onChange={(st) => setConfirm({
                        title: 'Alterar estado CRM',
                        body: `Passar este lead para «${SDR_STATUS_CFG[st]?.label || st}»?`,
                        confirmLabel: 'Alterar',
                        run: async () => {
                          await SdrAPI.patchCrm(sessionId, { sdr_status: st });
                          onToast && onToast('Estado CRM actualizado');
                          load();
                        },
                      })} />
                    <SdrDropdown label="Comercial" value={ce.sdr_comercial_email || ''}
                      options={[{ value: '', label: '—' }].concat(comerciais.map(c => ({ value: c.email, label: c.email })))}
                      onChange={(em) => setConfirm({
                        title: 'Atribuir comercial',
                        body: em ? `Atribuir este lead a ${em}?` : 'Remover comercial atribuído?',
                        confirmLabel: 'Atribuir',
                        run: async () => {
                          await SdrAPI.patchCrm(sessionId, { comercial_email: em || null });
                          onToast && onToast(em ? `Atribuído a ${em}` : 'Comercial removido');
                          load();
                        },
                      })} />
                    <textarea defaultValue={ce.sdr_notas || ''} rows={2} placeholder="Nota SDR…"
                      id="sdr-crm-nota"
                      style={{ width: '100%', marginTop: 8, padding: '8px 10px', borderRadius: 8, border: '1px solid var(--border)', fontSize: 12, fontFamily: 'inherit', boxSizing: 'border-box', color: 'var(--text)', background: 'var(--bg-sunken)' }} />
                    <div style={{ display: 'flex', gap: 6, marginTop: 8, flexWrap: 'wrap' }}>
                      <button type="button" className="btn btn-xs btn-ai" disabled={busy} onClick={async () => {
                        const nota = document.getElementById('sdr-crm-nota')?.value || '';
                        try {
                          await SdrAPI.patchCrm(sessionId, { nota });
                          onToast && onToast('Nota guardada');
                          load();
                        } catch (e) { onToast && onToast(e.message, 'error'); }
                      }}>Guardar nota</button>
                      <button type="button" className="btn btn-xs" onClick={() => {
                        window.location.hash = `screen=marketing&sub=leads-inbound&pessoa=${encodeURIComponent(ce.id)}`;
                      }}>Abrir no CRM</button>
                    </div>
                  </>
                ) : (
                  <div>
                    <div style={{ fontSize: 12, color: 'var(--text-dim)', marginBottom: 8 }}>Sem contacto ligado no CRM.</div>
                    <button type="button" className="btn btn-xs btn-ai" disabled={busy} onClick={async () => {
                      setBusy(true);
                      try {
                        await SdrAPI.criarContacto(sessionId);
                        onToast && onToast('Contacto criado');
                        load();
                      } catch (e) { onToast && onToast(e.message, 'error'); }
                      finally { setBusy(false); }
                    }}>Criar contacto no CRM</button>
                  </div>
                )}
              </SdrCard>}
              <SdrCard title="Execuções">
                {(data.runs || []).length === 0
                  ? <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>Ainda sem execuções nesta sessão — entram aqui depois da próxima resposta da Digi AI.</div>
                  : (data.runs || []).map(r => (
                    <div key={r.id} style={{ padding: '8px 0', borderBottom: '1px solid var(--border)', fontSize: 12 }}>
                      <div style={{ fontWeight: 600 }}>{r.sp_name || 'SP'} · {r.status === 'erro' ? 'erro' : (r.frame_activo || 'ok')}</div>
                      <div style={{ color: 'var(--text-muted)' }}>
                        {r.etapa_qualificacao || r.level || '—'} · {r.duration_ms != null ? `${r.duration_ms}ms` : '—'}
                        {r.cost_usd != null ? ` · $${Number(r.cost_usd).toFixed(4)}` : ''}
                        {r.sp_sha ? ` · ${String(r.sp_sha).slice(0, 7)}` : ''}
                      </div>
                      {r.erro ? <div style={{ color: 'var(--danger, #ef4444)', marginTop: 4 }}>{r.erro}</div> : null}
                      {r.score_global != null && (
                        <div style={{ marginTop: 4, color: 'var(--text-muted)', fontSize: 11 }}>
                          C {r.score_clareza} · R {r.score_relevancia} · T {r.score_tom} · F {r.score_framework} · Σ {r.score_global}
                          {r.desvio_detectado ? ` · desvio: ${r.tipo_desvio ? flagTipoLabel(r.tipo_desvio) : 'sim'}` : ''}
                        </div>
                      )}
                      {r.quality_id && !r.revisto_at && (
                        <div style={{ display: 'flex', gap: 6, marginTop: 6 }}>
                          <button type="button" className="btn btn-xs" disabled={busy} onClick={async () => {
                            try {
                              await SdrAPI.flag(sessionId, { quality_id: r.quality_id, acordo: true });
                              onToast && onToast('Avaliação confirmada');
                              load();
                            } catch (e) { onToast && onToast(e.message, 'error'); }
                          }}>Concordo</button>
                          <button type="button" className="btn btn-xs" disabled={busy} onClick={async () => {
                            try {
                              await SdrAPI.flag(sessionId, { quality_id: r.quality_id, acordo: false });
                              onToast && onToast('Desacordo registado');
                              load();
                            } catch (e) { onToast && onToast(e.message, 'error'); }
                          }}>Não concordo</button>
                        </div>
                      )}
                      {r.revisto_at && <div style={{ fontSize: 11, color: 'var(--success, #22c55e)', marginTop: 4 }}>Revista · {r.quality_note || r.revisto_by || ''}</div>}
                    </div>
                  ))}
              </SdrCard>
              <SdrCard title="Qualidade e sinalizações">
                {(data.quality || []).length === 0
                  ? <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>Nenhuma avaliação ou flag.</div>
                  : (data.quality || []).map(q => (
                    <div key={q.id} style={{ padding: '8px 0', borderBottom: '1px solid var(--border)', fontSize: 12 }}>
                      <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8 }}>
                        <span style={{ fontWeight: 600 }}>{q.tipo_desvio ? flagTipoLabel(q.tipo_desvio) : q.evaluated_by}</span>
                        <span style={{ color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', fontSize: 10 }}>{sdrRelTime(q.created_at)}</span>
                      </div>
                      {q.flag_note && <div style={{ color: 'var(--text-muted)', marginTop: 4 }}>{q.flag_note}</div>}
                      {q.para_revisao && !q.revisto_at && (
                        <button type="button" className="btn btn-xs" style={{ marginTop: 6 }} disabled={busy} onClick={() => doUnflag(q.id)}>Marcar revisto</button>
                      )}
                      {q.revisto_at && <div style={{ fontSize: 11, color: 'var(--success, #22c55e)', marginTop: 4 }}>Revista · {q.revisto_by || ''}</div>}
                    </div>
                  ))}
              </SdrCard>
              <SdrCard title="Histórico de score">
                {(data.score_history || []).length === 0
                  ? <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>Sem alterações de score nesta sessão.</div>
                  : (data.score_history || []).map(h => (
                    <div key={h.id} style={{ fontSize: 12, padding: '4px 0', color: 'var(--text)' }}>
                      {h.score_ant ?? '—'} → {h.score_novo ?? '—'} <span style={{ color: 'var(--text-dim)' }}>· {sdrRelTime(h.created_at)}</span>
                    </div>
                  ))}
              </SdrCard>
            </div>
          </div>
        )}
      </div>
      <SdrFlagModal open={flagOpen} onClose={() => setFlagOpen(false)} onConfirm={doFlag} />
      <SdrConfirmModal
        open={!!confirm}
        title={confirm?.title}
        body={confirm?.body}
        confirmLabel={confirm?.confirmLabel}
        onClose={() => setConfirm(null)}
        onConfirm={async () => {
          const run = confirm?.run;
          setConfirm(null);
          if (!run) return;
          setBusy(true);
          try { await run(); }
          catch (e) { onToast && onToast(e.message, 'error'); }
          finally { setBusy(false); }
        }}
      />
    </div>
  );
};

const SdrLinha = ({ label, value }) => !value ? null : (
  <div style={{ padding: '8px 0', borderTop: '1px solid var(--border)' }}>
    <div style={{ fontSize: 11, color: 'var(--text-muted)', marginBottom: 2 }}>{label}</div>
    <div style={{ fontSize: 14, lineHeight: 1.5, color: 'var(--text)' }}>{value}</div>
  </div>
);

const SdrPasso = ({ passo }) => (
  <div style={{ display: 'flex', gap: 12, padding: '14px 0', borderBottom: '1px solid var(--border)' }}>
    <div style={{ width: 28, height: 28, borderRadius: 99, background: 'var(--ai-500)', color: '#fff', fontWeight: 700, fontSize: 13, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>{passo.ordem}</div>
    <div style={{ minWidth: 0 }}>
      <div style={{ fontWeight: 700, fontSize: 14, color: 'var(--text)' }}>{passo.titulo}</div>
      {Array.isArray(passo.dizer)
        ? <ul style={{ margin: '6px 0 0', paddingLeft: 18, fontSize: 14, lineHeight: 1.5, color: 'var(--text)' }}>{passo.dizer.map(d => <li key={d}>{d}</li>)}</ul>
        : passo.dizer && <div style={{ marginTop: 6, fontSize: 14, lineHeight: 1.55, color: 'var(--text)' }}>{passo.dizer}</div>}
      {Array.isArray(passo.perguntas) && (
        <ol style={{ margin: '6px 0 0', paddingLeft: 18, fontSize: 14, lineHeight: 1.5, color: 'var(--text)' }}>
          {passo.perguntas.map(q => <li key={q} style={{ marginBottom: 4 }}>{q}</li>)}
        </ol>
      )}
    </div>
  </div>
);

const SdrConsultaPainel = ({ consulta }) => {
  const [modo, setModo] = React.useState('playbook');
  const mercados = (modo === 'playbook' ? consulta?.playbook?.mercados : consulta?.ficha?.mercados) || [];
  const [mkt, setMkt] = React.useState(mercados[0]?.mercado || '');
  React.useEffect(() => {
    if (mercados[0] && !mercados.some(m => m.mercado === mkt)) setMkt(mercados[0].mercado);
  }, [consulta, modo]);
  if (!consulta) return <div style={{ fontSize: 13, color: 'var(--text-dim)' }}>Ficha ainda não gerada.</div>;
  const bloco = mercados.find(m => m.mercado === mkt) || mercados[0];
  const ficha = consulta.ficha || {};
  const camp = consulta.campanha || {};
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
        {[['playbook', 'Script'], ['ficha', 'Ficha']].map(([id, label]) => (
          <button type="button" key={id} className={modo === id ? 'btn btn-xs btn-ai' : 'btn btn-xs'} onClick={() => setModo(id)}>{label}</button>
        ))}
        {mercados.length > 1 && mercados.map(m => (
          <button type="button" key={m.mercado} className={mkt === m.mercado ? 'btn btn-xs btn-ai' : 'btn btn-xs'} onClick={() => setMkt(m.mercado)}>{m.mercado}</button>
        ))}
        <span style={{ marginLeft: 'auto', fontSize: 12, color: 'var(--text-muted)' }}>
          {[camp.produto, camp.mercados && camp.mercados.join(' · '), camp.vigencia?.inicio && camp.vigencia?.fim ? `${camp.vigencia.inicio} → ${camp.vigencia.fim}` : ''].filter(Boolean).join(' · ')}
        </span>
      </div>
      {modo === 'playbook' && bloco && (
        <SdrCard title={`Script · ${bloco.mercado}`}>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 4 }}>O que dizer, por esta ordem. A Digi AI usa a ficha completa.</div>
          {(bloco.passos || []).map(p => <SdrPasso key={p.ordem} passo={p} />)}
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 12 }}>
            {(bloco.regras || []).map(r => (
              <span key={r} style={{ fontSize: 12, padding: '4px 8px', borderRadius: 99, background: 'var(--bg-sunken)', color: 'var(--text)' }}>{r}</span>
            ))}
          </div>
        </SdrCard>
      )}
      {modo === 'ficha' && (
        <>
          <SdrCard title="O que é esta campanha">
            {ficha.pitch && <div style={{ fontSize: 15, lineHeight: 1.55, color: 'var(--text)' }}>{ficha.pitch}</div>}
            <SdrLinha label="Oferta" value={ficha.oferta} />
            <SdrLinha label="Pedido" value={ficha.pedido} />
            <SdrLinha label="Quem" value={ficha.quem} />
            <SdrLinha label="Quando compra" value={ficha.gatilho} />
            {(ficha.dores || []).length > 0 && (
              <div style={{ marginTop: 8 }}>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 4 }}>Dores</div>
                <ul style={{ margin: 0, paddingLeft: 18, fontSize: 13.5, lineHeight: 1.5 }}>{ficha.dores.map(d => <li key={d}>{d}</li>)}</ul>
              </div>
            )}
            {(ficha.nao_dizer || []).length > 0 && (
              <div style={{ marginTop: 10 }}>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 4 }}>Não dizer</div>
                <ul style={{ margin: 0, paddingLeft: 18, fontSize: 13.5, lineHeight: 1.5 }}>{ficha.nao_dizer.map(d => <li key={d}>{d}</li>)}</ul>
              </div>
            )}
          </SdrCard>
          {bloco && (
            <SdrCard title={`Como qualificar · ${bloco.mercado}`}>
              <SdrLinha label="Abertura" value={bloco.abertura} />
              {(bloco.perguntas || []).length > 0 && (
                <ol style={{ margin: '8px 0', paddingLeft: 18, fontSize: 13.5, lineHeight: 1.5 }}>{bloco.perguntas.map(q => <li key={q} style={{ marginBottom: 4 }}>{q}</li>)}</ol>
              )}
              {(bloco.argumentos || []).map(a => <div key={a} style={{ fontSize: 13.5, lineHeight: 1.5, padding: '4px 0' }}>{a}</div>)}
              <SdrLinha label="Objecção" value={bloco.objecao} />
              <SdrLinha label="Quando passar" value={bloco.passar_quando} />
              {(bloco.seguimento || []).length > 0 && (
                <div style={{ marginTop: 8 }}>
                  <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 4 }}>Se não fechar</div>
                  {bloco.seguimento.map(s => (
                    <div key={s.dizer || s.quando} style={{ fontSize: 13.5, lineHeight: 1.5, padding: '4px 0' }}>
                      {s.quando && <span style={{ color: 'var(--text-muted)' }}>{s.quando}. </span>}{s.dizer}
                    </div>
                  ))}
                </div>
              )}
            </SdrCard>
          )}
        </>
      )}
    </div>
  );
};

const SdrCampanhaView = ({ campanhaId, fallback, onBack, onOpenSession }) => {
  const [campanha, setCampanha] = React.useState(fallback || null);
  const [err, setErr] = React.useState('');
  const [ver, setVer] = React.useState(null);
  React.useEffect(() => {
    if (!campanhaId) return;
    SdrAPI.campanha(campanhaId)
      .then(d => setCampanha(prev => ({ ...(prev || {}), ...d })))
      .catch(e => setErr(e.message));
  }, [campanhaId]);
  if (!campanha) {
    return <div data-theme="light" style={SDR_THEME}><SdrEmpty title={err || 'A carregar campanha…'} /></div>;
  }
  const hist = ver ? (campanha.historico || []).find(h => h.version === ver) : null;
  return (
    <div data-theme="light" style={SDR_THEME}>
      <SdrHeader
        title={campanha.titulo || 'Campanha'}
        contextLine={[
          campanha.brand_name,
          campanha.activa_para_digi ? 'Ficha pronta' : null,
          campanha.meta_no_ar ? 'No ar na Meta' : (campanha.meta_no_ar === false ? 'Fora do ar' : null),
          campanha.campanha_teste ? 'Teste' : null,
          campanha.sdr_ai_activated_by,
          campanha.sdr_ai_activated_at && sdrRelTime(campanha.sdr_ai_activated_at),
        ].filter(Boolean).join(' · ')}
        back={onBack}
      />
      <div className="scrollbar sdr-pad" style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '24px 40px 48px', background: 'var(--bg)', display: 'flex', flexDirection: 'column', gap: 16 }}>
        <SdrKPIs items={[
          { id: 'sess', label: 'Sessões', value: campanha.n_sessoes || 0, accent: 'var(--ai-500)', fill: 1, noClick: true },
          { id: 'qual', label: 'Qualificadas', value: campanha.n_qualificados || 0, accent: 'var(--success, #22c55e)', fill: 1, noClick: true },
          { id: 'ads',  label: 'Ads mapeados', value: campanha.n_ads || 0, accent: 'var(--text-muted)', fill: 1, noClick: true },
          { id: 'ver',  label: 'Versão ficha', value: campanha.sdr_ficha_version || '—', accent: 'var(--text)', fill: 1, noClick: true },
        ]} />
        <div style={{ maxWidth: 860, display: 'flex', flexDirection: 'column', gap: 16 }}>
          <SdrConsultaPainel consulta={campanha.consulta} />
          <SdrCard title="Conversas desta campanha">
            {(campanha.conversas || []).length === 0
              ? <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>Ainda sem conversas ligadas a esta ficha.</div>
              : (campanha.conversas || []).map(c => (
                <button type="button" key={c.visitor_id} onClick={() => onOpenSession && onOpenSession(c.visitor_id)}
                  style={{ display: 'block', width: '100%', textAlign: 'left', background: 'none', border: 'none', borderBottom: '1px solid var(--border)', padding: '8px 0', cursor: 'pointer', color: 'var(--text)' }}>
                  <strong>{c.lead_name_wa || c.nome || c.lead_company_wa || c.empresa || sdrPhone(c.visitor_id)}</strong>
                  <span style={{ color: 'var(--text-muted)', marginLeft: 8 }}>{c.sdr_ficha_match_tipo || '—'} · {c.classification || '—'} · {sdrRelTime(c.updated_at)}</span>
                </button>
              ))}
          </SdrCard>
          {(campanha.historico || []).length > 0 && (
            <SdrCard title="Markdown da versão">
              <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                {(campanha.historico || []).map(h => (
                  <button type="button" key={h.version} className={ver === h.version ? 'btn btn-xs btn-ai' : 'btn btn-xs'} onClick={() => setVer(ver === h.version ? null : h.version)}>
                    v{h.version}{h.manual ? ' · manual' : ''}
                  </button>
                ))}
              </div>
              {hist?.md && (
                <pre style={{ margin: '12px 0 0', whiteSpace: 'pre-wrap', fontFamily: 'var(--font-body)', fontSize: 13, lineHeight: 1.65, color: 'var(--text)' }}>{hist.md}</pre>
              )}
            </SdrCard>
          )}
        </div>
      </div>
    </div>
  );
};

const SdrRelatorioView = ({ relatorio, onBack }) => {
  const [full, setFull] = React.useState(relatorio);
  React.useEffect(() => {
    if (!relatorio?.id || !SdrAPI.relatorio) return;
    SdrAPI.relatorio(relatorio.id).then(d => setFull(d.relatorio || d.row || d || relatorio)).catch(() => {});
  }, [relatorio?.id]);
  const rel = full || relatorio;
  return (
  <div data-theme="light" style={SDR_THEME}>
    <SdrHeader
      title={`Relatório ${sdrDate(rel.periodo_inicio)} – ${sdrDate(rel.periodo_fim)}`}
      contextLine={[rel.marca, rel.generated_by, rel.generated_at && sdrRelTime(rel.generated_at)].filter(Boolean).join(' · ')}
      back={onBack}
    />
    <div className="scrollbar" style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '24px 40px 48px', background: 'var(--bg)' }}>
      <SdrCard title="Resumo">
        <pre style={{ margin: 0, whiteSpace: 'pre-wrap', fontFamily: 'var(--font-body)', fontSize: 13.5, lineHeight: 1.65, color: 'var(--text)' }}>
          {rel.resumo_md || 'Sem resumo.'}
        </pre>
      </SdrCard>
    </div>
  </div>
  );
};

const SdrFrameworkView = ({ item, onBack, onOpenSession, onToast, onReload }) => {
  const exemplos = item.exemplos_session_ids || [];
  const busyRef = React.useRef(false);
  const [confirmStatus, setConfirmStatus] = React.useState(null);
  const patch = async (status) => {
    if (busyRef.current) return;
    busyRef.current = true;
    try {
      await SdrAPI.patchFramework(item.id, { status });
      onToast && onToast(status === 'incorporated' ? 'Incorporado' : 'Ignorado');
      onReload && onReload();
      onBack();
    } catch (e) {
      onToast && onToast(e.message, 'error');
    } finally { busyRef.current = false; }
  };
  return (
    <div data-theme="light" style={SDR_THEME}>
      <SdrHeader
        title={`${item.tipo_desvio ? flagTipoLabel(item.tipo_desvio) : 'Desvio'} · ${item.frame_target || 'frame'}`}
        contextLine={[item.regra_id, item.sp_target || 'SP', `${item.n_ocorrencias || 0} ocorrências`, FW_STATUS_LABEL[item.status] || item.status].filter(Boolean).join(' · ')}
        back={onBack}
        extra={(
          <div style={{ display: 'flex', gap: 6 }}>
            <button type="button" className="btn btn-ai" onClick={() => setConfirmStatus('incorporated')}>Incorporar</button>
            <button type="button" className="btn" onClick={() => setConfirmStatus('ignored')}>Ignorar</button>
          </div>
        )}
      />
      <div className="scrollbar" style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '24px 40px 48px', background: 'var(--bg)', display: 'flex', flexDirection: 'column', gap: 16 }}>
        <SdrCard title="Proposta">
          <pre style={{ margin: 0, whiteSpace: 'pre-wrap', fontFamily: 'var(--font-body)', fontSize: 13, lineHeight: 1.65, color: 'var(--text)' }}>
            {item.proposta_md || 'Sem proposta.'}
          </pre>
        </SdrCard>
        <SdrCard title="Correcções humanas">
          {!(item.exemplos_correcoes || []).length
            ? <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>Ainda sem respostas correctas associadas a esta regra.</div>
            : (item.exemplos_correcoes || []).map((ex, i) => (
              <div key={i} style={{ padding: '8px 0', borderBottom: '1px solid var(--border)', fontSize: 12 }}>
                <div style={{ color: 'var(--text-muted)' }}>{ex.session_id}{ex.msg_idx != null ? ` · msg ${ex.msg_idx}` : ''}</div>
                {ex.nota && <div style={{ marginTop: 4 }}>{ex.nota}</div>}
                {ex.resposta_correcta && <pre style={{ whiteSpace: 'pre-wrap', margin: '6px 0 0', fontFamily: 'inherit' }}>{ex.resposta_correcta}</pre>}
              </div>
            ))}
        </SdrCard>
        <SdrCard title="Sessões exemplo">
          {exemplos.length === 0
            ? <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>Sem exemplos.</div>
            : exemplos.map(id => (
              <button key={id} type="button" className="btn btn-xs" style={{ margin: '0 6px 6px 0' }}
                onClick={() => onOpenSession && onOpenSession(id)}>{id}</button>
            ))}
        </SdrCard>
      </div>
      <SdrConfirmModal
        open={!!confirmStatus}
        title={confirmStatus === 'incorporated' ? 'Incorporar proposta' : 'Ignorar proposta'}
        body={confirmStatus === 'incorporated'
          ? 'Marcar esta proposta como incorporada no framework? Só o strategist pode confirmar.'
          : 'Ignorar esta proposta de alteração?'}
        confirmLabel={confirmStatus === 'incorporated' ? 'Incorporar' : 'Ignorar'}
        onClose={() => setConfirmStatus(null)}
        onConfirm={() => { const st = confirmStatus; setConfirmStatus(null); if (st) patch(st); }}
      />
    </div>
  );
};

const SdrVersaoView = ({ fileName, data, onBack }) => (
  <div data-theme="light" style={SDR_THEME}>
    <SdrHeader title={fileName} contextLine="Impacto por versão" back={onBack} />
    <div className="scrollbar" style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '24px 40px 48px', background: 'var(--bg)' }}>
      {!(data?.versions || []).length
        ? <SdrEmpty title="Sem histórico de versões para este ficheiro." />
        : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {(data.versions || []).map((v, i) => (
              <SdrCard key={v.container_boot_id || i} title={`${(v.file_sha256 || '').slice(0, 7)} · ${sdrRelTime(v.loaded_at)}`}>
                <SdrKV label="Container" value={v.container} />
                <SdrKV label="Runs" value={v.n_runs} />
                <SdrKV label="Score médio" value={v.avg_score} />
                <SdrKV label="Qualificação" value={v.taxa_qualificacao != null ? `${v.taxa_qualificacao}%` : '—'} />
                <SdrKV label="Desvios" value={v.n_desvios} />
              </SdrCard>
            ))}
          </div>
        )}
    </div>
  </div>
);

const MktSdrScreen = () => {
  const [tab, setTab] = React.useState('overview');
  const [view, setView] = React.useState('list');
  const [sessionId, setSessionId] = React.useState(null);
  const [campanha, setCampanha] = React.useState(null);
  const [relatorio, setRelatorio] = React.useState(null);
  const [fwItem, setFwItem] = React.useState(null);
  const [versaoFile, setVersaoFile] = React.useState(null);
  const [versaoData, setVersaoData] = React.useState(null);

  const [publico, _setPublico]         = React.useState(() => sdrSsGet('publico', 'todas'));
  const [ambiente, _setAmbiente]       = React.useState(() => sdrSsGet('ambiente', 'ambos'));
  const [filterMarca, _setFilterMarca] = React.useState(() => sdrSsGet('marca', 'all'));
  const [periodo, _setPeriodo]         = React.useState(() => sdrSsGet('periodo', 'all'));
  const [classif, _setClassif]         = React.useState(() => sdrSsGet('classif', 'all'));
  const [sdrStatus, _setSdrStatus]     = React.useState(() => sdrSsGet('sdr_status', 'all'));
  const [campaignQ, setCampaignQ]      = React.useState('');
  const [q, setQ]                      = React.useState('');
  const [qDeb, setQDeb]                = React.useState('');
  const [paraRevisao, setParaRevisao]  = React.useState(false);
  const [kpiFilter, setKpiFilter]      = React.useState(null);
  const [soCriticas, setSoCriticas]    = React.useState(false);
  const [campanhaId, setCampanhaId]    = React.useState('all');
  const [maisFiltros, setMaisFiltros]  = React.useState(false);
  const [promptSec, setPromptSec]      = React.useState('versoes');
  const [regraFila, setRegraFila]      = React.useState('');
  const [incluirTestes, _setIncluirTestes] = React.useState(() => sdrSsGet('testes', '0') === '1');
  const [spFiltro, setSpFiltro]        = React.useState('');
  const [comErro, setComErro]          = React.useState(false);
  const [emFalta, setEmFalta]          = React.useState('');
  const [confMax, setConfMax]          = React.useState('');
  const [canal, _setCanal]             = React.useState(() => sdrSsGet('canal', 'all'));

  const setPublico = v => { _setPublico(v); sdrSsSet('publico', v); setSpFiltro(''); };
  const setAmbiente = v => { _setAmbiente(v); sdrSsSet('ambiente', v); };
  const setFilterMarca = v => { _setFilterMarca(v); sdrSsSet('marca', v); };
  const setPeriodo     = v => { _setPeriodo(v); sdrSsSet('periodo', v); };
  const setClassif     = v => { _setClassif(v); sdrSsSet('classif', v); };
  const setSdrStatus   = v => { _setSdrStatus(v); sdrSsSet('sdr_status', v); };
  const setIncluirTestes = v => { _setIncluirTestes(v); sdrSsSet('testes', v ? '1' : '0'); };
  const setCanal       = v => { _setCanal(v); sdrSsSet('canal', v); };

  const [allBrands, setAllBrands] = React.useState([]);
  const [dash, setDash] = React.useState(null);
  const [painel, setPainel] = React.useState(null);
  const [overview, setOverview] = React.useState(null);
  const [fila, setFila] = React.useState(null);
  const [cobertura, setCobertura] = React.useState(null);
  const [rows, setRows] = React.useState(null);
  const [total, setTotal] = React.useState(0);
  const [offset, setOffset] = React.useState(0);
  const [camps, setCamps] = React.useState(null);
  const [nSemMapa, setNSemMapa] = React.useState(0);
  const [health, setHealth] = React.useState(null);
  const [rels, setRels] = React.useState(null);
  const [fws, setFws] = React.useState(null);
  const [err, setErr] = React.useState('');
  window.useMktZoneLoading(overview == null && !err);
  const [toast, setToast] = React.useState(null);
  const [toastType, setToastType] = React.useState('ok');
  const [selectedIds, setSelectedIds] = React.useState(new Set());
  const [flagOpen, setFlagOpen] = React.useState(false);
  const [markExpectedOpen, setMarkExpectedOpen] = React.useState(false);
  const [internas, setInternas] = React.useState(null);
  const [dirInterna, setDirInterna] = React.useState('todas');
  const [depInterno, setDepInterno] = React.useState('todos');
  const [qInterna, setQInterna] = React.useState('');

  const showToast = (msg, type = 'ok') => {
    setToast(msg); setToastType(type);
    setTimeout(() => setToast(null), 3200);
  };

  React.useEffect(() => {
    const t = setTimeout(() => setQDeb(q), 300);
    return () => clearTimeout(t);
  }, [q]);

  React.useEffect(() => {
    SdrAPI.brands()
      .then(d => {
        const list = (Array.isArray(d) ? d : []).filter(b => b.active !== false && b.slug !== 'todas' && b.slug !== 'all');
        list.sort((a, b) => {
          const ia = SDR_BRAND_ORDER.indexOf(a.slug), ib = SDR_BRAND_ORDER.indexOf(b.slug);
          return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib);
        });
        setAllBrands(list);
      })
      .catch(() => {});
  }, []);

  const marcaParam = filterMarca === 'all' ? '' : `&marca=${encodeURIComponent(filterMarca)}`;
  const canalParam = canal === 'all' ? '' : `&origin_channel=${encodeURIComponent(canal)}`;
  const testesParam = incluirTestes ? '&incluir_testes=1' : '';
  const spParam = spFiltro ? `&sp=${encodeURIComponent(spFiltro)}` : '';
  const qsBase = `periodo=${encodeURIComponent(periodo)}&publico=${encodeURIComponent(publico || 'todas')}&ambiente=${encodeURIComponent(ambiente || 'producao')}${spParam}${marcaParam}${canalParam}${testesParam}`;

  const loadDash = React.useCallback(() => {
    SdrAPI.dashboard(qsBase)
      .then(setDash)
      .catch(e => { setDash({}); setErr(e.message); });
    SdrAPI.painel(qsBase)
      .then(setPainel)
      .catch(e => { setPainel({}); setErr(e.message); });
    SdrAPI.overview(qsBase)
      .then(setOverview)
      .catch(e => { setOverview({}); setErr(e.message); });
  }, [qsBase]);

  const conversasFilterQs = React.useMemo(() => {
    const params = [qsBase];
    if (classif !== 'all') params.push(`classification=${encodeURIComponent(classif)}`);
    if (sdrStatus !== 'all') params.push(`sdr_status=${encodeURIComponent(sdrStatus)}`);
    if (qDeb.trim()) params.push(`q=${encodeURIComponent(qDeb.trim())}`);
    if (paraRevisao) params.push('para_revisao=1');
    if (soCriticas) params.push('so_criticas=1');
    if (campanhaId && campanhaId !== 'all') params.push(`campanha_id=${encodeURIComponent(campanhaId)}`);
    if (comErro) params.push('com_erro=1');
    if (emFalta) params.push(`em_falta=${encodeURIComponent(emFalta)}`);
    if (confMax !== '' && Number.isFinite(Number(confMax))) params.push(`conformidade_max=${encodeURIComponent(confMax)}`);
    if (kpiFilter === 'demo') params.push('aceita_demo=1');
    if (kpiFilter === 'qual') params.push('qualificados=1');
    return params.join('&');
  }, [qsBase, classif, sdrStatus, qDeb, paraRevisao, kpiFilter, soCriticas, campanhaId, comErro, emFalta, confMax]);

  const convSeq = React.useRef(0);
  const loadConversas = React.useCallback(() => {
    const seq = ++convSeq.current;
    const append = offset > 0;
    if (!append) setRows(null);
    const qs = `${conversasFilterQs}&offset=${offset}&limit=50`;
    SdrAPI.conversas(qs)
      .then(d => {
        if (seq !== convSeq.current) return;
        const next = d.rows || [];
        setRows(prev => {
          if (!append || !prev) return next;
          const ids = new Set(next.map(r => r.visitor_id));
          return [...prev.filter(r => !ids.has(r.visitor_id)), ...next];
        });
        setTotal(d.total || 0);
      })
      .catch(e => {
        if (seq !== convSeq.current) return;
        if (!append) setRows([]);
        setErr(e.message);
      });
  }, [conversasFilterQs, offset]);

  const loadCamps = React.useCallback(() => {
    SdrAPI.campanhas(qsBase)
      .then(d => { setCamps(d.rows || d || []); setNSemMapa(d.n_sem_mapa || 0); })
      .catch(e => { setCamps([]); setErr(e.message); });
    SdrAPI.cobertura(qsBase).then(setCobertura).catch(() => setCobertura(null));
  }, [qsBase]);

  const loadFila = React.useCallback(() => {
    const qs = regraFila ? `${qsBase}&regra_id=${encodeURIComponent(regraFila)}` : qsBase;
    SdrAPI.fila(qs)
      .then(d => setFila(d.rows || []))
      .catch(e => { setFila([]); setErr(e.message); });
  }, [qsBase, regraFila]);

  const loadHealth = React.useCallback(() => {
    SdrAPI.health()
      .then(setHealth)
      .catch(e => { setHealth({ matrix: [], containers: [], files: [] }); setErr(e.message); });
  }, []);

  const loadRels = React.useCallback(() => {
    SdrAPI.relatorios()
      .then(d => setRels(d.rows || []))
      .catch(e => { setRels([]); setErr(e.message); });
  }, []);

  const loadFws = React.useCallback(() => {
    SdrAPI.frameworks()
      .then(d => setFws(d.rows || []))
      .catch(e => { setFws([]); setErr(e.message); });
  }, []);

  React.useEffect(() => { loadDash(); }, [loadDash]);
  React.useEffect(() => { if (tab === 'conversas') loadConversas(); }, [tab, loadConversas]);
  React.useEffect(() => { if (tab === 'fila') loadFila(); }, [tab, loadFila]);
  React.useEffect(() => { if (tab === 'campanhas' || tab === 'conversas') loadCamps(); }, [tab, loadCamps]);
  React.useEffect(() => {
    if (tab !== 'prompts') return;
    loadHealth(); loadRels(); loadFws();
  }, [tab, loadHealth, loadRels, loadFws]);
  React.useEffect(() => {
    try {
      const qh = new URLSearchParams(window.location.hash.replace(/^#/, ''));
      if (qh.get('view') === 'conversa' && qh.get('id')) {
        setSessionId(qh.get('id'));
        setView('conversa');
      }
    } catch {}
  }, []);
  React.useEffect(() => {
    const p = new URLSearchParams();
    const email = window.currentUser?.email || '';
    if (email) p.set('email', email);
    p.set('periodo', 'tudo');
    fetch('/api/marketing/crm/leads/internas?' + p.toString())
      .then(r => r.status === 403 ? null : r.json())
      .then(d => { if (d && !d.error) setInternas(d); else setInternas({ conversas: [], direccoes: [], total: 0, negado: true }); })
      .catch(() => setInternas({ conversas: [], direccoes: [], total: 0 }));
  }, []);
  React.useEffect(() => { setOffset(0); }, [conversasFilterQs]);

  const loadAll = () => {
    loadDash();
    if (tab === 'conversas') loadConversas();
    if (tab === 'fila') loadFila();
    if (tab === 'campanhas') loadCamps();
    if (tab === 'prompts') { loadHealth(); loadRels(); loadFws(); }
  };

  React.useEffect(() => {
    const handler = (e) => {
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.tagName === 'SELECT') return;
      if (e.key === 'Escape') {
        setFlagOpen(false); setMarkExpectedOpen(false);
        setView('list'); setSessionId(null); setCampanha(null);
        setRelatorio(null); setFwItem(null); setVersaoFile(null); setVersaoData(null);
      }
      if (e.key === '/' && !e.ctrlKey) { e.preventDefault(); document.getElementById('sdr-search')?.focus(); }
      if ((e.ctrlKey || e.metaKey) && e.key === 'r') { e.preventDefault(); loadAll(); }
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  });

  const k = dash?.kpis || {};
  const totalConv = parseInt(k.total_conversas || 0);
  const nQual = parseInt(k.qualificados || 0);
  const pctQual = totalConv > 0 ? Math.round(nQual / totalConv * 100) : 0;
  const brandLabel = filterMarca !== 'all' && allBrands.find(b => b.slug === filterMarca)
    ? allBrands.find(b => b.slug === filterMarca).name
    : 'todas as marcas';

  const kpiItems = [
    { id: 'all',    label: 'Conversas',      value: totalConv,                         accent: 'var(--text)',             fill: 1, noClick: true },
    { id: 'qual',   label: 'Qualificadas',   value: nQual,                             accent: 'var(--success, #22c55e)', fill: totalConv ? nQual / totalConv : 0, sub: totalConv ? `${pctQual}%` : '' },
    { id: 'demo',   label: 'Aceitam demo',   value: parseInt(k.aceita_demo || 0),      accent: 'var(--ai-500)',           fill: totalConv ? (k.aceita_demo || 0) / totalConv : 0 },
    { id: 'review', label: 'Para revisão',   value: parseInt(k.n_para_revisao || 0),   accent: 'var(--warning, #d97706)', fill: totalConv ? (k.n_para_revisao || 0) / Math.max(totalConv, 1) : 0 },
    { id: 'cost',   label: 'Custo / qualif.', value: nQual && k.custo_por_qualificado ? `$${Number(k.custo_por_qualificado).toFixed(2)}` : (k.custo_total ? `$${Number(k.custo_total).toFixed(2)}` : '—'), accent: 'var(--text-muted)', fill: 1, noClick: true, sub: k.custo_total ? `total $${Number(k.custo_total).toFixed(3)}` : 'sem agent_runs' },
  ];

  const onKpiFilter = (id) => {
    if (kpiFilter === 'hot' && id !== 'hot' && classif === 'HOT') setClassif('all');
    setParaRevisao(id === 'review');
    setKpiFilter(id || null);
    if (id === 'hot') setClassif('HOT');
    if (id) setTab('conversas');
  };

  const onBannerGo = (go) => {
    if (go === 'health') { setTab('health'); return; }
    onKpiFilter(go);
  };

  const hasFilter = classif !== 'all' || sdrStatus !== 'all' || q.trim() || paraRevisao || kpiFilter || canal !== 'all' || incluirTestes || soCriticas || (campanhaId && campanhaId !== 'all') || comErro || emFalta || confMax !== '';
  const clearFilters = () => {
    setClassif('all'); setSdrStatus('all'); setCampaignQ(''); setQ(''); setParaRevisao(false); setKpiFilter(null); setCanal('all'); setIncluirTestes(false); setSoCriticas(false); setCampanhaId('all'); setComErro(false); setEmFalta(''); setConfMax('');
  };
  const onAlerta = (a) => {
    if (!a) return;
    if (a.destino === 'fila') { setTab('fila'); return; }
    if (a.destino === 'campanhas') { setTab('campanhas'); return; }
    if (a.destino === 'prompts') { setTab('prompts'); return; }
    if (a.filtro === 'com_erro') setComErro(true);
    setTab('conversas');
  };

  const handleToggle = (id) => setSelectedIds(prev => {
    const next = new Set(prev);
    next.has(id) ? next.delete(id) : next.add(id);
    return next;
  });
  const handleToggleAll = (checked) => {
    if (checked) setSelectedIds(new Set((rows || []).map(r => r.visitor_id)));
    else setSelectedIds(new Set());
  };
  const someSelected = selectedIds.size > 0;
  const allSelected = (rows || []).length > 0 && (rows || []).every(r => selectedIds.has(r.visitor_id));

  const bulkFlag = async (payload) => {
    try {
      await Promise.all([...selectedIds].map(id => SdrAPI.flag(id, payload)));
      setFlagOpen(false);
      setSelectedIds(new Set());
      showToast(`${selectedIds.size} sinalizada(s)`);
      loadConversas(); loadDash();
    } catch (e) { showToast(e.message, 'error'); }
  };

  if (view === 'conversa' && sessionId) {
    return (
      <SdrConversaView
        sessionId={sessionId}
        onBack={() => { setView('list'); setSessionId(null); loadAll(); }}
        onToast={showToast}
      />
    );
  }
  if (view === 'campanha' && campanha) {
    return (
      <SdrCampanhaView
        campanhaId={campanha.id}
        fallback={campanha}
        onBack={() => { setView('list'); setCampanha(null); loadCamps(); }}
        onOpenSession={(id) => { setCampanha(null); setSessionId(id); setView('conversa'); }}
      />
    );
  }
  if (view === 'relatorio' && relatorio) {
    return <SdrRelatorioView relatorio={relatorio} onBack={() => { setView('list'); setRelatorio(null); loadRels(); }} />;
  }
  if (view === 'framework' && fwItem) {
    return (
      <SdrFrameworkView
        item={fwItem}
        onBack={() => { setView('list'); setFwItem(null); loadFws(); }}
        onOpenSession={(id) => { setFwItem(null); setSessionId(id); setView('conversa'); }}
        onToast={showToast}
        onReload={loadFws}
      />
    );
  }
  if (view === 'versao' && versaoFile) {
    return <SdrVersaoView fileName={versaoFile} data={versaoData} onBack={() => { setView('list'); setVersaoFile(null); setVersaoData(null); }} />;
  }

  const listaConversas = (() => {
    if (!rows || publico !== 'colaboradores' || (dirInterna === 'todas' && depInterno === 'todos')) return rows;
    const ok = new Set((internas?.conversas || [])
      .filter(c => (dirInterna === 'todas' || c.direccao === dirInterna) && (depInterno === 'todos' || c.departamento === depInterno))
      .map(c => c.visitor_id));
    return rows.filter(r => ok.has(r.visitor_id));
  })();
  const dist = dash?.distribuicoes || {};
  const sps  = dash?.por_sp || [];
  const matrix = health?.matrix || [];
  const files = health?.files || [...new Set(matrix.map(m => m.file_name))];
  const containers = health?.containers || [...new Set(matrix.map(m => m.container))];
  const nDiv = matrix.filter(m => m.matches_expected === false).length + (health?.prod_staging_diff || []).length;
  const nStale = matrix.filter(m => m.stale).length;

  return (
    <div data-theme="light" style={SDR_THEME}>
      <style>{`
        @media (max-width: 1100px) {
          .sdr-pad { padding-left: 24px !important; padding-right: 24px !important; }
        }
        .sdr-row:hover { background: var(--bg-hover); }
        .sdr-row-sel { background: color-mix(in oklch, var(--ai-500) 5%, transparent); }
      `}</style>
      <SdrHeader
        title="Monitorização da Digi AI"
        contextLine={`${(SDR_PERIODS.find(p => p.id === periodo) || {}).label || periodo} · actualizado ${painel?.gerado_em ? sdrRelTime(painel.gerado_em) : '—'} · ${(painel?.wa_numeros || []).map(w => `${w.ambiente === 'producao' ? 'Produção' : 'Staging'} ${w.numero}`).join(' · ') || brandLabel}`}
        tab={tab}
        setTab={(t) => { setTab(t); setView('list'); }}
        filters={(
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', padding: '12px 0 4px' }}>
            <SdrDateRangePicker value={periodo} onChange={setPeriodo} />
            <SdrDropdown label="Ambiente" value={ambiente} onChange={setAmbiente}
              options={SDR_AMBIENTES.map(a => ({ value: a.id, label: a.label }))} />
            <SdrDropdown label="Público" value={spFiltro || publico} onChange={(v) => { if (String(v).startsWith('SP_')) setSpFiltro(v); else setPublico(v); }}
              options={SDR_PUBLICOS.map(p => ({ value: p.id, label: p.label })).concat(spFiltro ? [{ value: spFiltro, label: spFiltro }] : [])} />
            <SdrDropdown label="Marca" value={filterMarca} onChange={setFilterMarca}
              options={[{ value: 'all', label: 'Todas' }, ...allBrands.map(b => ({ value: b.slug, label: b.name }))]} />
          </div>
        )}
      />

      <div className="scrollbar sdr-pad" style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '28px 40px 48px', background: 'var(--bg)', display: 'flex', flexDirection: 'column', gap: 18 }}>
        {err && <div style={{ color: 'var(--danger)', fontSize: 12 }}>{err}</div>}

        {tab === 'overview' && (
          <SdrVisaoGeral
            painel={painel}
            onSp={(nome) => { setSpFiltro(nome); }}
            onCampo={(id) => { setEmFalta(id); setPublico('clientes'); setTab('conversas'); }}
            onAlerta={onAlerta}
          />
        )}

        {tab === 'fila' && (
          <>
            {fila === null ? (
              <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-muted)' }}>A carregar…</div>
            ) : fila.length === 0 ? (
              <SdrEmpty title="A fila de revisão está vazia." hint={regraFila ? `Nada para ${regraFila}.` : 'Entram aqui conversas com falha crítica ou conformidade abaixo de 70%.'} onRetry={loadFila} />
            ) : fila.map(r => (
              <button type="button" key={r.visitor_id} onClick={() => { setSessionId(r.visitor_id); setView('conversa'); }}
                style={{ textAlign: 'left', background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 8, padding: 14, cursor: 'pointer' }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8 }}>
                  <strong>{r.lead_name_wa || r.lead_company_wa || sdrPhone(r.visitor_id)}</strong>
                  <span style={{ color: (r.n_falhas_criticas || 0) > 0 ? 'var(--danger, #ef4444)' : 'var(--warning, #d97706)', fontWeight: 700 }}>
                    {(r.n_falhas_criticas || 0) > 0 ? 'Crítico' : 'Alto'} · {r.score_global ?? '—'}
                  </span>
                </div>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4, display: 'flex', gap: 6, alignItems: 'center', flexWrap: 'wrap' }}>
                  <SdrAmbBadge value={r.ambiente} />
                  <span>{(r.marca || '').toUpperCase()} · {r.campanha_titulo || r.campaign_name || 'sem campanha'} · {r.ficha_match_tipo || '—'} · {sdrRelTime(r.updated_at)}</span>
                </div>
                <div style={{ fontSize: 12, marginTop: 6 }}>
                  {(Array.isArray(r.falhas) ? r.falhas : []).slice(0, 3).map(f => f.regra_id).join(' · ')}
                </div>
              </button>
            ))}
            {regraFila && <button type="button" className="btn btn-xs" onClick={() => setRegraFila('')}>Limpar filtro {regraFila}</button>}
          </>
        )}

        {tab === 'conversas' && (
          <>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 8 }}>
              <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
                <SdrDropdown label="Classificação" value={classif} onChange={setClassif}
                  options={[{ value: 'all', label: 'Todas' }, ...Object.keys(CLASSIF_CFG).map(v => ({ value: v, label: CLASSIF_CFG[v].label }))]} />
                <SdrDropdown label="Estado CRM" value={sdrStatus} onChange={setSdrStatus}
                  options={[{ value: 'all', label: 'Todos' }, ...Object.keys(SDR_STATUS_CFG).map(v => ({ value: v, label: SDR_STATUS_CFG[v].label }))]} />
                <SdrDropdown label="Campanha" value={campanhaId} onChange={setCampanhaId}
                  options={[{ value: 'all', label: 'Todas' }, ...(camps || []).map(c => ({ value: c.id, label: c.titulo || c.id }))]} />
                <input id="sdr-search" value={q} onChange={e => setQ(e.target.value)} placeholder="Pesquisar nome, empresa, telefone…"
                  style={{ padding: '6px 10px', borderRadius: 6, border: '1px solid var(--border)', fontSize: 12, minWidth: 220, background: 'var(--bg-elev)', color: 'var(--text)', fontFamily: 'inherit' }} />
                <label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12, color: 'var(--text-muted)', cursor: 'pointer' }}>
                  <input type="checkbox" checked={paraRevisao} onChange={e => {
                    setParaRevisao(e.target.checked);
                    if (!e.target.checked && kpiFilter === 'review') setKpiFilter(null);
                  }} />
                  Só sinalizadas
                </label>
                <label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12, color: 'var(--text-muted)', cursor: 'pointer' }}>
                  <input type="checkbox" checked={soCriticas} onChange={e => setSoCriticas(e.target.checked)} />
                  Só críticas
                </label>
                <label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12, color: 'var(--text-muted)', cursor: 'pointer' }}>
                  <input type="checkbox" checked={comErro} onChange={e => setComErro(e.target.checked)} />
                  Com erro
                </label>
                <SdrDropdown label="Campo em falta" value={emFalta || 'all'} onChange={v => setEmFalta(v === 'all' ? '' : v)}
                  options={[{ value: 'all', label: 'Todos' }, ...Object.keys(SDR_CAMPOS_FALTA).map(id => ({ value: id, label: SDR_CAMPOS_FALTA[id] }))]} />
                <button type="button" className="btn btn-xs" aria-expanded={maisFiltros} onClick={() => setMaisFiltros(v => !v)}>Mais filtros</button>
                {hasFilter && (
                  <button type="button" onClick={clearFilters} style={{ background: 'none', border: 'none', color: 'var(--text-muted)', fontSize: 11, cursor: 'pointer', padding: '4px 6px', fontFamily: 'var(--font-mono)' }}>✕ limpar</button>
                )}
                <span style={{ fontSize: 12, color: 'var(--text-muted)', paddingLeft: 4 }}>{total} resultado{total !== 1 ? 's' : ''}</span>
                {maisFiltros && (
                  <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', width: '100%', alignItems: 'center' }}>
                    <SdrDropdown label="Canal" value={canal} onChange={setCanal}
                      options={[{ value: 'all', label: 'Todos' }, { value: 'wa_direct', label: 'WhatsApp' }, { value: '(sem)', label: 'Sem canal' }]} />
                    <label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12, color: 'var(--text-muted)' }}>
                      Conformidade máx.
                      <input value={confMax} onChange={e => setConfMax(e.target.value.replace(/[^\d.]/g, ''))} inputMode="decimal" placeholder="70"
                        style={{ width: 64, padding: '6px 8px', borderRadius: 6, border: '1px solid var(--border)', fontSize: 12, background: 'var(--bg-elev)', color: 'var(--text)' }} />
                    </label>
                    <label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12, color: 'var(--text-muted)', cursor: 'pointer' }}>
                      <input type="checkbox" checked={incluirTestes} onChange={e => setIncluirTestes(e.target.checked)} />
                      Incluir testes
                    </label>
                  </div>
                )}
              </div>
              <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
                {['csv', 'xlsx'].map(fmt => (
                  <button key={fmt} type="button" className="btn btn-xs" onClick={() => {
                    window.location.href = `/api/marketing/sdr/export?formato=${fmt}&${conversasFilterQs}`;
                  }}>{fmt.toUpperCase()}</button>
                ))}
                <SdrDateRangePicker value={periodo} onChange={setPeriodo} />
              </div>
            </div>
            {publico === 'colaboradores' && (internas?.direccoes || []).length > 0 && (
              <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
                <SdrDropdown label="Direcção" value={dirInterna} onChange={v => { setDirInterna(v); setDepInterno('todos'); }}
                  options={[{ value: 'todas', label: 'Todas' }, ...(internas?.direccoes || []).map(d => ({ value: d.direccao, label: `${d.direccao} (${d.n})` }))]} />
                <SdrDropdown label="Departamento" value={depInterno} onChange={setDepInterno}
                  options={[{ value: 'todos', label: 'Todos' }, ...((dirInterna === 'todas' ? (internas?.direccoes || []).flatMap(d => d.departamentos || []) : ((internas?.direccoes || []).find(d => d.direccao === dirInterna)?.departamentos || []))).map(d => ({ value: d.departamento, label: `${d.departamento} (${d.n})` }))]} />
              </div>
            )}
            {someSelected && (
              <div style={{
                display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 8,
                padding: '8px 12px', borderRadius: 8,
                background: 'color-mix(in oklch, var(--ai-500) 6%, var(--bg-elev))',
                border: '1px solid color-mix(in oklch, var(--ai-500) 20%, var(--border))',
              }}>
                <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
                  <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--ai-500)', fontFamily: 'var(--font-mono)', letterSpacing: '0.04em' }}>
                    {selectedIds.size} seleccionad{selectedIds.size !== 1 ? 'as' : 'a'}
                  </span>
                  <button type="button" className="btn btn-xs btn-ai" onClick={() => setFlagOpen(true)}>Sinalizar seleccionadas</button>
                </div>
                <button type="button" onClick={() => setSelectedIds(new Set())} style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: 11, color: 'var(--text-muted)', fontFamily: 'var(--font-mono)' }}>✕ cancelar</button>
              </div>
            )}

            {rows === null ? (
              <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>A carregar…</div>
            ) : (listaConversas || []).length === 0 ? (
              <SdrEmpty title="Nenhuma conversa com estes filtros." hint="Alarga o período ou limpa os filtros." onRetry={loadConversas} />
            ) : (
              <div style={{ overflowX: 'auto', width: '100%' }}>
                <table style={{ width: '100%', minWidth: 1280, borderCollapse: 'collapse', fontSize: 12.5 }}>
                  <thead style={{ position: 'sticky', top: 0, zIndex: 2, background: 'var(--bg-elev)' }}>
                    <tr style={{ borderBottom: '1px solid var(--border)' }}>
                      <th style={{ ...thSt, textAlign: 'center' }}>
                        <input type="checkbox" checked={allSelected} onChange={e => handleToggleAll(e.target.checked)}
                          style={{ width: 14, height: 14, cursor: 'pointer', accentColor: 'var(--ai-500)' }} />
                      </th>
                      {['Lead', 'Ambiente', 'SP', 'Score', 'Classificação', 'Qualidade', 'Ficha', 'Canal', 'País', 'Msgs', 'Última', 'Custo', 'Erros'].map(h => <th key={h} style={thSt}>{h}</th>)}
                    </tr>
                  </thead>
                  <tbody>
                    {(listaConversas || []).map(r => (
                      <tr key={r.visitor_id}
                        onClick={() => { setSessionId(r.visitor_id); setView('conversa'); }}
                        className={selectedIds.has(r.visitor_id) ? 'sdr-row sdr-row-sel' : 'sdr-row'}
                        style={{ borderBottom: '1px solid var(--border)', cursor: 'pointer' }}>
                        <td style={{ padding: '4px 4px', textAlign: 'center' }} onClick={e => { e.stopPropagation(); handleToggle(r.visitor_id); }}>
                          <input type="checkbox" checked={selectedIds.has(r.visitor_id)} onChange={() => handleToggle(r.visitor_id)}
                            style={{ width: 14, height: 14, cursor: 'pointer', accentColor: 'var(--ai-500)' }} />
                        </td>
                        <td style={tdSt}>
                          <div style={{ fontWeight: 500, color: 'var(--text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: 180 }}>
                            {r.lead_name_wa || r.nome || r.lead_company_wa || r.empresa || sdrPhone(r.visitor_id)}
                          </div>
                          {r.colisao ? <div style={{ fontSize: 10, color: 'var(--warning, #d97706)' }}>Pode conter mensagens de staging anteriores à separação</div> : null}
                        </td>
                        <td style={tdSt}><SdrAmbBadge value={r.ambiente} /></td>
                        <td style={{ ...tdSt, fontSize: 11 }}>{r.sp_name || '—'}{r.sp_origem === 'inferido' ? ' · histórico' : ''}</td>
                        <td style={{ ...tdSt, fontFamily: 'var(--font-mono)' }}>{r.lead_score ?? '—'}</td>
                        <td style={tdSt}><SdrStatusBadge kind="classif" value={r.classification} /></td>
                        <td style={{ ...tdSt, fontFamily: 'var(--font-mono)' }}>{r.qualidade_score ?? '—'}</td>
                        <td style={{ ...tdSt, fontSize: 11 }}>{r.ficha_match_tipo || '—'}</td>
                        <td style={{ ...tdSt, fontSize: 11 }}>{r.origin_channel || '—'}</td>
                        <td style={{ ...tdSt, fontSize: 11 }}>{[r.origin_country, r.origin_language].filter(Boolean).join(' · ') || '—'}</td>
                        <td style={{ ...tdSt, fontFamily: 'var(--font-mono)' }}>{r.n_msgs_lead ?? r.n_msgs ?? '—'}</td>
                        <td style={{ ...tdSt, color: 'var(--text-muted)' }}>{sdrRelTime(r.last_user_at || r.updated_at)}</td>
                        <td style={{ ...tdSt, fontFamily: 'var(--font-mono)' }}>{r.custo != null ? sdrUsd(r.custo) : '—'}</td>
                        <td style={{ ...tdSt, fontFamily: 'var(--font-mono)', color: r.n_erros > 0 ? 'var(--danger, #ef4444)' : 'inherit' }}>{r.n_erros || 0}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
            {rows && rows.length > 0 && rows.length < total && (
              <div style={{ textAlign: 'center' }}>
                <button type="button" className="btn btn-sm" onClick={() => setOffset(rows.length)}>Mais 50 · {rows.length} de {total}</button>
              </div>
            )}
          </>
        )}

        {tab === 'campanhas' && (
          <>
            <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
              <SdrDateRangePicker value={periodo} onChange={setPeriodo} />
            </div>
            {camps === null ? (
              <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>A carregar…</div>
            ) : camps.length === 0 ? (
              <SdrEmpty title="Nenhuma campanha com SDR AI activado." hint="Activa o SDR AI numa campanha (Funil) para ela aparecer aqui." />
            ) : (
              <div style={{ overflowX: 'auto' }}>
                <table style={{ width: '100%', minWidth: 980, borderCollapse: 'collapse', fontSize: 12.5 }}>
                  <thead style={{ background: 'var(--bg-elev)' }}>
                    <tr style={{ borderBottom: '1px solid var(--border)' }}>
                      <th style={thSt}>Campanha</th>
                      <th style={thSt}>Marca</th>
                      <th style={thSt}>Estado</th>
                      <th style={{ ...thSt, textAlign: 'right' }}>Versão</th>
                      <th style={{ ...thSt, textAlign: 'right' }}>Ads</th>
                      <th style={{ ...thSt, textAlign: 'right' }}>Conversas</th>
                      <th style={{ ...thSt, textAlign: 'right' }}>Qualificadas</th>
                      <th style={{ ...thSt, textAlign: 'right' }}>Ficha injectada</th>
                      <th style={{ ...thSt, textAlign: 'right' }}>Ficha usada</th>
                      <th style={{ ...thSt, textAlign: 'right' }}>Conformidade</th>
                      <th style={thSt}>Alertas</th>
                    </tr>
                  </thead>
                  <tbody>
                    {camps.map(c => {
                      const alerts = Array.isArray(c.alertas) && c.alertas.length ? c.alertas : [];
                      const linha = (ok, texto) => (
                        <div style={{ fontSize: 12, color: ok ? 'var(--success, #15803d)' : 'var(--text-muted)' }}>{texto}</div>
                      );
                      return (
                        <tr key={c.id}
                          onClick={() => { setCampanha(c); setView('campanha'); }}
                          className="sdr-row"
                          style={{ borderBottom: '1px solid var(--border)', cursor: 'pointer' }}>
                          <td style={tdSt}><span style={{ fontWeight: 500, color: 'var(--text)' }}>{c.titulo}</span></td>
                          <td style={tdSt}><span style={{ fontSize: 11, fontFamily: 'var(--font-display)', fontWeight: 700, letterSpacing: '0.06em', color: 'var(--ai-500)' }}>{(c.brand_name || c.brand_slug || '').toUpperCase()}</span></td>
                          <td style={tdSt}>
                            {linha(!!c.activa_para_digi, c.activa_para_digi ? 'Ficha pronta' : 'Ficha fora da vista activa')}
                            {linha(!!c.meta_no_ar, c.meta_no_ar ? 'No ar na Meta' : 'Fora do ar')}
                            {c.campanha_teste ? <div style={{ fontSize: 12, color: 'var(--warning, #d97706)' }}>Teste</div> : null}
                          </td>
                          <td style={{ ...tdSt, textAlign: 'right', fontFamily: 'var(--font-mono)' }}>v{c.sdr_ficha_version || 1}</td>
                          <td style={{ ...tdSt, textAlign: 'right', fontFamily: 'var(--font-mono)' }}>{c.n_ads || 0}</td>
                          <td style={{ ...tdSt, textAlign: 'right', fontFamily: 'var(--font-mono)' }}>{c.n_sessoes || 0}</td>
                          <td style={{ ...tdSt, textAlign: 'right', fontFamily: 'var(--font-mono)' }}>{c.n_qualificados || 0}</td>
                          <td style={{ ...tdSt, textAlign: 'right', fontFamily: 'var(--font-mono)' }}>{c.pct_ficha_injectada == null ? '—' : `${c.pct_ficha_injectada}%`}</td>
                          <td style={{ ...tdSt, textAlign: 'right', fontFamily: 'var(--font-mono)' }}>{c.pct_ficha_usada == null ? '—' : `${c.pct_ficha_usada}%`}</td>
                          <td style={{ ...tdSt, textAlign: 'right', fontFamily: 'var(--font-mono)' }}>{c.conformidade_media == null ? '—' : `${c.conformidade_media}%`}</td>
                          <td style={tdSt}>
                            {alerts.map(a => (
                              <span key={a} style={{ display: 'inline-block', marginRight: 4, fontSize: 10, fontFamily: 'var(--font-mono)', padding: '2px 6px', borderRadius: 99, color: 'var(--warning, #d97706)', background: 'color-mix(in oklch, var(--warning, #d97706) 12%, transparent)' }}>{a}</span>
                            ))}
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            )}
            {(cobertura || nSemMapa > 0) && (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 8 }}>
                {cobertura && (
                  <SdrCard title="Cobertura das fichas">
                    <div style={{ fontSize: 22, fontWeight: 700 }}>{cobertura.pct_injectada == null ? '—' : `${cobertura.pct_injectada}%`}</div>
                    <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>das conversas com campanha ou anúncio em que a ficha entrou (anúncio, campanha, lista ou outbound).</div>
                    <div style={{ fontSize: 12, marginTop: 6 }}>{(cobertura.rows || []).map(r => `${r.ficha_match_tipo}: ${r.n}`).join(' · ') || 'Sem conversas com campanha neste período.'}</div>
                  </SdrCard>
                )}
                {nSemMapa > 0 && (
                  <div style={{
                    display: 'flex', alignItems: 'center', gap: 10,
                    padding: '8px 12px', borderRadius: 8,
                    background: 'var(--bg-elev)',
                    border: '1px solid var(--border)',
                    fontSize: 12, color: 'var(--text-muted)',
                  }}>
                    <span>{nSemMapa} conversas antigas com anúncio ainda sem campanha mapeada.</span>
                    <button type="button" className="btn btn-xs" onClick={async () => {
                      try {
                        const r = await SdrAPI.reconciliar();
                        showToast(`${r.mapeados || 0} ads · ${r.contactos_criados || 0} contactos`);
                        loadCamps();
                      } catch (e) { showToast(e.message, 'error'); }
                    }}>Reconciliar</button>
                  </div>
                )}
              </div>
            )}
          </>
        )}

        {tab === 'prompts' && (
          <div style={{ display: 'flex', gap: 8 }}>
            {[['versoes', 'Versões em produção'], ['propostas', 'Propostas de melhoria'], ['relatorios', 'Relatórios semanais']].map(([id, label]) => (
              <button type="button" key={id} className={promptSec === id ? 'btn btn-xs btn-ai' : 'btn btn-xs'} onClick={() => setPromptSec(id)}>{label}</button>
            ))}
          </div>
        )}
        {tab === 'prompts' && promptSec === 'versoes' && (overview?.rubric?.sp_sha_ref || painel) && (
          <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>
            {(() => {
              const ref = overview?.rubric?.sp_sha_ref || painel?.rubric?.sp_sha_ref;
              const sp = (painel?.por_sp || []).find(s => s.sp_name === 'SP_CLIENTES.md') || {};
              const run = sp.sha_run_producao;
              const igual = ref && run ? ref === run : null;
              return `Checklist ${overview?.rubric?.version || painel?.rubric?.version || ''} referencia ${ref ? String(ref).slice(0, 12) : '—'}. Runs recentes de SP_CLIENTES em produção: ${run ? String(run).slice(0, 12) : 'sem runs'}${igual === false ? ' · SHA diferente da checklist' : igual ? ' · coincide com a checklist' : ''}.`;
            })()}
            {(health?.prod_staging_diff || []).length > 0 && (
              <div style={{ marginTop: 6 }}>Produção ≠ staging: {(health.prod_staging_diff || []).map(d => d.file_name).join(', ')}</div>
            )}
          </div>
        )}

        {tab === 'prompts' && promptSec === 'versoes' && (
          <>
            <SdrKPIs items={[
              { id: 'c', label: 'Containers',  value: containers.length, accent: 'var(--ai-500)', fill: 1, noClick: true },
              { id: 'f', label: 'Ficheiros',   value: files.length,      accent: 'var(--text)', fill: 1, noClick: true },
              { id: 'd', label: 'Divergentes', value: nDiv,              accent: 'var(--danger, #ef4444)', fill: files.length ? nDiv / files.length : 0, noClick: true },
              { id: 's', label: 'Stale >24h',  value: nStale,            accent: 'var(--warning, #d97706)', fill: matrix.length ? nStale / Math.max(matrix.length, 1) : 0, noClick: true },
            ]} />
            {matrix.length > 0 && (
              <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
                <button type="button" className="btn btn-sm" onClick={() => setMarkExpectedOpen(true)}>Marcar produção como esperada</button>
              </div>
            )}
            {matrix.length === 0 ? (
              <SdrEmpty title="heydigi.js ainda não regista versões." hint="O Version Registry entra no boot do container. Ficheiros em falta aparecem como —." />
            ) : (
              <div style={{ overflowX: 'auto' }}>
                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12 }}>
                  <thead>
                    <tr style={{ borderBottom: '1px solid var(--border)' }}>
                      <th style={thSt}>Container \ ficheiro</th>
                      {files.map(f => <th key={f} style={thSt}>{f}</th>)}
                    </tr>
                  </thead>
                  <tbody>
                    {containers.map(c => (
                      <tr key={c} style={{ borderBottom: '1px solid var(--border)' }}>
                        <td style={{ ...tdSt, fontFamily: 'var(--font-mono)', fontWeight: 600 }}>{c}</td>
                        {files.map(f => {
                          const cell = matrix.find(m => m.container === c && m.file_name === f);
                          if (!cell) return <td key={f} style={{ ...tdSt, color: 'var(--text-dim)' }}>—</td>;
                          const diff = (health?.prod_staging_diff || []).some(d => d.file_name === f);
                          const col = cell.matches_expected === true ? 'var(--success, #22c55e)' : cell.matches_expected === false ? 'var(--danger, #ef4444)' : 'var(--text-dim)';
                          return (
                            <td key={f} style={{ ...tdSt, cursor: 'pointer' }}
                              onClick={async () => {
                                try {
                                  const d = await SdrAPI.versionImpact(f, c);
                                  setVersaoFile(f);
                                  setVersaoData(d);
                                  setView('versao');
                                } catch (e) { showToast(e.message, 'error'); }
                              }}>
                              <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: col }}>{(cell.file_sha256 || '').slice(0, 7) || '—'}</div>
                              <div style={{ fontSize: 10, color: 'var(--text-dim)' }}>{cell.file_lines != null ? `${cell.file_lines} L` : ''} · {sdrRelTime(cell.loaded_at)}</div>
                              {cell.stale && <span style={{ fontSize: 10, color: 'var(--warning, #d97706)', fontFamily: 'var(--font-mono)' }}>stale</span>}
                              {diff && <div style={{ fontSize: 10, color: 'var(--warning, #d97706)', fontFamily: 'var(--font-mono)' }}>prod ≠ staging</div>}
                            </td>
                          );
                        })}
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
            {(health?.boots || []).length > 0 && (
              <SdrCard title="Boots recentes">
                {health.boots.map((b, i) => (
                  <SdrKV key={i} label={`${b.container} · ${b.container_boot_id?.slice(0, 8)}`} value={sdrRelTime(b.loaded_at)} />
                ))}
              </SdrCard>
            )}
          </>
        )}

        {tab === 'prompts' && promptSec === 'relatorios' && (
          <>
            <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
              <button type="button" className="btn btn-sm btn-ai" onClick={async () => {
                try {
                  await SdrAPI.gerarRelatorio();
                  showToast('Relatório gerado');
                  loadRels();
                } catch (e) { showToast(e.message, 'error'); }
              }}>Gerar relatório</button>
            </div>
            {rels === null ? (
              <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>A carregar…</div>
            ) : rels.length === 0 ? (
              <SdrEmpty title="Ainda não há relatórios semanais." hint="Gera o primeiro ou espera pela segunda-feira (job automático)." />
            ) : (
              <div style={{ overflowX: 'auto' }}>
                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
                  <thead>
                    <tr style={{ borderBottom: '1px solid var(--border)' }}>
                      <th style={thSt}>Período</th>
                      <th style={thSt}>Marca</th>
                      <th style={thSt}>Gerado</th>
                      <th style={thSt}>Resumo</th>
                    </tr>
                  </thead>
                  <tbody>
                    {rels.map(r => (
                      <tr key={r.id}
                        onClick={() => { setRelatorio(r); setView('relatorio'); }}
                        className="sdr-row"
                        style={{ borderBottom: '1px solid var(--border)', cursor: 'pointer' }}>
                        <td style={tdSt}>{sdrDate(r.periodo_inicio)} – {sdrDate(r.periodo_fim)}</td>
                        <td style={tdSt}>{r.marca || '*'}</td>
                        <td style={{ ...tdSt, color: 'var(--text-muted)' }}>{sdrRelTime(r.generated_at)} · {r.generated_by}</td>
                        <td style={tdSt}><div style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: 480 }}>{(r.resumo_md || '').slice(0, 160)}</div></td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </>
        )}

        {tab === 'prompts' && promptSec === 'propostas' && (
          <>
            <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
              <button type="button" className="btn btn-sm btn-ai" onClick={async () => {
                try {
                  const r = await SdrAPI.gerarFrameworks();
                  showToast(`${r.created || 0} proposta(s)`);
                  loadFws();
                } catch (e) { showToast(e.message, 'error'); }
              }}>Gerar propostas</button>
            </div>
            {fws === null ? (
              <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>A carregar…</div>
            ) : fws.length === 0 ? (
              <SdrEmpty title="Sem clusters de desvio." hint="Quando houver ≥3 flags do mesmo tipo/frame, aparece aqui uma proposta de alteração." />
            ) : (
              <div style={{ overflowX: 'auto' }}>
                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
                  <thead>
                    <tr style={{ borderBottom: '1px solid var(--border)' }}>
                      <th style={thSt}>Regra</th>
                      <th style={thSt}>Tipo</th>
                      <th style={thSt}>Frame</th>
                      <th style={thSt}>SP</th>
                      <th style={{ ...thSt, textAlign: 'right' }}>N</th>
                      <th style={thSt}>Estado</th>
                    </tr>
                  </thead>
                  <tbody>
                    {fws.map(f => (
                      <tr key={f.id}
                        onClick={() => { setFwItem(f); setView('framework'); }}
                        className="sdr-row"
                        style={{ borderBottom: '1px solid var(--border)', cursor: 'pointer' }}>
                        <td style={{ ...tdSt, fontFamily: 'var(--font-mono)' }}>{f.regra_id || '—'}</td>
                        <td style={tdSt}><SdrStatusBadge kind="flag" value={f.tipo_desvio} /></td>
                        <td style={tdSt}>{f.frame_target}</td>
                        <td style={tdSt}>{f.sp_target}</td>
                        <td style={{ ...tdSt, textAlign: 'right', fontFamily: 'var(--font-mono)' }}>{f.n_ocorrencias}</td>
                        <td style={tdSt}>{FW_STATUS_LABEL[f.status] || f.status}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </>
        )}
      </div>

      {k.total_cost_usd > 0 && (
        <div style={{
          flexShrink: 0, borderTop: '1px solid var(--border)',
          background: 'var(--bg-elev)', padding: '5px 24px',
          fontSize: 10.5, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)',
        }}>
          <span style={{ fontWeight: 600, color: 'var(--text-muted)', marginRight: 10 }}>SDR</span>
          Custo período: <strong style={{ color: 'var(--text-muted)' }}>${Number(k.total_cost_usd).toFixed(3)}</strong>
        </div>
      )}

      <SdrFlagModal open={flagOpen} bulkCount={selectedIds.size} onClose={() => setFlagOpen(false)} onConfirm={bulkFlag} />
      <SdrConfirmModal
        open={markExpectedOpen}
        title="Marcar produção como esperada"
        body="A versão carregada mais recente de cada ficheiro no container heydigi-ai passa a ser a versão esperada. Os restantes containers ficam divergentes se tiverem outro SHA."
        confirmLabel="Marcar"
        onClose={() => setMarkExpectedOpen(false)}
        onConfirm={async () => {
          setMarkExpectedOpen(false);
          try {
            const r = await SdrAPI.markExpected();
            showToast(`${r.updated || 0} registo(s) actualizado(s)`);
            loadHealth(); loadDash();
          } catch (e) { showToast(e.message, 'error'); }
        }}
      />
      <SdrToast msg={toast} type={toastType} />

      {window.MktTutorial && (
        <window.MktTutorial
          moduleName="sdr"
          moduleLabel="SDR"
          moduleState={{ tab }}
          userEmail={window.currentUser?.email}
        />
      )}
    </div>
  );
};

window.MktSdrScreen = MktSdrScreen;
window.MktLeadsScreen = MktSdrScreen;
window.SdrConversaView = SdrConversaView;
