/* screen_marketing_clipping.jsx
   Marketing · Clipping — observatório de presença externa.
   Menções, sentimento, share of voice, concorrência, alertas.
   Expõe window.MktClippingScreen.
   Nomes JSX únicos (Clip*) — Babel partilha scope entre scripts.
*/

const CLIP_BASE = '/api/marketing/clipping';

const CLIP_MARCAS = [
  { slug: 'mimaki',    label: 'Mimaki' },
  { slug: 'biond',     label: 'BIOND' },
  { slug: 'decal',     label: 'Decal' },
  { slug: 'sensek',    label: 'Sensek' },
  { slug: 'alldecor',  label: 'AllDecor' },
  { slug: 'netscreen', label: 'NetScreen' },
];
const CLIP_MARCA_TOKEN = {
  mimaki: 'var(--danger)',
  biond: 'var(--success)',
  decal: 'var(--warning)',
  sensek: 'var(--ai-500)',
  alldecor: 'var(--brand-500)',
  netscreen: 'var(--brand-700)',
};
const CLIP_MARCA_LABEL = Object.fromEntries(CLIP_MARCAS.map(m => [m.slug, m.label]));

const CLIP_FONTES = [
  ['web', 'Web'], ['imprensa', 'Imprensa'], ['linkedin', 'LinkedIn'],
  ['instagram', 'Instagram'], ['facebook', 'Facebook'], ['twitter', 'X / Twitter'],
  ['tiktok', 'TikTok'], ['reddit', 'Reddit'], ['forum', 'Fórum'], ['google_alerts', 'Google Alerts'],
];
const CLIP_FONTE_LABEL = Object.fromEntries(CLIP_FONTES);

const CLIP_SENT = {
  positivo: { label: 'Positivo', color: 'var(--success)', bg: 'color-mix(in oklch, var(--success) 14%, transparent)' },
  neutro:   { label: 'Neutro',   color: 'var(--text-dim)', bg: 'var(--bg-sunken)' },
  negativo: { label: 'Negativo', color: 'var(--danger)',  bg: 'color-mix(in oklch, var(--danger) 14%, transparent)' },
};
const CLIP_INSIGHT = {
  amplificar:             { label: 'Amplificar',            color: 'var(--success)' },
  responder:              { label: 'Responder',             color: 'var(--warning)' },
  crisis:                 { label: 'Crise',                 color: 'var(--danger)' },
  oportunidade_pr:        { label: 'Oportunidade PR',       color: 'var(--ai-500)' },
  movimento_concorrente:  { label: 'Movimento concorrente', color: 'var(--brand-700)' },
  monitorizar:            { label: 'Monitorizar',           color: 'var(--text-dim)' },
};
const CLIP_ALERT_TIPOS = [
  ['keyword', 'Keyword'],
  ['sentiment_negativo', 'Sentimento negativo'],
  ['volume_pico', 'Volume pico'],
  ['concorrente_menciona', 'Concorrente menciona'],
  ['crisis', 'Crise'],
];

const CLIP_INPUT = {
  fontSize: 12, padding: '7px 10px', borderRadius: 6,
  background: 'var(--bg-elev)', border: '1px solid var(--border)',
  color: 'var(--text)', width: '100%', boxSizing: 'border-box', fontFamily: 'inherit',
};
const CLIP_LABEL = {
  fontSize: 10, fontWeight: 600, color: 'var(--text-muted)',
  textTransform: 'uppercase', letterSpacing: '0.06em', display: 'block', marginBottom: 4,
  fontFamily: 'var(--font-mono)',
};
const CLIP_TH = {
  textAlign: 'left', padding: '8px 12px',
  fontSize: 10, fontFamily: 'var(--font-display)', fontWeight: 600,
  letterSpacing: '0.10em', textTransform: 'uppercase',
  color: 'var(--text-muted)', whiteSpace: 'nowrap',
};

async function clipApiCall(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}`);
  }
  if (res.status === 204) return { ok: true };
  return res.json();
}

const ClipAPI = {
  dashboard:    (p) => clipApiCall(`${CLIP_BASE}/dashboard?${new URLSearchParams(p || {})}`),
  mencoes:      (p) => clipApiCall(`${CLIP_BASE}/mencoes?${new URLSearchParams(p || {})}`),
  mencao:       (id) => clipApiCall(`${CLIP_BASE}/mencoes/${id}`),
  criarMencao:  (body) => clipApiCall(`${CLIP_BASE}/mencoes`, { method: 'POST', body: JSON.stringify(body) }),
  patchMencao:  (id, body) => clipApiCall(`${CLIP_BASE}/mencoes/${id}`, { method: 'PATCH', body: JSON.stringify(body) }),
  delMencao:    (id) => clipApiCall(`${CLIP_BASE}/mencoes/${id}`, { method: 'DELETE' }),
  reanalyze:    (id) => clipApiCall(`${CLIP_BASE}/mencoes/${id}/reanalyze`, { method: 'POST', body: '{}' }),
  alertas:      () => clipApiCall(`${CLIP_BASE}/alertas`),
  criarAlerta:  (body) => clipApiCall(`${CLIP_BASE}/alertas`, { method: 'POST', body: JSON.stringify(body) }),
  patchAlerta:  (id, body) => clipApiCall(`${CLIP_BASE}/alertas/${id}`, { method: 'PATCH', body: JSON.stringify(body) }),
  delAlerta:    (id) => clipApiCall(`${CLIP_BASE}/alertas/${id}`, { method: 'DELETE' }),
  disparos:     () => clipApiCall(`${CLIP_BASE}/disparos`),
  ack:          (alertaId, body) => clipApiCall(`${CLIP_BASE}/alertas/${alertaId}/ack`, { method: 'POST', body: JSON.stringify(body) }),
  concorrencia: (p) => clipApiCall(`${CLIP_BASE}/concorrencia?${new URLSearchParams(p || {})}`),
  addConc:      (body) => clipApiCall(`${CLIP_BASE}/concorrencia`, { method: 'POST', body: JSON.stringify(body) }),
  patchConc:    (id, body) => clipApiCall(`${CLIP_BASE}/concorrencia/${id}`, { method: 'PATCH', body: JSON.stringify(body) }),
  sov:          (p) => clipApiCall(`${CLIP_BASE}/share-of-voice?${new URLSearchParams(p || {})}`),
  relatorios:   (p) => clipApiCall(`${CLIP_BASE}/relatorios?${new URLSearchParams(p || {})}`),
  gerarRel:     (body) => clipApiCall(`${CLIP_BASE}/relatorios/gerar`, { method: 'POST', body: JSON.stringify(body) }),
  insights:     (p) => clipApiCall(`${CLIP_BASE}/insights?${new URLSearchParams(p || {})}`),
  patchInsight: (id, action) => clipApiCall(`${CLIP_BASE}/insights/${id}`, { method: 'PATCH', body: JSON.stringify({ action }) }),
  briefing:     (id, body) => clipApiCall(`${CLIP_BASE}/insights/${id}/briefing`, { method: 'POST', body: JSON.stringify(body || {}) }),
  collect:      () => clipApiCall(`${CLIP_BASE}/collect`, { method: 'POST', body: '{}' }),
  status:       () => clipApiCall(`${CLIP_BASE}/status`),
};

function clipFmtDate(iso) {
  if (!iso) return '—';
  const s = String(iso);
  const hit = s.match(/(\d{4})-(\d{2})-(\d{2})/);
  if (hit) return `${hit[3]}/${hit[2]}/${hit[1]}`;
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return s.slice(0, 10);
  return d.toLocaleDateString('pt-PT');
}
function clipQs(obj) {
  const o = {};
  Object.entries(obj || {}).forEach(([k, v]) => {
    if (v !== undefined && v !== '' && v !== null && v !== false) o[k] = v;
  });
  return o;
}

const ClipBadge = ({ label, color, bg }) => (
  <span style={{
    fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
    padding: '2px 8px', borderRadius: 4, background: bg || 'var(--bg-sunken)',
    color: color || 'var(--text-dim)', fontFamily: 'var(--font-mono)',
    display: 'inline-block', whiteSpace: 'nowrap',
  }}>{label}</span>
);

const ClipMarcaChip = ({ slug }) => {
  const c = CLIP_MARCA_TOKEN[slug] || 'var(--ai-500)';
  return (
    <span style={{
      fontSize: 10, fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase',
      padding: '2px 8px', borderRadius: 4, fontFamily: 'var(--font-mono)',
      background: `color-mix(in oklch, ${c} 14%, transparent)`,
      color: c, border: `1px solid color-mix(in oklch, ${c} 28%, transparent)`,
    }}>{CLIP_MARCA_LABEL[slug] || slug}</span>
  );
};

const ClipSentBadge = ({ sent }) => {
  const cfg = CLIP_SENT[sent] || CLIP_SENT.neutro;
  return <ClipBadge label={cfg.label} color={cfg.color} bg={cfg.bg} />;
};

const ClipSelect = ({ value, onChange, options, placeholder = 'Todos' }) => (
  <select value={value || ''} onChange={e => onChange(e.target.value)}
    style={{ ...CLIP_INPUT, width: 'auto', minWidth: 120, color: value ? 'var(--text)' : 'var(--text-dim)' }}>
    <option value="">{placeholder}</option>
    {options.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
  </select>
);

function ClipSentimentBar({ pos = 0, neu = 0, neg = 0 }) {
  const t = pos + neu + neg;
  const w = (n) => t ? `${(n / t) * 100}%` : '0%';
  return (
    <div title={`${pos} pos · ${neu} neu · ${neg} neg`} style={{
      display: 'flex', height: 8, borderRadius: 99, overflow: 'hidden',
      background: 'var(--bg-sunken)', minWidth: 72,
    }}>
      <div style={{ width: w(pos), background: 'var(--success)' }} />
      <div style={{ width: w(neu), background: 'var(--text-dim)', opacity: 0.45 }} />
      <div style={{ width: w(neg), background: 'var(--danger)' }} />
    </div>
  );
}

function ClipVolumeChart({ volume, height = 160 }) {
  const marcas = CLIP_MARCAS.map(m => m.slug);
  const days = [...new Set((volume || []).map(v => String(v.dia).slice(0, 10)))].sort();
  if (!days.length) {
    return <div style={{ padding: 24, color: 'var(--text-muted)', fontSize: 12 }}>Sem volume no período.</div>;
  }
  const by = {};
  let max = 1;
  for (const v of volume || []) {
    const dia = String(v.dia).slice(0, 10);
    if (!by[v.marca_slug]) by[v.marca_slug] = {};
    by[v.marca_slug][dia] = v.n;
    if (v.n > max) max = v.n;
  }
  const W = Math.max(520, days.length * 18);
  const H = height;
  const pad = { l: 28, r: 8, t: 12, b: 22 };
  const iw = W - pad.l - pad.r;
  const ih = H - pad.t - pad.b;
  const x = (i) => pad.l + (days.length === 1 ? iw / 2 : (i / (days.length - 1)) * iw);
  const y = (n) => pad.t + ih - (n / max) * ih;
  return (
    <div className="scrollbar" style={{ overflowX: 'auto' }}>
      <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} role="img" aria-label="Volume de menções">
        {[0, 0.5, 1].map(p => (
          <line key={p} x1={pad.l} x2={W - pad.r} y1={y(max * p)} y2={y(max * p)}
            stroke="var(--border)" strokeWidth="1" />
        ))}
        {marcas.map(slug => {
          const pts = days.map((d, i) => `${x(i)},${y(by[slug]?.[d] || 0)}`).join(' ');
          return (
            <polyline key={slug} points={pts} fill="none"
              stroke={CLIP_MARCA_TOKEN[slug]} strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" />
          );
        })}
        <text x={pad.l} y={H - 4} fontSize="9" fill="var(--text-dim)" fontFamily="var(--font-mono)">{clipFmtDate(days[0])}</text>
        <text x={W - pad.r} y={H - 4} fontSize="9" fill="var(--text-dim)" fontFamily="var(--font-mono)" textAnchor="end">{clipFmtDate(days[days.length - 1])}</text>
      </svg>
    </div>
  );
}

function clipPolar(cx, cy, r, a) {
  const rad = (a - 90) * Math.PI / 180;
  return [cx + r * Math.cos(rad), cy + r * Math.sin(rad)];
}
function ClipPie({ slices, size = 180 }) {
  const total = (slices || []).reduce((s, x) => s + (x.n || 0), 0);
  if (!total) return <div style={{ fontSize: 12, color: 'var(--text-muted)', padding: 20 }}>Sem dados de SoV.</div>;
  const cx = size / 2, cy = size / 2, r = size / 2 - 8;
  let a = 0;
  const paths = slices.filter(s => s.n > 0).map((s, i) => {
    const sweep = (s.n / total) * 360;
    const start = a;
    const end = a + sweep;
    a = end;
    const [x1, y1] = clipPolar(cx, cy, r, start);
    const [x2, y2] = clipPolar(cx, cy, r, end);
    const large = sweep > 180 ? 1 : 0;
    const d = sweep >= 359.9
      ? `M ${cx} ${cy - r} A ${r} ${r} 0 1 1 ${cx - 0.01} ${cy - r} Z`
      : `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2} Z`;
    return <path key={s.slug || i} d={d} fill={s.color} opacity={s.is_marca ? 1 : 0.72} />;
  });
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} role="img" aria-label="Share of voice">
      {paths}
    </svg>
  );
}

const ClipModal = ({ title, onClose, children, footer, width = 480 }) => {
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);
  return ReactDOM.createPortal(
    <>
      <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'color-mix(in oklch, var(--text) 28%, transparent)', zIndex: 400 }} />
      <div role="dialog" aria-label={title} style={{
        position: 'fixed', top: '10vh', left: '50%', transform: 'translateX(-50%)',
        width, maxWidth: 'calc(100vw - 32px)', maxHeight: '80vh',
        background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 12,
        zIndex: 410, display: 'flex', flexDirection: 'column',
        boxShadow: '0 16px 48px color-mix(in oklch, var(--text) 18%, transparent)',
      }}>
        <div style={{ padding: '16px 20px', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div style={{ fontSize: 15, fontWeight: 700, fontFamily: 'var(--font-display)' }}>{title}</div>
          <button type="button" onClick={onClose} aria-label="Fechar" style={{
            background: 'none', border: '1px solid var(--border)', borderRadius: 6,
            padding: '4px 8px', cursor: 'pointer', color: 'var(--text-muted)',
          }}>✕</button>
        </div>
        <div className="scrollbar" style={{ padding: 20, overflowY: 'auto', flex: 1 }}>{children}</div>
        {footer && (
          <div style={{ padding: '12px 20px', borderTop: '1px solid var(--border)', background: 'var(--bg-sunken)', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
            {footer}
          </div>
        )}
      </div>
    </>,
    document.body
  );
};

const ClipMencaoDrawer = ({ id, onClose, onChanged, userName }) => {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [sentEdit, setSentEdit] = React.useState('');

  const load = React.useCallback(() => {
    setLoading(true);
    ClipAPI.mencao(id).then(d => { setData(d); setSentEdit(d.sentimento || ''); setLoading(false); })
      .catch(() => setLoading(false));
  }, [id]);
  React.useEffect(() => { load(); }, [load]);
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);

  async function act(fn) {
    setBusy(true);
    try {
      await fn();
      load();
      if (onChanged) onChanged();
    } catch (e) { alert(e.message); }
    finally { setBusy(false); }
  }

  return (
    <>
      <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'color-mix(in oklch, var(--text) 25%, transparent)', zIndex: 350 }} />
      <aside role="dialog" aria-label="Detalhe da menção" style={{
        position: 'fixed', top: 0, right: 0, bottom: 0, width: 420, maxWidth: '100vw',
        background: 'var(--bg-elev)', zIndex: 360, display: 'flex', flexDirection: 'column',
        borderLeft: '1px solid var(--border)',
        boxShadow: '-8px 0 32px color-mix(in oklch, var(--text) 12%, transparent)',
      }}>
        <div style={{ padding: '16px 20px', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>Menção</div>
          <button type="button" onClick={onClose} aria-label="Fechar" style={{
            background: 'none', border: '1px solid var(--border)', borderRadius: 6, padding: '4px 8px', cursor: 'pointer', color: 'var(--text-muted)',
          }}>✕</button>
        </div>
        <div className="scrollbar" style={{ flex: 1, overflowY: 'auto', padding: 20 }}>
          {loading ? (
            <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-muted)', fontSize: 12 }}>A carregar…</div>
          ) : !data ? (
            <div style={{ color: 'var(--text-muted)', fontSize: 12 }}>Não foi possível carregar.</div>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                <ClipMarcaChip slug={data.marca_slug} />
                <ClipSentBadge sent={data.sentimento} />
                {data.is_critical && <ClipBadge label="Crítico" color="var(--danger)" bg="color-mix(in oklch, var(--danger) 14%, transparent)" />}
                {data.sujeito_tipo === 'concorrente' && <ClipBadge label={data.concorrente_slug || 'Concorrente'} color="var(--warning)" bg="color-mix(in oklch, var(--warning) 12%, transparent)" />}
              </div>
              <div style={{ fontSize: 16, fontWeight: 700, fontFamily: 'var(--font-display)', lineHeight: 1.3 }}>{data.titulo}</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', fontFamily: 'var(--font-mono)' }}>
                {CLIP_FONTE_LABEL[data.fonte] || data.fonte} · {data.fonte_nome || '—'} · {data.pais || '—'} · {clipFmtDate(data.data_publicacao)}
              </div>
              {data.url && (
                <a href={data.url} target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: 'var(--ai-500)', wordBreak: 'break-all' }}>{data.url}</a>
              )}
              {data.fonte_autor && <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Autor: {data.fonte_autor}</div>}
              {data.conteudo && (
                <div style={{ fontSize: 13, color: 'var(--text)', lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{data.conteudo}</div>
              )}
              <div style={{ padding: 12, borderRadius: 8, background: 'var(--bg-sunken)', border: '1px solid var(--border)' }}>
                <div style={{ ...CLIP_LABEL, marginBottom: 6 }}>Análise de sentimento</div>
                <div style={{ fontSize: 12, color: 'var(--text)', lineHeight: 1.55 }}>{data.sentiment_reasoning || '—'}</div>
                <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', marginTop: 6 }}>
                  score {data.sentiment_score ?? '—'}
                </div>
              </div>
              {data.insight_accao && (
                <div style={{ padding: 12, borderRadius: 8, border: '1px solid var(--border)', background: 'color-mix(in oklch, var(--ai-500) 6%, transparent)' }}>
                  <div style={{ ...CLIP_LABEL, color: 'var(--ai-500)' }}>O que fazer</div>
                  <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 4 }}>{CLIP_INSIGHT[data.insight_tipo]?.label || data.insight_tipo}</div>
                  <div style={{ fontSize: 12, lineHeight: 1.55 }}>{data.insight_accao}</div>
                </div>
              )}
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
                <div style={{ padding: 10, background: 'var(--bg-sunken)', borderRadius: 8 }}>
                  <div style={CLIP_LABEL}>Reach</div>
                  <div style={{ fontFamily: 'var(--font-mono)', fontWeight: 700 }}>{data.reach_estimado ?? '—'}</div>
                </div>
                <div style={{ padding: 10, background: 'var(--bg-sunken)', borderRadius: 8 }}>
                  <div style={CLIP_LABEL}>Engagement</div>
                  <div style={{ fontFamily: 'var(--font-mono)', fontWeight: 700 }}>{data.engagement_total ?? '—'}</div>
                </div>
              </div>
              {!!data.disparos?.length && (
                <div>
                  <div style={CLIP_LABEL}>Alertas disparados</div>
                  {data.disparos.map(d => (
                    <div key={d.id} style={{ fontSize: 12, padding: '6px 0', borderBottom: '1px solid var(--border)' }}>
                      {d.alerta_nome} · {clipFmtDate(d.disparado_em)}
                    </div>
                  ))}
                </div>
              )}
              <div>
                <label style={CLIP_LABEL}>Override sentimento</label>
                <select value={sentEdit} onChange={e => setSentEdit(e.target.value)} style={CLIP_INPUT}>
                  <option value="positivo">Positivo</option>
                  <option value="neutro">Neutro</option>
                  <option value="negativo">Negativo</option>
                </select>
              </div>
            </div>
          )}
        </div>
        {data && (
          <div style={{ padding: 14, borderTop: '1px solid var(--border)', background: 'var(--bg-sunken)', display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            <button type="button" className="btn-ai" disabled={busy} onClick={() => act(() => ClipAPI.patchMencao(id, { sentimento: sentEdit }))} style={{ fontSize: 11, padding: '6px 10px' }}>Guardar sentimento</button>
            <button type="button" disabled={busy} onClick={() => act(() => ClipAPI.patchMencao(id, { is_critical: !data.is_critical }))} style={{ fontSize: 11, padding: '6px 10px', border: '1px solid var(--border)', borderRadius: 6, background: 'var(--bg-elev)', cursor: 'pointer', color: 'var(--text)' }}>
              {data.is_critical ? 'Desmarcar crítico' : 'Marcar crítico'}
            </button>
            <button type="button" disabled={busy} onClick={() => act(() => ClipAPI.patchMencao(id, { is_reviewed: true, reviewed_by: userName || 'portal' }))} style={{ fontSize: 11, padding: '6px 10px', border: '1px solid var(--border)', borderRadius: 6, background: 'var(--bg-elev)', cursor: 'pointer', color: 'var(--text)' }}>
              {data.is_reviewed ? 'Revisto' : 'Marcar revisto'}
            </button>
            <button type="button" disabled={busy} onClick={() => act(() => ClipAPI.reanalyze(id))} style={{ fontSize: 11, padding: '6px 10px', border: '1px solid var(--border)', borderRadius: 6, background: 'var(--bg-elev)', cursor: 'pointer', color: 'var(--text)' }}>
              Reanalisar
            </button>
          </div>
        )}
      </aside>
    </>
  );
};

const ClipNovaMencaoModal = ({ onClose, onSaved, defaultMarca }) => {
  const [marca, setMarca] = React.useState(defaultMarca && defaultMarca !== 'todas' ? defaultMarca : 'mimaki');
  const [titulo, setTitulo] = React.useState('');
  const [conteudo, setConteudo] = React.useState('');
  const [url, setUrl] = React.useState('');
  const [fonte, setFonte] = React.useState('web');
  const [pais, setPais] = React.useState('PT');
  const [dataPub, setDataPub] = React.useState(new Date().toISOString().slice(0, 16));
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');
  async function save() {
    if (!titulo.trim()) { setErr('Título obrigatório'); return; }
    setBusy(true); setErr('');
    try {
      await ClipAPI.criarMencao({
        marca_slug: marca, titulo: titulo.trim(), conteudo, url, fonte, pais,
        data_publicacao: dataPub ? new Date(dataPub).toISOString() : new Date().toISOString(),
      });
      onSaved();
    } catch (e) { setErr(e.message); setBusy(false); }
  }
  return (
    <ClipModal title="Nova menção (manual)" onClose={onClose} footer={
      <>
        <button type="button" onClick={onClose} style={{ padding: '7px 12px', borderRadius: 6, border: '1px solid var(--border)', background: 'transparent', cursor: 'pointer', color: 'var(--text-muted)' }}>Cancelar</button>
        <button type="button" className="btn-ai" disabled={busy} onClick={save} style={{ padding: '7px 14px' }}>{busy ? 'A analisar…' : 'Guardar e analisar'}</button>
      </>
    }>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {err && <div style={{ color: 'var(--danger)', fontSize: 12 }}>{err}</div>}
        <div><label style={CLIP_LABEL}>Marca</label>
          <select value={marca} onChange={e => setMarca(e.target.value)} style={CLIP_INPUT}>
            {CLIP_MARCAS.map(m => <option key={m.slug} value={m.slug}>{m.label}</option>)}
          </select>
        </div>
        <div><label style={CLIP_LABEL}>Título</label>
          <input value={titulo} onChange={e => setTitulo(e.target.value)} style={CLIP_INPUT} /></div>
        <div><label style={CLIP_LABEL}>Conteúdo</label>
          <textarea value={conteudo} onChange={e => setConteudo(e.target.value)} rows={5} style={{ ...CLIP_INPUT, resize: 'vertical' }} /></div>
        <div><label style={CLIP_LABEL}>URL</label>
          <input value={url} onChange={e => setUrl(e.target.value)} style={CLIP_INPUT} /></div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
          <div><label style={CLIP_LABEL}>Fonte</label>
            <select value={fonte} onChange={e => setFonte(e.target.value)} style={CLIP_INPUT}>
              {CLIP_FONTES.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
            </select></div>
          <div><label style={CLIP_LABEL}>País</label>
            <select value={pais} onChange={e => setPais(e.target.value)} style={CLIP_INPUT}>
              {['PT','ES','FR','UK','DE','IT'].map(p => <option key={p} value={p}>{p}</option>)}
            </select></div>
        </div>
        <div><label style={CLIP_LABEL}>Data publicação</label>
          <input type="datetime-local" value={dataPub} onChange={e => setDataPub(e.target.value)} style={CLIP_INPUT} /></div>
      </div>
    </ClipModal>
  );
};

const ClipAlertaModal = ({ initial, onClose, onSaved, userName }) => {
  const [nome, setNome] = React.useState(initial?.nome || '');
  const [tipo, setTipo] = React.useState(initial?.tipo || 'keyword');
  const [marca, setMarca] = React.useState(initial?.marca_slug || '');
  const [keyword, setKeyword] = React.useState(initial?.keyword || '');
  const [thVol, setThVol] = React.useState(initial?.threshold_volume ?? 10);
  const [thSent, setThSent] = React.useState(initial?.threshold_sentiment ?? -0.4);
  const [dest, setDest] = React.useState((initial?.destinatarios || ['fabio.costa@digidelta.pt']).join(', '));
  const [canais, setCanais] = React.useState(initial?.canais_notif || ['portal', 'email']);
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');
  function toggleCanal(c) {
    setCanais(prev => prev.includes(c) ? prev.filter(x => x !== c) : [...prev, c]);
  }
  async function save() {
    if (!nome.trim()) { setErr('Nome obrigatório'); return; }
    setBusy(true); setErr('');
    const body = {
      nome: nome.trim(), tipo, marca_slug: marca || null, keyword: keyword || null,
      threshold_volume: Number(thVol), threshold_sentiment: Number(thSent),
      destinatarios: dest.split(',').map(s => s.trim()).filter(Boolean),
      canais_notif: canais, created_by: userName || null,
    };
    try {
      if (initial?.id) await ClipAPI.patchAlerta(initial.id, body);
      else await ClipAPI.criarAlerta(body);
      onSaved();
    } catch (e) { setErr(e.message); setBusy(false); }
  }
  return (
    <ClipModal title={initial?.id ? 'Editar alerta' : 'Novo alerta'} onClose={onClose} footer={
      <>
        <button type="button" onClick={onClose} style={{ padding: '7px 12px', borderRadius: 6, border: '1px solid var(--border)', background: 'transparent', cursor: 'pointer', color: 'var(--text-muted)' }}>Cancelar</button>
        <button type="button" className="btn-ai" disabled={busy} onClick={save}>{busy ? 'A guardar…' : 'Guardar'}</button>
      </>
    }>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {err && <div style={{ color: 'var(--danger)', fontSize: 12 }}>{err}</div>}
        <div><label style={CLIP_LABEL}>Nome</label><input value={nome} onChange={e => setNome(e.target.value)} style={CLIP_INPUT} /></div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
          <div><label style={CLIP_LABEL}>Tipo</label>
            <select value={tipo} onChange={e => setTipo(e.target.value)} style={CLIP_INPUT}>
              {CLIP_ALERT_TIPOS.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
            </select></div>
          <div><label style={CLIP_LABEL}>Marca</label>
            <select value={marca} onChange={e => setMarca(e.target.value)} style={CLIP_INPUT}>
              <option value="">Todas</option>
              {CLIP_MARCAS.map(m => <option key={m.slug} value={m.slug}>{m.label}</option>)}
            </select></div>
        </div>
        {tipo === 'keyword' && <div><label style={CLIP_LABEL}>Keyword</label><input value={keyword} onChange={e => setKeyword(e.target.value)} style={CLIP_INPUT} /></div>}
        {tipo === 'volume_pico' && <div><label style={CLIP_LABEL}>Threshold volume 24h</label><input type="number" value={thVol} onChange={e => setThVol(e.target.value)} style={CLIP_INPUT} /></div>}
        {tipo === 'sentiment_negativo' && <div><label style={CLIP_LABEL}>Threshold score</label><input type="number" step="0.1" value={thSent} onChange={e => setThSent(e.target.value)} style={CLIP_INPUT} /></div>}
        <div><label style={CLIP_LABEL}>Destinatários (emails)</label><input value={dest} onChange={e => setDest(e.target.value)} style={CLIP_INPUT} /></div>
        <div>
          <label style={CLIP_LABEL}>Canais</label>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            {['portal', 'email', 'wa', 'push'].map(c => (
              <button key={c} type="button" onClick={() => toggleCanal(c)} style={{
                padding: '4px 10px', borderRadius: 99, cursor: 'pointer', fontSize: 11, fontWeight: 600,
                border: '1px solid var(--border)',
                background: canais.includes(c) ? 'color-mix(in oklch, var(--ai-500) 14%, transparent)' : 'var(--bg-elev)',
                color: canais.includes(c) ? 'var(--ai-500)' : 'var(--text-muted)',
              }}>{c}</button>
            ))}
          </div>
        </div>
      </div>
    </ClipModal>
  );
};

const ClipTabObservatorio = ({ data, loading, onOpenMencao, onCollect, collecting, onInsight, onBriefing, periodo, setPeriodo, clipStatus }) => {
  const Kpi = window.MktKpi;
  const k = data?.kpis || {};
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
        <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em' }}>O QUE FAZER AGORA</div>
        <div style={{ display: 'flex', gap: 8 }}>
          {['7d', '30d', '90d'].map(p => (
            <button key={p} type="button" onClick={() => setPeriodo(p)} style={{
              padding: '4px 10px', borderRadius: 6, fontSize: 11, fontWeight: 600, cursor: 'pointer',
              border: '1px solid var(--border)',
              background: periodo === p ? 'var(--ai-500)' : 'var(--bg-elev)',
              color: periodo === p ? 'var(--bg-elev)' : 'var(--text-muted)',
            }}>{p}</button>
          ))}
          <button type="button" className="btn-ai" disabled={collecting} onClick={onCollect} style={{ fontSize: 11, padding: '5px 12px' }}>
            {collecting ? 'A recolher…' : 'Correr agora'}
          </button>
        </div>
      </div>
      {clipStatus && (
        <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)' }}>
          {clipStatus.running ? 'Recolha em curso…' : (clipStatus.last
            ? `Última recolha: ${clipStatus.last.inserted || 0} novas · ${clipStatus.last.analyzed || 0} analisadas · ${clipStatus.last.jobs || 0} fontes`
            : (clipStatus.config?.path_ok ? `${clipStatus.config.sources_rss} RSS + Google News + concorrentes` : 'Config de fontes em falta'))}
          {clipStatus.paid && !clipStatus.paid.mention && !clipStatus.paid.brand24 ? ' · Mention/Brand24 não ligados' : ''}
        </div>
      )}

      {(data?.insights || []).length === 0 && !loading && (
        <div style={{ padding: 18, borderRadius: 10, border: '1px dashed var(--border)', background: 'var(--bg-sunken)' }}>
          <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 6 }}>Ainda sem insights</div>
          <div style={{ fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.55, maxWidth: 560 }}>
            A recolha cobre RSS de imprensa, Google News (PT/ES + LinkedIn), sites de concorrentes, Reddit e GDELT. Clica em «Correr agora» ou cola uma menção.
          </div>
        </div>
      )}

      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        {(data?.insights || []).map(ins => {
          const cfg = CLIP_INSIGHT[ins.tipo] || CLIP_INSIGHT.monitorizar;
          return (
            <div key={ins.id} style={{
              padding: '12px 14px', borderRadius: 10, border: '1px solid var(--border)',
              background: 'var(--bg-elev)', display: 'flex', gap: 12, alignItems: 'flex-start',
            }}>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: 'flex', gap: 6, marginBottom: 4, flexWrap: 'wrap' }}>
                  <ClipBadge label={cfg.label} color={cfg.color} bg={`color-mix(in oklch, ${cfg.color} 12%, transparent)`} />
                  {ins.marca_slug && <ClipMarcaChip slug={ins.marca_slug} />}
                  <ClipBadge label={ins.priority} color="var(--text-dim)" bg="var(--bg-sunken)" />
                </div>
                <div style={{ fontSize: 13, fontWeight: 600 }}>{ins.titulo}</div>
                <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4, lineHeight: 1.5 }}>{ins.accao_sugerida || ins.resumo}</div>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 4, flexShrink: 0 }}>
                {ins.mencao_id && (
                  <button type="button" onClick={() => onOpenMencao(ins.mencao_id)} style={{
                    fontSize: 11, padding: '5px 8px', borderRadius: 6, border: '1px solid var(--border)',
                    background: 'var(--bg-sunken)', cursor: 'pointer', color: 'var(--ai-500)',
                  }}>Ver menção</button>
                )}
                <button type="button" onClick={() => onInsight(ins.id, 'accept')} style={{
                  fontSize: 11, padding: '5px 8px', borderRadius: 6, border: 'none',
                  background: 'color-mix(in oklch, var(--success) 16%, transparent)', cursor: 'pointer', color: 'var(--success)', fontWeight: 600,
                }}>Aceitar</button>
                <button type="button" onClick={() => onBriefing && onBriefing(ins.id)} style={{
                  fontSize: 11, padding: '5px 8px', borderRadius: 6, border: '1px solid var(--border)',
                  background: 'var(--bg-sunken)', cursor: 'pointer', color: 'var(--ai-500)', fontWeight: 600,
                }}>Gerar briefing</button>
                <button type="button" onClick={() => onInsight(ins.id, 'dismiss')} style={{
                  fontSize: 11, padding: '5px 8px', borderRadius: 6, border: '1px solid var(--border)',
                  background: 'transparent', cursor: 'pointer', color: 'var(--text-muted)',
                }}>Dispensar</button>
              </div>
            </div>
          );
        })}
      </div>

      {Kpi ? (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, minmax(0, 1fr))', gap: 10 }}>
          <Kpi label="Menções 30d" value={k.total_mencoes ?? 0} sub="todas as fontes" />
          <Kpi label="Críticas" value={k.criticas ?? 0} sub={`${data?.criticas_por_rever || 0} por rever`} />
          <Kpi label="Sentimento" value={k.sentimento_medio ?? 0} sub="média −1 a +1" />
          <Kpi label="Share of Voice" value={`${k.sov_medio ?? 0}%`} sub="média das marcas" />
          <Kpi label="Alertas activos" value={k.alertas_activos ?? 0} />
        </div>
      ) : (
        <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>KPIs: {k.total_mencoes || 0} menções</div>
      )}

      <div>
        <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em', marginBottom: 10 }}>POR MARCA</div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 10 }}>
          {(data?.por_marca || CLIP_MARCAS.map(m => ({ marca_slug: m.slug, mencoes: 0, sentimento: {}, sov: 0, tendencia_semana: 0 }))).map(m => {
            const up = (m.tendencia_semana || 0) > 0;
            const down = (m.tendencia_semana || 0) < 0;
            return (
              <div key={m.marca_slug} style={{ padding: 14, borderRadius: 10, border: '1px solid var(--border)', background: 'var(--bg-elev)' }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
                  <ClipMarcaChip slug={m.marca_slug} />
                  <span style={{
                    fontSize: 11, fontFamily: 'var(--font-mono)', fontWeight: 700,
                    color: up ? 'var(--success)' : down ? 'var(--danger)' : 'var(--text-dim)',
                  }}>{up ? '↑' : down ? '↓' : '→'} {Math.abs(m.tendencia_semana || 0)}%</span>
                </div>
                <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'var(--font-display)' }}>{m.mencoes || 0}</div>
                <div style={{ fontSize: 10, color: 'var(--text-dim)', marginBottom: 8 }}>menções · SoV {m.sov || 0}%</div>
                <ClipSentimentBar pos={m.sentimento?.positivo || 0} neu={m.sentimento?.neutro || 0} neg={m.sentimento?.negativo || 0} />
              </div>
            );
          })}
        </div>
      </div>

      <div style={{ padding: 16, borderRadius: 10, border: '1px solid var(--border)', background: 'var(--bg-elev)' }}>
        <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em', marginBottom: 8 }}>VOLUME · {periodo}</div>
        <ClipVolumeChart volume={data?.volume || []} />
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 8 }}>
          {CLIP_MARCAS.map(m => (
            <span key={m.slug} style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: CLIP_MARCA_TOKEN[m.slug], display: 'flex', alignItems: 'center', gap: 4 }}>
              <span style={{ width: 8, height: 2, background: CLIP_MARCA_TOKEN[m.slug], display: 'inline-block' }} />
              {m.label}
            </span>
          ))}
        </div>
      </div>

      {(data?.top_fontes || []).length > 0 && (
        <div>
          <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em', marginBottom: 8 }}>TOP FONTES</div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
            {data.top_fontes.map(f => (
              <span key={f.fonte_nome} style={{
                fontSize: 11, padding: '4px 8px', borderRadius: 6, border: '1px solid var(--border)',
                background: 'var(--bg-elev)', color: 'var(--text-muted)', fontFamily: 'var(--font-mono)',
              }}>{f.fonte_nome} · {f.n}</span>
            ))}
          </div>
        </div>
      )}

      {(data?.alertas_24h || []).length > 0 && (
        <div>
          <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em', marginBottom: 8 }}>ALERTAS 24H</div>
          {data.alertas_24h.map(a => (
            <div key={a.id} onClick={() => a.mencao_id && onOpenMencao(a.mencao_id)} style={{
              padding: '8px 12px', borderRadius: 8, border: '1px solid var(--border)', marginBottom: 6,
              cursor: 'pointer', display: 'flex', gap: 8, alignItems: 'center', background: 'var(--bg-elev)',
            }}>
              {a.is_critical && <ClipBadge label="Crítico" color="var(--danger)" bg="color-mix(in oklch, var(--danger) 14%, transparent)" />}
              <span style={{ fontSize: 12, fontWeight: 600 }}>{a.alerta_nome}</span>
              <span style={{ fontSize: 12, color: 'var(--text-muted)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{a.mencao_titulo}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

const ClipTabMencoes = ({ marcaCtx, onOpen, onNew, refreshPing }) => {
  const [q, setQ] = React.useState('');
  const [sentimento, setSentimento] = React.useState('');
  const [fonte, setFonte] = React.useState('');
  const [pais, setPais] = React.useState('');
  const [lingua, setLingua] = React.useState('');
  const [crit, setCrit] = React.useState(() => {
    try {
      if (localStorage.getItem('mkt-inicio-clipping-criticas')) {
        localStorage.removeItem('mkt-inicio-clipping-criticas');
        return 'true';
      }
    } catch {}
    return '';
  });
  const [rev, setRev] = React.useState('');
  const [dataIni, setDataIni] = React.useState('');
  const [dataFim, setDataFim] = React.useState('');
  const [offset, setOffset] = React.useState(0);
  const [data, setData] = React.useState({ rows: [], total: 0 });
  const [loading, setLoading] = React.useState(false);

  const load = React.useCallback(() => {
    setLoading(true);
    const params = clipQs({
      marca: marcaCtx && marcaCtx !== 'todas' ? marcaCtx : undefined,
      sentimento, fonte, pais, lingua, keyword: q,
      is_critical: crit || undefined, is_reviewed: rev || undefined,
      data_inicio: dataIni || undefined, data_fim: dataFim || undefined,
      limit: 50, offset,
    });
    ClipAPI.mencoes(params).then(d => { setData(d); setLoading(false); }).catch(() => setLoading(false));
  }, [marcaCtx, sentimento, fonte, pais, lingua, q, crit, rev, dataIni, dataFim, offset, refreshPing]);

  React.useEffect(() => { setOffset(0); }, [marcaCtx, sentimento, fonte, pais, lingua, q, crit, rev, dataIni, dataFim]);
  React.useEffect(() => { load(); }, [load]);

  return (
    <div>
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 14, alignItems: 'center' }}>
        <input value={q} onChange={e => setQ(e.target.value)} placeholder="Keyword…" style={{ ...CLIP_INPUT, width: 180 }} />
        <ClipSelect value={sentimento} onChange={setSentimento} options={[['positivo','Positivo'],['neutro','Neutro'],['negativo','Negativo']]} placeholder="Sentimento" />
        <ClipSelect value={fonte} onChange={setFonte} options={CLIP_FONTES} placeholder="Fonte" />
        <ClipSelect value={pais} onChange={setPais} options={['PT','ES','FR','UK','DE','IT'].map(p => [p, p])} placeholder="País" />
        <ClipSelect value={lingua} onChange={setLingua} options={[['pt','PT'],['es','ES'],['fr','FR'],['en','EN'],['de','DE'],['it','IT']]} placeholder="Língua" />
        <ClipSelect value={crit} onChange={setCrit} options={[['true','Crítico'],['false','Não crítico']]} placeholder="Crítico" />
        <ClipSelect value={rev} onChange={setRev} options={[['true','Revisto'],['false','Por rever']]} placeholder="Revisão" />
        <input type="date" value={dataIni} onChange={e => setDataIni(e.target.value)} style={{ ...CLIP_INPUT, width: 140 }} />
        <input type="date" value={dataFim} onChange={e => setDataFim(e.target.value)} style={{ ...CLIP_INPUT, width: 140 }} />
        <button type="button" className="btn-ai" onClick={onNew} style={{ marginLeft: 'auto', fontSize: 12 }}>+ Menção</button>
      </div>
      <div style={{ fontSize: 11, color: 'var(--text-dim)', marginBottom: 8, fontFamily: 'var(--font-mono)' }}>
        {loading ? 'A carregar…' : `${data.total || 0} menções`}
      </div>
      <div style={{ border: '1px solid var(--border)', borderRadius: 10, overflow: 'hidden', background: 'var(--bg-elev)' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse' }}>
          <thead>
            <tr style={{ background: 'var(--bg-sunken)' }}>
              {['Marca','Título','Fonte','Sentimento','País','Data','Reach','Crítico'].map(h => (
                <th key={h} style={CLIP_TH}>{h}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {(data.rows || []).map(r => (
              <tr key={r.id} onClick={() => onOpen(r.id)} style={{ cursor: 'pointer', borderTop: '1px solid var(--border)' }}
                onMouseEnter={e => { e.currentTarget.style.background = 'var(--bg-sunken)'; }}
                onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; }}>
                <td style={{ padding: '10px 12px' }}><ClipMarcaChip slug={r.marca_slug} /></td>
                <td style={{ padding: '10px 12px', fontSize: 12.5, fontWeight: 600, maxWidth: 280, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.titulo}</td>
                <td style={{ padding: '10px 12px', fontSize: 11, color: 'var(--text-muted)' }}>{r.fonte_nome || CLIP_FONTE_LABEL[r.fonte] || r.fonte}</td>
                <td style={{ padding: '10px 12px' }}><ClipSentBadge sent={r.sentimento} /></td>
                <td style={{ padding: '10px 12px', fontSize: 11, fontFamily: 'var(--font-mono)' }}>{r.pais || '—'}</td>
                <td style={{ padding: '10px 12px', fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-muted)' }}>{clipFmtDate(r.data_publicacao)}</td>
                <td style={{ padding: '10px 12px', fontSize: 11, fontFamily: 'var(--font-mono)' }}>{r.reach_estimado ?? '—'}</td>
                <td style={{ padding: '10px 12px' }}>{r.is_critical ? <ClipBadge label="Sim" color="var(--danger)" bg="color-mix(in oklch, var(--danger) 14%, transparent)" /> : <span style={{ color: 'var(--text-dim)' }}>—</span>}</td>
              </tr>
            ))}
            {!loading && !(data.rows || []).length && (
              <tr><td colSpan={8} style={{ padding: 28, textAlign: 'center', color: 'var(--text-muted)', fontSize: 12 }}>Sem menções com estes filtros.</td></tr>
            )}
          </tbody>
        </table>
      </div>
      {data.total > 50 && (
        <div style={{ display: 'flex', gap: 8, marginTop: 10, alignItems: 'center' }}>
          <button type="button" disabled={offset === 0} onClick={() => setOffset(o => Math.max(0, o - 50))} style={{ padding: '5px 10px', borderRadius: 6, border: '1px solid var(--border)', background: 'var(--bg-elev)', cursor: 'pointer' }}>Anterior</button>
          <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)' }}>{offset + 1}–{Math.min(offset + 50, data.total)} / {data.total}</span>
          <button type="button" disabled={offset + 50 >= data.total} onClick={() => setOffset(o => o + 50)} style={{ padding: '5px 10px', borderRadius: 6, border: '1px solid var(--border)', background: 'var(--bg-elev)', cursor: 'pointer' }}>Seguinte</button>
        </div>
      )}
    </div>
  );
};

const ClipTabSov = ({ marcaCtx }) => {
  const [periodo, setPeriodo] = React.useState('30d');
  const [canal, setCanal] = React.useState('');
  const [data, setData] = React.useState(null);
  const [relatorio, setRelatorio] = React.useState(null);
  const [busy, setBusy] = React.useState(false);

  const load = React.useCallback(() => {
    const p = clipQs({ marca: marcaCtx && marcaCtx !== 'todas' ? marcaCtx : undefined, periodo, canal: canal || undefined });
    ClipAPI.sov(p).then(setData).catch(() => setData(null));
  }, [marcaCtx, periodo, canal]);
  React.useEffect(() => { load(); }, [load]);

  const focus = (data?.marcas || [])[0];
  const slices = (focus?.breakdown || []).map(s => ({
    ...s,
    color: s.is_marca ? (CLIP_MARCA_TOKEN[s.slug] || 'var(--ai-500)') : 'var(--text-dim)',
  }));

  async function gerar() {
    setBusy(true);
    try {
      const rel = await ClipAPI.gerarRel({
        marca_slug: marcaCtx && marcaCtx !== 'todas' ? marcaCtx : null,
        tipo: periodo === '7d' ? 'semanal' : periodo === '90d' ? 'mensal' : 'ad_hoc',
      });
      setRelatorio(rel);
    } catch (e) { alert(e.message); }
    finally { setBusy(false); }
  }

  const evolDays = [...new Set((data?.evolucao || []).map(e => String(e.dia).slice(0, 10)))].sort();

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
        {['7d','30d','90d'].map(p => (
          <button key={p} type="button" onClick={() => setPeriodo(p)} style={{
            padding: '4px 10px', borderRadius: 6, fontSize: 11, fontWeight: 600, cursor: 'pointer',
            border: '1px solid var(--border)',
            background: periodo === p ? 'var(--ai-500)' : 'var(--bg-elev)',
            color: periodo === p ? 'var(--bg-elev)' : 'var(--text-muted)',
          }}>{p}</button>
        ))}
        <ClipSelect value={canal} onChange={setCanal} options={[['web','Web'],['social','Social'],['imprensa','Imprensa']]} placeholder="Canal" />
        <button type="button" className="btn-ai" disabled={busy} onClick={gerar} style={{ marginLeft: 'auto', fontSize: 12 }}>
          {busy ? 'A gerar…' : 'Gerar relatório'}
        </button>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '220px 1fr', gap: 20, alignItems: 'center' }}>
        <ClipPie slices={slices} />
        <div>
          {(focus?.breakdown || []).map(s => (
            <div key={s.slug} style={{ display: 'flex', justifyContent: 'space-between', padding: '6px 0', borderBottom: '1px solid var(--border)', fontSize: 12 }}>
              <span style={{ fontWeight: s.is_marca ? 700 : 500 }}>{s.is_marca ? (CLIP_MARCA_LABEL[s.slug] || s.slug) : s.slug}</span>
              <span style={{ fontFamily: 'var(--font-mono)' }}>{s.n} · {s.pct}%</span>
            </div>
          ))}
          {focus && <div style={{ marginTop: 8, fontSize: 12, color: 'var(--text-muted)' }}>SoV marca: <strong style={{ color: 'var(--text)' }}>{focus.marca_pct}%</strong></div>}
        </div>
      </div>

      <div>
        <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em', marginBottom: 8 }}>EVOLUÇÃO</div>
        <div style={{ border: '1px solid var(--border)', borderRadius: 10, overflow: 'hidden' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead>
              <tr style={{ background: 'var(--bg-sunken)' }}>
                <th style={CLIP_TH}>Dia</th>
                <th style={CLIP_TH}>Marca</th>
                <th style={CLIP_TH}>Concorrentes</th>
              </tr>
            </thead>
            <tbody>
              {evolDays.map(dia => {
                const rows = (data?.evolucao || []).filter(e => String(e.dia).slice(0, 10) === dia);
                const nM = rows.filter(r => r.sujeito_tipo === 'marca').reduce((a, r) => a + r.n, 0);
                const nC = rows.filter(r => r.sujeito_tipo === 'concorrente').reduce((a, r) => a + r.n, 0);
                return (
                  <tr key={dia} style={{ borderTop: '1px solid var(--border)' }}>
                    <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', fontSize: 11 }}>{clipFmtDate(dia)}</td>
                    <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', fontSize: 12 }}>{nM}</td>
                    <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', fontSize: 12 }}>{nC}</td>
                  </tr>
                );
              })}
              {!evolDays.length && <tr><td colSpan={3} style={{ padding: 20, textAlign: 'center', color: 'var(--text-muted)', fontSize: 12 }}>Sem evolução no período.</td></tr>}
            </tbody>
          </table>
        </div>
      </div>

      {relatorio && (
        <div style={{ padding: 16, borderRadius: 10, border: '1px solid var(--border)', background: 'var(--bg-sunken)' }}>
          <div style={{ ...CLIP_LABEL, color: 'var(--ai-500)' }}>Resumo AI</div>
          <div style={{ fontSize: 13, lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{relatorio.resumo_ai}</div>
        </div>
      )}
    </div>
  );
};

const ClipTabConcorrencia = ({ marcaCtx, onOpenMencao }) => {
  const [rows, setRows] = React.useState([]);
  const [nome, setNome] = React.useState('');
  const [url, setUrl] = React.useState('');
  const [marcaAdd, setMarcaAdd] = React.useState('mimaki');
  const [busy, setBusy] = React.useState(false);

  const load = React.useCallback(() => {
    ClipAPI.concorrencia(clipQs({ marca: marcaCtx && marcaCtx !== 'todas' ? marcaCtx : undefined }))
      .then(d => setRows(d.rows || [])).catch(() => setRows([]));
  }, [marcaCtx]);
  React.useEffect(() => { load(); }, [load]);

  const grouped = {};
  for (const r of rows) {
    if (!grouped[r.marca_slug]) grouped[r.marca_slug] = [];
    grouped[r.marca_slug].push(r);
  }
  const brands = marcaCtx && marcaCtx !== 'todas' ? [marcaCtx] : CLIP_MARCAS.map(m => m.slug);

  async function add() {
    if (!nome.trim()) return;
    setBusy(true);
    try {
      await ClipAPI.addConc({ marca_slug: marcaAdd, concorrente_slug: nome, concorrente_url: url || null });
      setNome(''); setUrl(''); load();
    } catch (e) { alert(e.message); }
    finally { setBusy(false); }
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'flex-end' }}>
        <div><label style={CLIP_LABEL}>Marca</label>
          <select value={marcaAdd} onChange={e => setMarcaAdd(e.target.value)} style={{ ...CLIP_INPUT, width: 140 }}>
            {CLIP_MARCAS.map(m => <option key={m.slug} value={m.slug}>{m.label}</option>)}
          </select></div>
        <div><label style={CLIP_LABEL}>Concorrente</label>
          <input value={nome} onChange={e => setNome(e.target.value)} placeholder="Nome" style={{ ...CLIP_INPUT, width: 180 }} /></div>
        <div><label style={CLIP_LABEL}>URL</label>
          <input value={url} onChange={e => setUrl(e.target.value)} placeholder="https://…" style={{ ...CLIP_INPUT, width: 220 }} /></div>
        <button type="button" className="btn-ai" disabled={busy} onClick={add} style={{ fontSize: 12 }}>+ Adicionar</button>
      </div>
      {brands.map(slug => (
        <div key={slug}>
          <div style={{ marginBottom: 8 }}><ClipMarcaChip slug={slug} /></div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 10 }}>
            {(grouped[slug] || []).map(c => (
              <div key={c.id} style={{ padding: 12, borderRadius: 10, border: '1px solid var(--border)', background: 'var(--bg-elev)' }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
                  <div style={{ fontWeight: 700, fontSize: 13 }}>{c.concorrente_slug}</div>
                  <button type="button" onClick={async () => { await ClipAPI.patchConc(c.id, { monitorizar: !c.monitorizar }); load(); }} style={{
                    fontSize: 10, fontFamily: 'var(--font-mono)', padding: '3px 8px', borderRadius: 99, cursor: 'pointer',
                    border: '1px solid var(--border)',
                    background: c.monitorizar ? 'color-mix(in oklch, var(--success) 14%, transparent)' : 'var(--bg-sunken)',
                    color: c.monitorizar ? 'var(--success)' : 'var(--text-dim)',
                  }}>{c.monitorizar ? 'ON' : 'OFF'}</button>
                </div>
                <div style={{ fontSize: 11, color: 'var(--text-muted)', marginBottom: 8 }}>
                  {c.n_mencoes} menções · sentimento {c.sentimento_medio}
                </div>
                {(c.ultimas || []).map(u => (
                  <div key={u.id} onClick={() => onOpenMencao(u.id)} style={{
                    fontSize: 12, padding: '4px 0', cursor: 'pointer', color: 'var(--ai-500)',
                    overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                  }}>{u.titulo}</div>
                ))}
              </div>
            ))}
            {!(grouped[slug] || []).length && (
              <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Sem concorrentes.</div>
            )}
          </div>
        </div>
      ))}
    </div>
  );
};

const ClipTabAlertas = ({ userName, onOpenMencao }) => {
  const [rows, setRows] = React.useState([]);
  const [disparos, setDisparos] = React.useState([]);
  const [modal, setModal] = React.useState(null);

  const load = React.useCallback(() => {
    ClipAPI.alertas().then(d => setRows(d.rows || [])).catch(() => setRows([]));
    ClipAPI.disparos().then(d => setDisparos(d.rows || [])).catch(() => setDisparos([]));
  }, []);
  React.useEffect(() => { load(); }, [load]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between' }}>
        <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em' }}>ALERTAS CONFIGURADOS</div>
        <button type="button" className="btn-ai" onClick={() => setModal({})} style={{ fontSize: 12 }}>+ Alerta</button>
      </div>
      <div style={{ border: '1px solid var(--border)', borderRadius: 10, overflow: 'hidden' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse' }}>
          <thead>
            <tr style={{ background: 'var(--bg-sunken)' }}>
              {['Nome','Tipo','Marca','Regra','Destinatários','Último','Total',''].map(h => <th key={h} style={CLIP_TH}>{h}</th>)}
            </tr>
          </thead>
          <tbody>
            {rows.map(a => (
              <tr key={a.id} style={{ borderTop: '1px solid var(--border)' }}>
                <td style={{ padding: '10px 12px', fontWeight: 600, fontSize: 12 }}>{a.nome}{!a.activo && <span style={{ color: 'var(--text-dim)', marginLeft: 6 }}>(off)</span>}</td>
                <td style={{ padding: '10px 12px', fontSize: 11 }}>{CLIP_ALERT_TIPOS.find(t => t[0] === a.tipo)?.[1] || a.tipo}</td>
                <td style={{ padding: '10px 12px' }}>{a.marca_slug ? <ClipMarcaChip slug={a.marca_slug} /> : '—'}</td>
                <td style={{ padding: '10px 12px', fontSize: 11, fontFamily: 'var(--font-mono)' }}>
                  {a.tipo === 'keyword' ? a.keyword : a.tipo === 'volume_pico' ? `> ${a.threshold_volume}` : a.tipo === 'sentiment_negativo' ? `< ${a.threshold_sentiment}` : a.tipo}
                </td>
                <td style={{ padding: '10px 12px', fontSize: 11, color: 'var(--text-muted)' }}>{(a.destinatarios || []).join(', ') || '—'}</td>
                <td style={{ padding: '10px 12px', fontSize: 11, fontFamily: 'var(--font-mono)' }}>{clipFmtDate(a.ultimo_disparo)}</td>
                <td style={{ padding: '10px 12px', fontFamily: 'var(--font-mono)', fontSize: 12 }}>{a.total_disparos || 0}</td>
                <td style={{ padding: '10px 12px', whiteSpace: 'nowrap' }}>
                  <button type="button" onClick={() => setModal(a)} style={{ fontSize: 11, marginRight: 6, cursor: 'pointer', border: '1px solid var(--border)', borderRadius: 5, background: 'var(--bg-elev)', color: 'var(--text)', padding: '3px 8px' }}>Editar</button>
                  <button type="button" onClick={async () => { await ClipAPI.patchAlerta(a.id, { activo: !a.activo }); load(); }} style={{ fontSize: 11, marginRight: 6, cursor: 'pointer', border: '1px solid var(--border)', borderRadius: 5, background: 'var(--bg-elev)', color: 'var(--text)', padding: '3px 8px' }}>{a.activo ? 'Off' : 'On'}</button>
                  <button type="button" onClick={async () => { if (confirm('Eliminar alerta?')) { await ClipAPI.delAlerta(a.id); load(); } }} style={{ fontSize: 11, cursor: 'pointer', border: '1px solid var(--border)', borderRadius: 5, background: 'var(--bg-elev)', color: 'var(--danger)', padding: '3px 8px' }}>Apagar</button>
                </td>
              </tr>
            ))}
            {!rows.length && <tr><td colSpan={8} style={{ padding: 24, textAlign: 'center', color: 'var(--text-muted)', fontSize: 12 }}>Nenhum alerta. Cria um para crises e keywords.</td></tr>}
          </tbody>
        </table>
      </div>

      <div>
        <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em', marginBottom: 8 }}>DISPAROS RECENTES</div>
        {disparos.map(d => (
          <div key={d.id} style={{
            display: 'flex', gap: 10, alignItems: 'center', padding: '8px 0',
            borderBottom: '1px solid var(--border)', fontSize: 12,
          }}>
            {d.is_critical && <ClipBadge label="Crítico" color="var(--danger)" bg="color-mix(in oklch, var(--danger) 14%, transparent)" />}
            <span style={{ fontWeight: 600 }}>{d.alerta_nome}</span>
            <button type="button" onClick={() => onOpenMencao(d.mencao_id)} style={{
              background: 'none', border: 'none', color: 'var(--ai-500)', cursor: 'pointer', fontSize: 12, textAlign: 'left',
            }}>{d.mencao_titulo}</button>
            <span style={{ marginLeft: 'auto', fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', fontSize: 11 }}>{clipFmtDate(d.disparado_em)}</span>
            {!d.acknowledged_at && (
              <button type="button" onClick={async () => { await ClipAPI.ack(d.alerta_id, { mencao_id: d.mencao_id, acknowledged_by: userName }); load(); }} style={{
                fontSize: 11, padding: '3px 8px', borderRadius: 5, cursor: 'pointer',
                border: '1px solid var(--border)', background: 'var(--bg-elev)', color: 'var(--text)',
              }}>Ack</button>
            )}
          </div>
        ))}
        {!disparos.length && <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Sem disparos.</div>}
      </div>

      {modal && (
        <ClipAlertaModal initial={modal.id ? modal : null} onClose={() => setModal(null)} onSaved={() => { setModal(null); load(); }} userName={userName} />
      )}
    </div>
  );
};

const MktClippingScreen = ({ userName }) => {
  const { brand: marcaCtx = 'todas' } = window.useMktBrand();

  const [tab, setTab] = React.useState(() => {
    try {
      if (localStorage.getItem('mkt-inicio-clipping-criticas') || localStorage.getItem('mkt-open-clipping-id')) return 'mencoes';
    } catch {}
    return 'observatorio';
  });
  const [periodo, setPeriodo] = React.useState('30d');
  const [dash, setDash] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  window.useMktZoneLoading(loading && !dash);
  const [collecting, setCollecting] = React.useState(false);
  const [drawerId, setDrawerId] = React.useState(() => {
    try {
      const id = localStorage.getItem('mkt-open-clipping-id');
      if (id) { localStorage.removeItem('mkt-open-clipping-id'); return id; }
    } catch {}
    return null;
  });
  const [showNova, setShowNova] = React.useState(() => {
    try { return !!(window.__mktInicioNovaMencao || localStorage.getItem('mkt-inicio-nova-mencao')); } catch {}
    return false;
  });
  const [mencoesPing, setMencoesPing] = React.useState(0);
  const [clipStatus, setClipStatus] = React.useState(null);

  const loadDash = React.useCallback(() => {
    setLoading(true);
    ClipAPI.dashboard(clipQs({ marca: marcaCtx !== 'todas' ? marcaCtx : undefined, periodo }))
      .then(d => { setDash(d); setLoading(false); })
      .catch(() => setLoading(false));
  }, [marcaCtx, periodo]);
  React.useEffect(() => { loadDash(); }, [loadDash]);
  React.useEffect(() => { ClipAPI.status().then(setClipStatus).catch(() => {}); }, []);
  React.useEffect(() => {
    if (!(window.__mktInicioNovaMencao || (typeof localStorage !== 'undefined' && localStorage.getItem('mkt-inicio-nova-mencao')))) return;
    setShowNova(true);
    const t = setTimeout(() => {
      window.__mktInicioNovaMencao = false;
      try { localStorage.removeItem('mkt-inicio-nova-mencao'); } catch {}
    }, 600);
    return () => clearTimeout(t);
  }, []);

  const tabs = [
    { id: 'observatorio', label: 'Observatório' },
    { id: 'mencoes', label: 'Menções' },
    { id: 'sov', label: 'Share of Voice' },
    { id: 'concorrencia', label: 'Concorrência' },
    { id: 'alertas', label: 'Alertas' },
  ];

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', minHeight: 0, background: 'var(--bg)' }}>
      <div style={{ background: 'var(--bg-elev)', borderBottom: '1px solid var(--border)', padding: '20px 40px 0', flexShrink: 0 }}>
        <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.07em', color: 'var(--text-muted)', textTransform: 'uppercase', marginBottom: 6, fontFamily: 'var(--font-mono)' }}>
          MARKETING · CLIPPING
        </div>
        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16 }}>
          <div>
            <h1 style={{ margin: 0, fontSize: 21, fontWeight: 700, color: 'var(--text)', fontFamily: 'var(--font-display)', letterSpacing: '-0.01em' }}>
              Observatório
            </h1>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 4 }}>
              O que o mercado diz — e o que fazemos com isso na comunicação.
            </div>
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <button type="button" onClick={() => setShowNova(true)} className="btn-ai" style={{ fontSize: 12, height: 32, padding: '0 14px' }}>+ Menção</button>
          </div>
        </div>
        <div style={{ height: 1, background: 'var(--border)', margin: '16px -40px 0' }} />
        <div style={{ display: 'flex', gap: 0 }}>
          {tabs.map(t => {
            const active = tab === t.id;
            return (
              <button key={t.id} type="button" onClick={() => setTab(t.id)} style={{
                background: 'none', border: 'none', outline: 'none',
                borderBottom: `2px solid ${active ? 'var(--ai-500)' : 'transparent'}`,
                color: active ? 'var(--text)' : 'var(--text-muted)',
                fontSize: 13, fontWeight: active ? 600 : 500,
                fontFamily: 'var(--font-display)', padding: '10px 18px 12px', cursor: 'pointer',
              }}>{t.label}</button>
            );
          })}
        </div>
      </div>

      <div className="scrollbar" style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '24px 40px 40px' }}>
        {tab === 'observatorio' && (
          <ClipTabObservatorio
            data={dash} loading={loading} periodo={periodo} setPeriodo={setPeriodo}
            onOpenMencao={setDrawerId}
            collecting={collecting}
            clipStatus={clipStatus}
            onCollect={async () => {
              setCollecting(true);
              try {
                await ClipAPI.collect();
                for (let i = 0; i < 90; i++) {
                  await new Promise(r => setTimeout(r, 2000));
                  const s = await ClipAPI.status();
                  setClipStatus(s);
                  if (!s.running) break;
                }
                loadDash();
                setMencoesPing(p => p + 1);
              } catch (e) { alert(e.message); }
              finally { setCollecting(false); }
            }}
            onInsight={async (id, action) => {
              await ClipAPI.patchInsight(id, action);
              loadDash();
            }}
            onBriefing={async (id) => {
              try {
                const r = await ClipAPI.briefing(id, { created_by_name: userName });
                loadDash();
                if (r.briefing_id) {
                  try { localStorage.setItem('mkt-open-briefing-id', String(r.briefing_id)); } catch {}
                  alert(`Briefing #${r.briefing_id} criado em rascunho. Abre o ecrã Briefings.`);
                }
              } catch (e) { alert(e.message); }
            }}
          />
        )}
        {tab === 'mencoes' && (
          <ClipTabMencoes marcaCtx={marcaCtx} onOpen={setDrawerId} onNew={() => setShowNova(true)} refreshPing={mencoesPing} />
        )}
        {tab === 'sov' && <ClipTabSov marcaCtx={marcaCtx} />}
        {tab === 'concorrencia' && <ClipTabConcorrencia marcaCtx={marcaCtx} onOpenMencao={setDrawerId} />}
        {tab === 'alertas' && <ClipTabAlertas userName={userName} onOpenMencao={setDrawerId} />}
      </div>

      {drawerId && (
        <ClipMencaoDrawer
          id={drawerId}
          userName={userName}
          onClose={() => setDrawerId(null)}
          onChanged={() => { loadDash(); setMencoesPing(p => p + 1); }}
        />
      )}
      {showNova && (
        <ClipNovaMencaoModal
          defaultMarca={marcaCtx}
          onClose={() => setShowNova(false)}
          onSaved={() => { setShowNova(false); loadDash(); setMencoesPing(p => p + 1); setTab('mencoes'); }}
        />
      )}
    </div>
  );
};

window.MktClippingScreen = MktClippingScreen;
