/* Marketing · Performance 2025
   Modo "Todas" → portfolio: funnel 3-stream + KPIs + leads-por-marca + ranking ROAS
   Modo single-brand → filtrado: funnel marca + KPIs marca + leads-por-campanha + top produtos */

// Mapeamento: id da marca no portal → id no MKT_PERF_DATA (Meta Ads)
const PERF_BRAND_MAP = { mimaki: 'digidelta', biond: 'biond', decal: 'decal', alldecor: 'alldecor' };
// Mapeamento: id da marca no portal → nome no ADS agent API
const ADS_BRAND_MAP = { mimaki: 'Digidelta', biond: 'BIOND', decal: 'Decal', alldecor: 'AllDecor' };

// ── DM Data (CRM funnel) — carregado dinamicamente, não requer alteração ao index.html ──
(function() {
  if (window.MKT_DM_DATA || document.querySelector('script[src*="screen_marketing_dm_data"]')) return;
  const s = document.createElement('script');
  s.src = 'js/screen_marketing_dm_data.js';
  s.onload = () => window.dispatchEvent(new CustomEvent('mkt-dm-loaded'));
  document.head.appendChild(s);
})();

// Retorna totais DM por marca — agregado + breakdown por fonte (ads/web/email)
function getDmTotals(portalBrandId) {
  const dm = window.MKT_DM_DATA;
  if (!dm) return null;
  const map = { mimaki: 'digidelta' };
  const key = map[portalBrandId];
  if (!key) return null;
  const t = dm[key]?.totals;
  if (!t) return null;
  return {
    // Agregado
    mql:        (t.ads?.mql      || 0) + (t.email?.mql      || 0) + (t.web?.mql      || 0),
    sql:        (t.ads?.sql      || 0) + (t.email?.sql      || 0) + (t.web?.sql      || 0),
    wins:       (t.ads?.wins     || 0) + (t.email?.wins     || 0) + (t.web?.wins     || 0),
    winValue:   (t.ads?.winValue || 0) + (t.email?.winValue || 0) + (t.web?.winValue || 0),
    emailLeads: t.email?.leads || 0,
    webLeads:   t.web?.leads   || 0,
    // Por fonte — para filtro no funnel
    bySource: {
      ads:   { mql: t.ads?.mql||0,   sql: t.ads?.sql||0,   wins: t.ads?.wins||0,   winValue: t.ads?.winValue||0 },
      email: { mql: t.email?.mql||0, sql: t.email?.sql||0, wins: t.email?.wins||0, winValue: t.email?.winValue||0, leads: t.email?.leads||0 },
      web:   { mql: t.web?.mql||0,   sql: t.web?.sql||0,   wins: t.web?.wins||0,   winValue: t.web?.winValue||0,  leads: t.web?.leads||0  },
    },
  };
}

// Agrega dados mensais de uma marca do MKT_PERF_DATA em totais YTD
function getRealBrandData(perfBrandId) {
  const d = (window.MKT_PERF_DATA || {})[perfBrandId];
  if (!d) return null;
  const rows = d.accountMonthly || [];
  if (!rows.length) return null;
  return rows.reduce((acc, r) => ({
    spend:       acc.spend       + r.spend,
    impressions: acc.impressions + r.impressions,
    reach:       acc.reach       + r.reach,
    clicks:      acc.clicks      + r.clicks,
    leads:       acc.leads       + (r.formLeads || 0) + (r.pixelLeads || 0),
  }), { spend: 0, impressions: 0, reach: 0, clicks: 0, leads: 0 });
}

// Totais reais do portfolio — só as marcas activas em PERF_BRAND_MAP
function getRealPortfolioData() {
  if (!window.MKT_PERF_DATA) return null;
  const acc = { spend: 0, impressions: 0, reach: 0, leads: 0 };
  for (const perfId of Object.values(PERF_BRAND_MAP)) {
    const d = window.MKT_PERF_DATA[perfId];
    if (!d) continue;
    for (const r of (d.accountMonthly || [])) {
      acc.spend       += r.spend;
      acc.impressions += r.impressions;
      acc.reach       += r.reach;
      acc.leads       += (r.formLeads || 0) + (r.pixelLeads || 0);
    }
  }
  return acc.leads > 0 || acc.spend > 0 ? acc : null;
}

// Dados efectivos por marca: Meta (leads, invest) + DM Report (ops, wins, faturacao, roas)
function getRealEffectiveNumbers() {
  const mock = window.MKT_BRAND_NUMBERS || {};
  if (!window.MKT_PERF_DATA) return mock;
  const zero = { leads: 0, ops: 0, wins: 0, faturacao: 0, roas: 0, invest: 0, cpl: 0 };
  const result = {};
  for (const portalId of Object.keys(mock)) {
    const perfId = PERF_BRAND_MAP[portalId];
    const real = perfId ? getRealBrandData(perfId) : null;
    const dm = getDmTotals(portalId);
    if (real) {
      const faturacao = dm ? dm.winValue : 0;
      const roas = faturacao > 0 && real.spend > 0 ? faturacao / real.spend : 0;
      result[portalId] = {
        ...zero,
        leads:    real.leads,
        invest:   real.spend,
        cpl:      real.leads > 0 ? real.spend / real.leads : 0,
        ops:      dm ? dm.sql  : (mock[portalId]?.ops  || 0),
        wins:     dm ? dm.wins : (mock[portalId]?.wins || 0),
        faturacao,
        roas,
      };
    } else {
      // Sem dados Meta reais — usa mock como fallback
      result[portalId] = { ...zero, ...(mock[portalId] || {}) };
    }
  }
  return result;
}

// Opens totais de email (Brevo) para uma marca
function getRealEmailOpens(perfBrandId) {
  const d = (window.MKT_PERF_DATA || {})[perfBrandId];
  return (d?.emailCampaigns || []).reduce((s, c) => s + c.opens, 0);
}

// Dados de funnel: Meta leads (ads) + leads CRM email/web + MQL/SQL/Wins do DM Report
function getRealFunnel(portalBrandId) {
  if (!window.MKT_PERF_DATA) return null;
  if (portalBrandId === 'todas') {
    const mockFunnel = window.MKT_BRAND_FUNNEL || {};
    let ads = 0, email = 0, web = 0, leads = 0, mql = 0, sql = 0, ops = 0, wins = 0;

    // bySource agregado — para filtro de stream em "todas"
    const bySourceAll = {
      ads:   { mql: 0, sql: 0, wins: 0, leads: 0 },
      email: { mql: 0, sql: 0, wins: 0, leads: 0 },
      web:   { mql: 0, sql: 0, wins: 0, leads: 0 },
    };

    // Agrega todas as marcas com dados Meta (PERF_BRAND_MAP)
    for (const [portalId, perfId] of Object.entries(PERF_BRAND_MAP)) {
      const r = getRealBrandData(perfId);
      const dm = getDmTotals(portalId);
      const brandAds   = r ? r.leads : 0;
      const brandEmail = dm ? dm.emailLeads : 0;
      const brandWeb   = dm ? dm.webLeads   : 0;
      ads   += brandAds;
      email += brandEmail;
      web   += brandWeb;
      leads += brandAds + brandEmail + brandWeb;
      if (dm) {
        mql += dm.mql; sql += dm.sql; ops += dm.sql; wins += dm.wins;
      } else {
        for (const c of getRealCampaigns(portalId) || []) {
          mql  += c.mql  || 0;
          sql  += c.sql  || 0;
          ops  += c.sql  || 0;
          wins += c.wins || 0;
        }
      }
      // Acumula bySource com dados exactos por canal
      if (dm?.bySource) {
        for (const src of ['ads', 'email', 'web']) {
          bySourceAll[src].mql   += dm.bySource[src]?.mql   || 0;
          bySourceAll[src].sql   += dm.bySource[src]?.sql   || 0;
          bySourceAll[src].wins  += dm.bySource[src]?.wins  || 0;
          bySourceAll[src].leads += dm.bySource[src]?.leads || 0;
        }
      }
    }
    // Corrige leads de ads com dados reais Meta (mais fiável que DM)
    bySourceAll.ads.leads = ads;
    return leads > 0 ? { ads, email, web, leads, mql, sql, ops, wins, bySource: bySourceAll } : null;
  }
  const perfId = PERF_BRAND_MAP[portalBrandId];
  if (!perfId) return null;
  const r = getRealBrandData(perfId);
  if (!r) return null;
  const dm = getDmTotals(portalBrandId);
  // Se não há DM totals, agrega MQL/SQL/Wins das campanhas (já enriquecidas via DM Report)
  let mql = 0, sql = 0, wins = 0;
  if (dm) {
    mql = dm.mql; sql = dm.sql; wins = dm.wins;
  } else {
    for (const c of getRealCampaigns(portalBrandId) || []) {
      mql  += c.mql  || 0;
      sql  += c.sql  || 0;
      wins += c.wins || 0;
    }
  }
  return {
    ads:   r.leads,
    email: dm ? dm.emailLeads : 0,
    web:   dm ? dm.webLeads   : 0,
    leads: r.leads + (dm ? dm.emailLeads + dm.webLeads : 0),
    mql,
    sql,
    ops:  sql,
    wins,
    bySource: dm ? { ...dm.bySource, ads: { ...dm.bySource.ads, leads: r.leads } } : null,
  };
}

// Correspondência ad name → produto (por ordem de prioridade — mais específico primeiro)
// Regra: padrões mais longos/específicos antes dos curtos; \b evita que JV apanhe CJV/UCJV.
const AD_PRODUCT_PATTERNS = {
  digidelta: [
    // UV-DTF (antes de qualquer UJV genérico)
    { rx: /UJV.?300.*DTF|UJV300DTF/i,    nome: 'UJV300DTF-75' },
    // UV LED Print & Cut — UCJV (antes de CJV e JV)
    { rx: /UCJV.?330/i,                   nome: 'UCJV330-160' },
    { rx: /UCJV.?300/i,                   nome: 'UCJV300-160' },
    // UV LED Flatbed híbrido (\b evita match dentro de UCJV330)
    { rx: /\bUJ.{0,2}330/i,              nome: 'UJ-330H' },
    // UV LED rolo (\b evita match em UCJV/UJF)
    { rx: /\bUJV.?100/i,                  nome: 'UJV100-160 Plus' },
    { rx: /\bUJV.?200/i,                  nome: 'UJV200-160' },
    { rx: /\bUJV.?55/i,                   nome: 'UJV55-320' },
    // UV LED Flatbed compacto
    { rx: /UJF.?715/i,                    nome: 'UJF-7151 Plus' },
    { rx: /UJF.?604/i,                    nome: 'UJF-6042MkII' },
    { rx: /UJF.?304/i,                    nome: 'UJF-3042MkII' },
    // Industrial flatbed (JFX — antes de JV)
    { rx: /JFX.?600/i,                    nome: 'JFX600' },
    { rx: /JFX.?500/i,                    nome: 'JFX500' },
    { rx: /JFX.?200/i,                    nome: 'JFX200' },
    // Eco-solvente Print & Cut (CJV — antes de JV)
    { rx: /\bCJV.?330/i,                  nome: 'CJV330-160' },
    { rx: /\bCJV.?200/i,                  nome: 'CJV200-160' },
    // Eco-solvente rolo (\b evita match em CJV/UCJV)
    { rx: /\bJV.?330/i,                   nome: 'JV330-160' },
    { rx: /\bJV.?200/i,                   nome: 'JV200-160' },
    { rx: /\bJV.?100/i,                   nome: 'JV100-160' },
    // Têxtil sublimação
    { rx: /TIGER.?600/i,                  nome: 'Tiger600-1800TS' },
    { rx: /\bTS.?330/i,                   nome: 'TS330-1600' },
    { rx: /\bTS.?200/i,                   nome: 'TS200-1600' },
    { rx: /\bTS.?100/i,                   nome: 'TS100-1600' },
    { rx: /\bTS.?55/i,                    nome: 'TS55-1800' },
    // DTF / Pigmento
    { rx: /TxF.?300/i,                    nome: 'TxF300-75' },
    { rx: /TxF.?150/i,                    nome: 'TxF150-75' },
    { rx: /\bTX.?330/i,                   nome: 'TX330-1800' },
    // Têxtil genérico — fallback depois de todos os modelos específicos
    { rx: /Home.?Textile/i,               nome: 'Têxtil · Home' },
    { rx: /Sportswear/i,                  nome: 'Têxtil · Sportswear' },
    { rx: /Leather|Footwear/i,            nome: 'Têxtil · Leather & Footwear' },
    { rx: /Swimwear/i,                    nome: 'Têxtil · Swimwear' },
    { rx: /T[êe]xtil/i,                   nome: 'Têxtil · Outros' },
  ],
  decal: [
    { rx: /FESPA/i,            nome: 'FESPA 2026' },
    { rx: /Awarness|Awareness/i, nome: 'Awareness decal®' },
  ],
  biond: [
    { rx: /FESPA/i,            nome: 'FESPA 2026' },
    { rx: /INSTAGRAM|FOLLOW/i, nome: 'Instagram Growth' },
    { rx: /PRINTER|TRAFEGO/i,  nome: 'Tráfego Website' },
  ],
  alldecor: [
    { rx: /Workshop/i, nome: 'Workshop AllDecor' },
  ],
};

// Produtos reais derivados dos nomes dos anúncios Meta (nível ad)
function getRealProducts(portalBrandId) {
  const perfId = PERF_BRAND_MAP[portalBrandId];
  if (!perfId) return null;
  const d = (window.MKT_PERF_DATA || {})[perfId];
  const ads = d?.adsYtd;
  if (!ads?.length) return null;
  const patterns = AD_PRODUCT_PATTERNS[perfId];
  if (!patterns?.length) return null;

  const byProduct = {};
  for (const ad of ads) {
    const leads = (ad.formLeads || 0) + (ad.pixelLeads || 0);
    const match = patterns.find(p => p.rx.test(ad.adName));
    if (!match) continue;
    const key = match.nome;
    if (!byProduct[key]) byProduct[key] = { nome: key, leads: 0, spend: 0 };
    byProduct[key].leads += leads;
    byProduct[key].spend += (ad.spend || 0);
  }

  const result = Object.values(byProduct)
    .filter(p => p.leads > 0 || p.spend > 0)
    .sort((a, b) => b.leads - a.leads || b.spend - a.spend);
  return result.length ? result : null;
}

// Campanhas reais: Meta Ads (leads + spend) enriquecidas com DM Report (MQL, SQL, Wins, WinValue)
function getRealCampaigns(portalBrandId) {
  const perfId = PERF_BRAND_MAP[portalBrandId];
  if (!perfId) return null;
  const d = (window.MKT_PERF_DATA || {})[perfId];
  if (!d) return null;

  // Agrega por nome de campanha (Meta)
  const byName = {};
  for (const c of d.campaignsMonthly || []) {
    if (!byName[c.name]) byName[c.name] = { nome: c.name, canal: 'Meta Ads', leads: 0, spend: 0, mql: 0, sql: 0, wins: 0, winValue: 0, roas: 0 };
    byName[c.name].leads += (c.formLeads || 0) + (c.pixelLeads || 0);
    byName[c.name].spend += c.spend;
  }

  // Enriquece com DM Report — match por nome de campanha (exacto ou parcial)
  const dmCampaigns = window.MKT_DM_DATA?.digidelta?.campaigns || {};
  for (const camp of Object.values(byName)) {
    // Tentativa de match exacto primeiro, depois parcial
    const dmKey = Object.keys(dmCampaigns).find(k =>
      k === camp.nome ||
      camp.nome.includes(k) ||
      k.includes(camp.nome)
    );
    if (dmKey) {
      const dm = dmCampaigns[dmKey];
      camp.mql      = dm.mql      || 0;
      camp.sql      = dm.sql      || 0;
      camp.wins     = dm.wins     || 0;
      camp.winValue = dm.winValue || 0;
      // ROAS = Win Value / Investimento Meta (mais preciso que o do Excel)
      camp.roas = camp.winValue > 0 && camp.spend > 0 ? camp.winValue / camp.spend : 0;
    }
  }

  const result = Object.values(byName).filter(c => c.leads > 0 || c.spend > 0);
  return result.length ? result.sort((a, b) => b.leads - a.leads).slice(0, 10) : null;
}

const fmtEur = (n) => {
  if (n == null) return '—';
  if (n >= 1000000) return '€' + (n/1000000).toFixed(2).replace('.', ',') + 'M';
  if (n >= 1000) return '€' + Math.round(n/1000) + 'k';
  return '€' + n;
};
const fmtN = (n) => n == null ? '—' : new Intl.NumberFormat('pt-PT').format(n);

// ============================================================================
// 3-stream convergent funnel (ADS + EMAIL + WEB → LEADS → MQL → SQL → OPs → WINS)
// ============================================================================
const PerfFunnel = ({ data, color, label }) => {
  const [sel, setSel] = React.useState(null); // 'ads' | 'email' | 'web' | null

  const streams = [
    { key: 'ads',   label: 'Ads',     color: '#dc2626', y: 30 },
    { key: 'email', label: 'Email',   color: '#059669', y: 110 },
    { key: 'web',   label: 'Website', color: '#6b7280', y: 190 },
  ];

  // Dados filtrados pela stream seleccionada
  const d = React.useMemo(() => {
    if (!sel) return data;
    // Com bySource (Mimaki) — dados exactos por canal
    if (data.bySource?.[sel]) {
      const s = data.bySource[sel];
      const leads = sel === 'ads' ? data.ads : (s.leads || 0);
      return {
        ads:   sel === 'ads'   ? data.ads   : 0,
        email: sel === 'email' ? data.email : 0,
        web:   sel === 'web'   ? data.web   : 0,
        leads,
        mql:  s.mql  || 0,
        sql:  s.sql  || 0,
        ops:  s.sql  || 0,
        wins: s.wins || 0,
      };
    }
    // Sem bySource (outras marcas) — distribui proporcionalmente pela quota de leads
    const streamLeads = data[sel] || 0;
    const totalLeads = Math.max(data.leads, 1);
    const ratio = streamLeads / totalLeads;
    return {
      ads:   sel === 'ads'   ? data.ads   : 0,
      email: sel === 'email' ? data.email : 0,
      web:   sel === 'web'   ? data.web   : 0,
      leads: streamLeads,
      mql:   Math.round((data.mql  || 0) * ratio),
      sql:   Math.round((data.sql  || 0) * ratio),
      ops:   Math.round((data.ops  || 0) * ratio),
      wins:  Math.round((data.wins || 0) * ratio),
    };
  }, [sel, data]);

  const W = 720, H = 220;

  const stages = [
    { key: 'leads', label: 'Leads', x: 320, w: 80 },
    { key: 'mql',   label: 'MQL',   x: 420, w: 70 },
    { key: 'sql',   label: 'SQL',   x: 510, w: 60 },
    { key: 'ops',   label: 'OPs',   x: 590, w: 60 },
    { key: 'wins',  label: 'Wins',  x: 670, w: 50 },
  ];

  const maxStream = Math.max(d.ads, d.email, d.web, 1);
  const streamHeight = (v) => 12 + (v / maxStream) * 36;

  return (
    <div style={{
      padding: '16px 20px',
      background: 'var(--bg-elev)',
      border: '1px solid var(--border)',
      borderRadius: 10,
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
        <div className="font-display" style={{ fontSize: 14, fontWeight: 600 }}>Funnel · {label}</div>
        <div style={{ display: 'flex', gap: 4 }}>
          {streams.map(s => (
            <button key={s.key} onClick={() => setSel(sel === s.key ? null : s.key)} style={{
              padding: '2px 10px', borderRadius: 999, fontSize: 10.5,
              fontFamily: 'var(--font-mono)', cursor: 'pointer', border: '1px solid',
              borderColor: sel === s.key ? s.color : 'var(--border)',
              background: sel === s.key ? `color-mix(in oklch, ${s.color} 15%, transparent)` : 'transparent',
              color: sel === s.key ? s.color : 'var(--text-dim)',
              transition: 'all .15s',
            }}>{s.label.toUpperCase()}</button>
          ))}
          {sel && <button onClick={() => setSel(null)} style={{
            padding: '2px 8px', borderRadius: 999, fontSize: 10.5,
            fontFamily: 'var(--font-mono)', cursor: 'pointer',
            border: '1px solid var(--border)', background: 'transparent', color: 'var(--text-dim)',
          }}>✕ Todos</button>}
        </div>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: 'block' }}>
        {/* Streams entrando */}
        {streams.map((s, i) => {
          const v = d[s.key];
          const isActive = !sel || sel === s.key;
          const h = streamHeight(v);
          return (
            <g key={s.key} style={{ cursor: 'pointer' }} onClick={() => setSel(sel === s.key ? null : s.key)}>
              <path
                d={`M 0 ${s.y} L 60 ${s.y} L 320 ${110 - h/2 + (i * h/3)} L 320 ${110 + h/2 + ((i-1) * h/3)} L 60 ${s.y + h/2} L 0 ${s.y + h/2} Z`}
                fill={s.color}
                opacity={isActive ? 0.35 : 0.08}
              />
              <rect x="6" y={s.y - 12} width="110" height="32" rx="6"
                fill="var(--bg-sunken)"
                stroke={s.color} strokeOpacity={isActive ? 0.6 : 0.2} />
              <circle cx="20" cy={s.y + 4} r="3.5" fill={s.color} opacity={isActive ? 1 : 0.3} />
              <text x="32" y={s.y + 1} fontSize="10" fill={isActive ? 'var(--text-dim)' : 'var(--text-dim)'} fontFamily="var(--font-mono)" letterSpacing="0.04em" opacity={isActive ? 1 : 0.4}>{s.label.toUpperCase()}</text>
              <text x="32" y={s.y + 14} fontSize="13" fontWeight="600" fill={isActive ? 'var(--text)' : 'var(--text-dim)'} fontFamily="var(--font-display)" opacity={isActive ? 1 : 0.4}>{fmtN(v)}</text>
            </g>
          );
        })}

        {/* Stages — funnel narrowing */}
        {stages.map((st, i) => {
          const maxVal = Math.max(d.leads, d.mql, d.sql, d.ops, d.wins, 1);
          const v = d[st.key];
          const prev = i === 0 ? (d.ads + d.email + d.web) : d[stages[i-1].key];
          const ratio = prev > 0 ? v / prev : 1;
          const h = 30 + 80 * (v / maxVal);
          return (
            <g key={st.key}>
              <rect
                x={st.x} y={110 - h/2}
                width={st.w} height={h}
                rx="6"
                fill={i === stages.length - 1 ? color : `color-mix(in oklch, ${color} ${20 + i * 10}%, var(--bg-sunken))`}
                stroke={i === stages.length - 1 ? color : 'none'}
                strokeWidth="1"
              />
              <text x={st.x + st.w/2} y={110 - h/2 - 6} textAnchor="middle"
                fontSize="9.5" fill="var(--text-dim)" fontFamily="var(--font-mono)" letterSpacing="0.06em">{st.label.toUpperCase()}</text>
              <text x={st.x + st.w/2} y={110 + 4} textAnchor="middle"
                fontSize="15" fontWeight="700" fill={i === stages.length - 1 ? '#fff' : 'var(--text)'} fontFamily="var(--font-display)">{fmtN(v)}</text>
              {i > 0 && (
                <text x={st.x + st.w/2} y={110 + h/2 + 14} textAnchor="middle"
                  fontSize="9" fill="var(--text-dim)" fontFamily="var(--font-mono)">{Math.round(ratio * 100)}%</text>
              )}
            </g>
          );
        })}
      </svg>
    </div>
  );
};

// ============================================================================
// KPIs strip (5 cards)
// ============================================================================
const PerfKpis = ({ kpis }) => (
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 10 }}>
    {kpis.map((k, i) => (
      <div key={i} style={{
        padding: '14px 16px',
        background: 'var(--bg-elev)',
        border: '1px solid var(--border)',
        borderRadius: 10,
        position: 'relative',
        overflow: 'hidden',
      }}>
        {k.accentColor && (
          <span style={{
            position: 'absolute', top: 0, left: 0, bottom: 0,
            width: 3, background: k.accentColor,
          }} />
        )}
        <div style={{ fontSize: 9.5, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>{k.label}</div>
        <div className="font-display" style={{ fontSize: 24, fontWeight: 600, lineHeight: 1.05, margin: '4px 0 4px', letterSpacing: '-0.015em' }}>{k.value}</div>
        <div style={{ fontSize: 11, color: k.tone === 'success' ? 'var(--success)' : k.tone === 'danger' ? 'var(--danger)' : 'var(--text-muted)' }}>{k.sub}</div>
      </div>
    ))}
  </div>
);

// ============================================================================
// "Leads por marca" stacked bar (Todas only) — 7 brands stack horizontalmente
// ============================================================================
const LeadsPorMarcaCard = ({ onPickBrand, numbers: numbersOverride }) => {
  const brands = (window.MKT_BRANDS || []).filter(b => b.id !== 'todas');
  const numbers = numbersOverride || window.MKT_BRAND_NUMBERS || {};
  const total = brands.reduce((a, b) => a + (numbers[b.id]?.leads || 0), 0);

  return (
    <div style={{
      padding: '16px 18px',
      background: 'var(--bg-elev)',
      border: '1px solid var(--border)',
      borderRadius: 10,
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 8 }}>
        <div className="font-display" style={{ fontSize: 14, fontWeight: 600 }}>Leads por marca · 2026</div>
        <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>Total {fmtN(total)}</div>
      </div>

      {/* Stacked horizontal bar */}
      <div style={{
        display: 'flex', height: 36, borderRadius: 6, overflow: 'hidden',
        border: '1px solid var(--border)', marginBottom: 12,
      }}>
        {brands.map(b => {
          const v = numbers[b.id]?.leads || 0;
          const pct = (v / total) * 100;
          return (
            <button
              key={b.id}
              onClick={() => onPickBrand(b.id)}
              title={`${b.nome}: ${v} leads (${pct.toFixed(1)}%)`}
              style={{
                width: `${pct}%`, height: '100%',
                background: b.cor, border: 'none', cursor: 'pointer',
                transition: 'opacity 0.15s', position: 'relative',
              }}
              onMouseEnter={e => e.currentTarget.style.opacity = '0.85'}
              onMouseLeave={e => e.currentTarget.style.opacity = '1'}
            >
              {pct > 8 && (
                <span style={{
                  position: 'absolute', inset: 0,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  fontSize: 10.5, fontWeight: 600, color: '#fff',
                  fontFamily: 'var(--font-display)',
                  letterSpacing: '0.02em',
                  textShadow: '0 1px 2px rgba(0,0,0,0.3)',
                }}>{b.nome}</span>
              )}
            </button>
          );
        })}
      </div>

      {/* Legend */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '4px 16px' }}>
        {brands.map(b => {
          const v = numbers[b.id]?.leads || 0;
          const pct = (v / total) * 100;
          return (
            <button key={b.id} onClick={() => onPickBrand(b.id)} style={{
              display: 'flex', alignItems: 'center', gap: 8, padding: '4px 0',
              border: 'none', background: 'transparent', cursor: 'pointer', textAlign: 'left',
            }}>
              <span style={{ width: 8, height: 8, borderRadius: '50%', background: b.cor, flexShrink: 0 }} />
              <span style={{ fontSize: 12, flex: 1 }}>{b.nome}</span>
              <span className="font-mono" style={{ fontSize: 11, color: 'var(--text-muted)' }}>{v} · {pct.toFixed(1)}%</span>
            </button>
          );
        })}
      </div>
    </div>
  );
};

// ============================================================================
// Top marcas por ROAS (ranking) — Todas only
// ============================================================================
const RankingROAS = ({ onPickBrand, numbers: numbersOverride }) => {
  const brands = (window.MKT_BRANDS || []).filter(b => b.id !== 'todas');
  const numbers = numbersOverride || window.MKT_BRAND_NUMBERS || {};
  const ranked = brands
    .map(b => ({ ...b, roas: numbers[b.id]?.roas || 0, fat: numbers[b.id]?.faturacao || 0 }))
    .sort((a, b) => b.roas - a.roas);
  const maxRoas = ranked[0]?.roas || 1;

  return (
    <div style={{
      padding: '16px 18px',
      background: 'var(--bg-elev)',
      border: '1px solid var(--border)',
      borderRadius: 10,
    }}>
      <div className="font-display" style={{ fontSize: 14, fontWeight: 600, marginBottom: 12 }}>Top marcas por ROAS</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        {ranked.map((b, i) => (
          <button key={b.id} onClick={() => onPickBrand(b.id)} style={{
            display: 'grid', gridTemplateColumns: '24px 1fr 60px 60px', gap: 10,
            alignItems: 'center', padding: '6px 8px', borderRadius: 6,
            border: 'none', background: 'transparent', cursor: 'pointer', textAlign: 'left',
            transition: 'background 0.12s',
          }}
          onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-hover)'}
          onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
            <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', fontWeight: 700 }}>{String(i+1).padStart(2, '0')}</span>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
              <span style={{ width: 8, height: 8, borderRadius: '50%', background: b.cor, flexShrink: 0 }} />
              <span style={{ fontSize: 12.5, fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{b.nome}</span>
            </div>
            <div style={{ height: 8, background: 'var(--bg-sunken)', borderRadius: 3, overflow: 'hidden' }}>
              <div style={{ height: '100%', width: `${(b.roas / maxRoas) * 100}%`, background: b.cor, borderRadius: 3 }} />
            </div>
            <span className="font-mono" style={{ fontSize: 12, fontWeight: 600, textAlign: 'right' }}>{b.roas.toFixed(1)}×</span>
          </button>
        ))}
      </div>
      <div style={{ fontSize: 10.5, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', marginTop: 8, paddingTop: 8, borderTop: '1px solid var(--border)' }}>
        ROAS = Faturação / Investimento Ads · 2026
      </div>
    </div>
  );
};

// ============================================================================
// Single-brand: Leads por campanha
// ============================================================================
const CHANNEL_ICONS = { Facebook: '📘', LinkedIn: '💼', Google: '🔍', Email: '✉', default: '◉' };

// Criativos (ads) de uma campanha — filtra adsYtd pelo nome de campanha
function getCampaignAds(perfBrandId, campaignName) {
  const d = (window.MKT_PERF_DATA || {})[perfBrandId];
  if (!d?.adsYtd) return [];
  const seen = {};
  const ads = [];
  for (const ad of d.adsYtd) {
    if (ad.campaignName !== campaignName) continue;
    // Agrupa por adId (pode ter dados de vários meses)
    if (!seen[ad.adId]) {
      seen[ad.adId] = { ...ad, formLeads: 0, pixelLeads: 0, spend: 0, impressions: 0, clicks: 0 };
      ads.push(seen[ad.adId]);
    }
    seen[ad.adId].formLeads   += ad.formLeads   || 0;
    seen[ad.adId].pixelLeads  += ad.pixelLeads  || 0;
    seen[ad.adId].spend       += ad.spend        || 0;
    seen[ad.adId].impressions += ad.impressions  || 0;
    seen[ad.adId].clicks      += ad.clicks       || 0;
  }
  return ads.sort((a, b) => (b.formLeads + b.pixelLeads) - (a.formLeads + a.pixelLeads));
}

// Card individual de criativo (estilo Meta ad preview)
const CreativeCard = ({ ad, color, imageUrl }) => {
  const leads    = (ad.formLeads || 0) + (ad.pixelLeads || 0);
  const cpl      = leads > 0 && ad.spend > 0 ? ad.spend / leads : 0;
  const ctr      = ad.impressions > 0 ? (ad.clicks / ad.impressions * 100) : 0;
  // Extrai produto do nome do anúncio
  const prodMatch = AD_PRODUCT_PATTERNS.digidelta?.find(p => p.rx.test(ad.adName));
  const prodNome  = prodMatch ? prodMatch.nome : null;
  // Extrai mercado [PT] ou [ES] do nome
  const mktMatch = ad.adName.match(/\[(PT|ES)\]/i);
  const market   = mktMatch ? mktMatch[1].toUpperCase() : (ad.market || '');
  // Nome limpo (remove prefixo tipo "[PT] Q1.03.26 ")
  const cleanName = ad.adName.replace(/^\[(PT|ES)\]\s*Q\d\.\d{2}\.\d{2}\s*/i, '').trim();

  return (
    <div style={{
      borderRadius: 8, overflow: 'hidden',
      border: '1px solid var(--border)',
      background: 'var(--bg-sunken)',
      display: 'flex', flexDirection: 'column',
      fontSize: 11,
    }}>
      {/* Imagem real ou placeholder */}
      <div style={{
        height: 100, position: 'relative',
        background: imageUrl ? 'var(--bg-sunken)' : `linear-gradient(135deg, color-mix(in oklch, ${color} 30%, var(--bg-sunken)), color-mix(in oklch, ${color} 8%, var(--bg-sunken)))`,
        display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center', gap: 4,
        padding: imageUrl ? 0 : '8px 10px',
        overflow: 'hidden',
      }}>
        {imageUrl && (
          <img
            src={imageUrl}
            alt={cleanName}
            style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
            onError={e => { e.target.style.display = 'none'; }}
          />
        )}
        {market && (
          <span style={{
            position: 'absolute', top: 6, right: 6,
            background: `color-mix(in oklch, ${color} 70%, #000)`,
            color: '#fff', fontSize: 9, fontFamily: 'var(--font-mono)',
            padding: '1px 5px', borderRadius: 3, letterSpacing: '0.06em',
          }}>{market}</span>
        )}
        {!imageUrl && (
          <>
            <div style={{
              width: 36, height: 36, borderRadius: 8,
              background: `color-mix(in oklch, ${color} 50%, transparent)`,
              border: `1.5px solid color-mix(in oklch, ${color} 60%, transparent)`,
              display: 'grid', placeItems: 'center', fontSize: 16, flexShrink: 0,
            }}>
              {leads > 0 ? '◉' : '◎'}
            </div>
            <div style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--text)', textAlign: 'center', lineHeight: 1.3 }}>
              {prodNome || '—'}
            </div>
          </>
        )}
      </div>
      {/* Separador estilo Facebook page */}
      <div style={{
        padding: '6px 8px 2px',
        borderTop: '1px solid var(--border)',
        background: 'var(--bg-elev)',
        flex: 1,
      }}>
        <div style={{
          fontSize: 11, fontWeight: 500, lineHeight: 1.35,
          color: 'var(--text)', marginBottom: 4,
          display: '-webkit-box', WebkitLineClamp: 2,
          WebkitBoxOrient: 'vertical', overflow: 'hidden',
        }}>{cleanName}</div>
        {/* Métricas */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '2px 8px', paddingTop: 4, borderTop: '1px solid var(--border)' }}>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: leads > 0 ? 'var(--text)' : 'var(--text-dim)' }}>
            <span style={{ color: 'var(--text-dim)' }}>Leads </span>{leads > 0 ? leads : '—'}
          </span>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-dim)' }}>
            <span>Inv. </span>{fmtEur(ad.spend)}
          </span>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: cpl > 0 ? 'var(--text-muted)' : 'var(--text-dim)' }}>
            <span style={{ color: 'var(--text-dim)' }}>CPL </span>{cpl > 0 ? fmtEur(cpl) : '—'}
          </span>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-dim)' }}>
            <span>CTR </span>{ctr > 0 ? ctr.toFixed(2) + '%' : '—'}
          </span>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-dim)', gridColumn: '1/-1' }}>
            <span>Imp. </span>{fmtN(ad.impressions)}
          </span>
        </div>
      </div>
    </div>
  );
};

const LeadsPorCampanha = ({ brandId, color, period = 'maximum', customSince = '', customUntil = '' }) => {
  const staticCamps = getRealCampaigns(brandId) || (window.MKT_BRAND_CAMPAIGNS || {})[brandId] || [];
  const [liveCamps, setLiveCamps] = React.useState(null); // dados reais da Meta API
  const [activeChannel, setActiveChannel] = React.useState(null);
  const [hovered, setHovered] = React.useState(null);
  const [openCamp, setOpenCamp] = React.useState(null);
  const [adsImages, setAdsImages] = React.useState({});
  const [adsLoading, setAdsLoading] = React.useState(false);

  // Fetch leads/spend em tempo real da Meta API via ADS agent
  React.useEffect(() => {
    setLiveCamps(null); // reset ao mudar período
    const adsBrand = ADS_BRAND_MAP[brandId];
    if (!adsBrand) return;
    // Datas personalizadas ou preset
    const isCustom = period === 'custom' && customSince && customUntil;
    if (period === 'custom' && !isCustom) return; // aguarda as duas datas
    const qs = isCustom
      ? `since=${customSince}&until=${customUntil}`
      : `date_preset=${period}`;
    fetch(`https://ads.digidelta.ai/api/campaign-insights?brand=${encodeURIComponent(adsBrand)}&${qs}`, {
      headers: { 'x-api-key': 'f9fc165dbca0ffb309c97d07b76f061cd69230eccb11549527341c8f112edd5f' },
    })
      .then(r => r.ok ? r.json() : null)
      .then(data => {
        if (!data?.campaigns?.length) return;
        // Constrói mapa camp_name → dados live
        const liveMap = {};
        for (const c of data.campaigns) {
          if (!liveMap[c.campaign_name]) liveMap[c.campaign_name] = { leads: 0, spend: 0, impressions: 0, clicks: 0 };
          liveMap[c.campaign_name].leads       += c.leads;
          liveMap[c.campaign_name].spend       += c.spend;
          liveMap[c.campaign_name].impressions += c.impressions;
          liveMap[c.campaign_name].clicks      += c.clicks;
        }
        // Substitui leads/spend nos staticCamps com dados reais; mantém mql/sql/wins
        const merged = staticCamps.map(c => {
          const live = liveMap[c.nome];
          return live ? { ...c, leads: live.leads, spend: live.spend } : c;
        });
        // Adiciona campanhas que existem em Meta mas não no ficheiro estático
        for (const [nome, live] of Object.entries(liveMap)) {
          if (!merged.find(c => c.nome === nome) && (live.leads > 0 || live.spend > 0)) {
            merged.push({ nome, canal: 'Meta Ads', leads: live.leads, spend: live.spend, mql: 0, sql: 0, wins: 0, roas: 0 });
          }
        }
        setLiveCamps(merged.filter(c => c.leads > 0 || c.spend > 0).sort((a, b) => b.leads - a.leads).slice(0, 15));
      })
      .catch(() => {});
  }, [brandId, period, customSince, customUntil]);

  // Fetch lista de criativos do ADS agent — constrói mapa adId → image_url (só URLs directas)
  React.useEffect(() => {
    const adsBrand = ADS_BRAND_MAP[brandId];
    if (!adsBrand) return;
    setAdsLoading(true);
    fetch(`https://ads.digidelta.ai/api/creatives?brand=${encodeURIComponent(adsBrand)}&sort=spend`, {
      headers: { 'x-api-key': 'f9fc165dbca0ffb309c97d07b76f061cd69230eccb11549527341c8f112edd5f' },
    })
      .then(r => r.ok ? r.json() : { creatives: [] })
      .then(data => {
        const map = {};
        (data.creatives || []).forEach(c => {
          const img = c.creative?.image_url;
          if (c.ad_id && typeof img === 'string' && img.startsWith('http')) {
            map[c.ad_id] = img;
          }
        });
        setAdsImages(map);
      })
      .catch(() => {})
      .finally(() => setAdsLoading(false));
  }, [brandId]);

  const allCamps = liveCamps || staticCamps;
  if (!allCamps.length) return null;

  const allChannels = [...new Set(allCamps.flatMap(c => Object.keys(c.sources || {})))];
  const camps = activeChannel
    ? allCamps.filter(c => c.sources?.[activeChannel])
    : allCamps;

  const hasDM = allCamps.some(c => c.mql > 0 || c.sql > 0 || c.wins > 0);
  const max = Math.max(...camps.map(c => c.leads), 1);
  const perfId = PERF_BRAND_MAP[brandId];

  // Overlay de criativos
  const CreativesOverlay = openCamp ? (() => {
    const campAds = getCampaignAds(perfId, openCamp.nome);
    return ReactDOM.createPortal(
      <div
        onClick={() => setOpenCamp(null)}
        style={{
          position: 'fixed', inset: 0, zIndex: 1000,
          background: 'rgba(0,0,0,.65)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          padding: 24,
        }}
      >
        <div
          onClick={e => e.stopPropagation()}
          style={{
            background: 'var(--bg-elev)',
            border: '1px solid var(--border)',
            borderRadius: 14,
            width: '100%', maxWidth: 780,
            maxHeight: '85vh',
            display: 'flex', flexDirection: 'column',
            boxShadow: '0 24px 80px rgba(0,0,0,.6)',
          }}
        >
          {/* Header */}
          <div style={{
            display: 'flex', alignItems: 'center', gap: 10,
            padding: '14px 20px', borderBottom: '1px solid var(--border)', flexShrink: 0,
          }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.08em', marginBottom: 2 }}>CRIATIVOS · {campAds.length} anúncio{campAds.length !== 1 ? 's' : ''}</div>
              <div style={{ fontSize: 14, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{openCamp.nome}</div>
            </div>
            {/* KPIs sumário */}
            <div style={{ display: 'flex', gap: 16, flexShrink: 0 }}>
              {[
                { l: 'Leads', v: openCamp.leads || '—' },
                { l: 'Invest.', v: fmtEur(openCamp.spend) },
                openCamp.mql > 0 && { l: 'MQL', v: openCamp.mql },
                openCamp.wins > 0 && { l: 'Wins', v: openCamp.wins, success: true },
                openCamp.roas > 0 && { l: 'ROAS', v: `${openCamp.roas.toFixed(1)}×`, success: true },
              ].filter(Boolean).map((k, i) => (
                <div key={i} style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 1 }}>
                  <span style={{ fontSize: 9, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.06em' }}>{k.l}</span>
                  <span style={{ fontSize: 13, fontWeight: 700, fontFamily: 'var(--font-mono)', color: k.success ? 'var(--success)' : 'var(--text)' }}>{k.v}</span>
                </div>
              ))}
            </div>
            <button
              onClick={() => setOpenCamp(null)}
              style={{
                marginLeft: 8, flexShrink: 0,
                width: 28, height: 28, borderRadius: 6,
                background: 'var(--bg-sunken)', border: '1px solid var(--border)',
                color: 'var(--text-dim)', fontSize: 16, cursor: 'pointer',
                display: 'grid', placeItems: 'center', lineHeight: 1,
              }}
            >×</button>
          </div>
          {/* Grid de criativos */}
          <div className="scrollbar" style={{ overflowY: 'auto', padding: '16px 20px 20px', flex: 1 }}>
            {adsLoading && Object.keys(adsImages).length === 0 && (
              <div style={{ fontSize: 11, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', padding: '8px 0 12px', display: 'flex', alignItems: 'center', gap: 6 }}>
                <span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: '50%', background: 'var(--ai-500)' }} />
                A carregar imagens…
              </div>
            )}
            {campAds.length > 0 ? (
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(170px, 1fr))', gap: 12 }}>
                {campAds.map((ad, i) => <CreativeCard key={i} ad={ad} color={color} imageUrl={adsImages[ad.adId]} />)}
              </div>
            ) : (
              <div style={{ fontSize: 12, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', padding: '20px 0', textAlign: 'center' }}>
                Sem dados de criativos para esta campanha
              </div>
            )}
            <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', marginTop: 16, paddingTop: 10, borderTop: '1px solid var(--border)' }}>
              Fonte: Meta Ads YTD 2026 · clica fora ou × para fechar{Object.keys(adsImages).length > 0 ? ` · ${Object.keys(adsImages).length} imagem(ns) sincronizada(s)` : ''}
            </div>
          </div>
        </div>
      </div>,
      document.body
    );
  })() : null;

  return (
  <React.Fragment>
    <div style={{ padding: '16px 18px', background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 10 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12, flexWrap: 'wrap' }}>
        <div className="font-display" style={{ fontSize: 14, fontWeight: 600 }}>Campanhas</div>
        {/* Filtro por canal */}
        {allChannels.length > 0 && (
          <div style={{ display: 'flex', gap: 4, marginLeft: 4 }}>
            {allChannels.map(ch => (
              <button key={ch} onClick={() => setActiveChannel(activeChannel === ch ? null : ch)} style={{
                display: 'flex', alignItems: 'center', gap: 4,
                padding: '2px 8px', borderRadius: 999, fontSize: 10.5,
                fontFamily: 'var(--font-mono)', cursor: 'pointer', border: '1px solid',
                borderColor: activeChannel === ch ? color : 'var(--border)',
                background: activeChannel === ch ? `color-mix(in oklch, ${color} 15%, transparent)` : 'transparent',
                color: activeChannel === ch ? color : 'var(--text-dim)',
                transition: 'all .15s',
              }}>
                {CHANNEL_ICONS[ch] || CHANNEL_ICONS.default} {ch}
              </button>
            ))}
          </div>
        )}
        {hasDM && <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.06em', marginLeft: 'auto' }}>LEADS · MQL · SQL · WINS · ROAS</span>}
      </div>
      {/* Header */}
      {hasDM && (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 36px 36px 36px 36px 52px', gap: 8, padding: '0 0 6px', borderBottom: '1px solid var(--border)', marginBottom: 4 }}>
          <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)' }}>CAMPANHA</span>
          {['Leads','MQL','SQL','Wins','ROAS'].map(h => (
            <span key={h} style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', textAlign: 'right' }}>{h}</span>
          ))}
        </div>
      )}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
        {camps.map((c, i) => (
          <div key={i} style={{ position: 'relative' }}
            onMouseEnter={() => setHovered(i)}
            onMouseLeave={() => setHovered(null)}
            onClick={() => perfId && setOpenCamp(c)}>
          {/* Tooltip com breakdown por canal */}
          {hovered === i && c.sources && Object.keys(c.sources).length > 0 && (
            <div style={{
              position: 'absolute', bottom: '100%', left: 0, zIndex: 100,
              background: 'var(--bg-elev)', border: '1px solid var(--border)',
              borderRadius: 8, padding: '10px 12px', minWidth: 220,
              boxShadow: '0 8px 24px rgba(0,0,0,.35)', pointerEvents: 'none',
              marginBottom: 4,
            }}>
              <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', letterSpacing: '0.06em', marginBottom: 6 }}>ORIGEM DAS WINS</div>
              {Object.entries(c.sources).map(([ch, s]) => (
                <div key={ch} style={{ display: 'grid', gridTemplateColumns: '80px 28px 28px 28px 50px', gap: 6, alignItems: 'center', padding: '3px 0', borderBottom: '1px solid color-mix(in oklch, var(--border) 40%, transparent)' }}>
                  <span style={{ fontSize: 11, color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 4 }}>
                    {CHANNEL_ICONS[ch] || CHANNEL_ICONS.default} {ch}
                  </span>
                  <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', textAlign: 'right', color: 'var(--text-dim)' }} title="MQL">{s.mql || '—'}</span>
                  <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', textAlign: 'right', color: 'var(--text-dim)' }} title="SQL">{s.sql || '—'}</span>
                  <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', textAlign: 'right', color: s.wins > 0 ? 'var(--success)' : 'var(--text-dim)' }} title="Wins">{s.wins || '—'}</span>
                  <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', textAlign: 'right', color: s.winValue > 0 ? 'var(--success)' : 'var(--text-dim)' }}>{s.winValue > 0 ? fmtEur(s.winValue) : '—'}</span>
                </div>
              ))}
              <div style={{ display: 'grid', gridTemplateColumns: '80px 28px 28px 28px 50px', gap: 6, marginTop: 4, paddingTop: 4 }}>
                <span style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)' }}></span>
                {['MQL','SQL','Wins','Fat.'].map(h => <span key={h} style={{ fontSize: 9, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', textAlign: 'right' }}>{h}</span>)}
              </div>
            </div>
          )}
          <div style={{
            display: 'grid',
            gridTemplateColumns: hasDM ? '1fr 36px 36px 36px 36px 52px' : '1fr 90px 50px 52px',
            gap: 8, alignItems: 'center', padding: '6px 4px', borderRadius: 6,
            background: hovered === i ? 'var(--bg-hover)' : (i % 2 === 0 ? 'transparent' : 'color-mix(in oklch, var(--border) 20%, transparent)'),
            transition: 'background .12s', cursor: perfId ? 'pointer' : 'default',
          }}>
            <div style={{ minWidth: 0 }}>
              <div style={{ fontSize: 12, fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.nome}</div>
              <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>{fmtEur(c.spend)} invest.</div>
            </div>
            {hasDM ? (<>
              <span className="font-mono" style={{ fontSize: 12, fontWeight: 600, textAlign: 'right', color: 'var(--text)' }}>{c.leads || '—'}</span>
              <span className="font-mono" style={{ fontSize: 12, textAlign: 'right', color: c.mql > 0 ? 'var(--text)' : 'var(--text-dim)' }}>{c.mql || '—'}</span>
              <span className="font-mono" style={{ fontSize: 12, textAlign: 'right', color: c.sql > 0 ? 'var(--text)' : 'var(--text-dim)' }}>{c.sql || '—'}</span>
              <span className="font-mono" style={{ fontSize: 12, textAlign: 'right', color: c.wins > 0 ? 'var(--success)' : 'var(--text-dim)' }}>{c.wins || '—'}</span>
              <span className="font-mono" style={{ fontSize: 12, fontWeight: 600, textAlign: 'right', color: c.roas > 0 ? 'var(--success)' : 'var(--text-dim)' }}>
                {c.roas > 0 ? `${c.roas.toFixed(1)}×` : '—'}
              </span>
            </>) : (<>
              <div style={{ height: 7, background: 'var(--bg-sunken)', borderRadius: 3, overflow: 'hidden' }}>
                <div style={{ height: '100%', width: `${(c.leads / max) * 100}%`, background: color, borderRadius: 3 }} />
              </div>
              <span className="font-mono" style={{ fontSize: 12, fontWeight: 600, textAlign: 'right' }}>{c.leads}</span>
              <span className="font-mono" style={{ fontSize: 11, color: c.roas > 0 ? 'var(--success)' : 'var(--text-dim)', textAlign: 'right' }}>
                {c.roas > 0 ? `${c.roas.toFixed(1)}×` : '—'}
              </span>
            </>)}
          </div>
          </div>
        ))}
      </div>
      {hasDM && (
        <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', marginTop: 8, paddingTop: 8, borderTop: '1px solid var(--border)' }}>
          Leads + Invest: Meta Ads · MQL/SQL/Wins: DM Report · ROAS = Win Value ÷ Invest Meta · clica numa campanha para ver criativos
        </div>
      )}
    </div>
    {CreativesOverlay}
  </React.Fragment>
  );
};

// ============================================================================
// Single-brand: Top 5 produtos
// ============================================================================
const TopProdutos = ({ brandId, color, brandNome }) => {
  const realProds = getRealProducts(brandId);
  const prods = realProds || (window.MKT_BRAND_PRODUCTS || {})[brandId] || [];
  if (!prods.length) return null;
  const max = Math.max(...prods.map(p => p.leads));
  const isReal = !!realProds;
  return (
    <div style={{
      padding: '16px 18px',
      background: 'var(--bg-elev)',
      border: '1px solid var(--border)',
      borderRadius: 10,
    }}>
      <div className="font-display" style={{ fontSize: 14, fontWeight: 600, marginBottom: 12 }}>
        Top {isReal ? 'produtos/categorias' : 'produtos'} {brandNome} por leads
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        {prods.slice(0, 5).map((p, i) => (
          <div key={i} style={{ display: 'grid', gridTemplateColumns: '24px 1fr 60px 80px', gap: 10, alignItems: 'center', padding: '4px 6px' }}>
            <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-dim)', fontWeight: 700 }}>{String(i+1).padStart(2, '0')}</span>
            <span style={{ fontSize: 12.5, fontWeight: 500 }}>{p.nome}</span>
            <div style={{ height: 8, background: 'var(--bg-sunken)', borderRadius: 3, overflow: 'hidden' }}>
              <div style={{ height: '100%', width: `${max > 0 ? (p.leads / max) * 100 : 0}%`, background: color, borderRadius: 3 }} />
            </div>
            <span className="font-mono" style={{ fontSize: 12, fontWeight: 600, textAlign: 'right' }}>{p.leads} leads</span>
          </div>
        ))}
      </div>
      <div style={{ fontSize: 10.5, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', marginTop: 10, paddingTop: 8, borderTop: '1px solid var(--border)' }}>
        {isReal
          ? `Fonte: Meta Ads YTD 2026 · correspondência por nome de anúncio`
          : `Ticket médio do top: ${fmtEur(prods.slice(0, 5).reduce((a, p) => a + (p.ticket || 0), 0) / 5)}`}
      </div>
    </div>
  );
};

// ============================================================================
// MAIN
// ============================================================================
const PERIOD_OPTIONS = [
  { value: 'maximum',      label: 'Máximo' },
  { value: 'this_year',    label: '2026' },
  { value: 'last_30d',     label: '30 dias' },
  { value: 'this_quarter', label: 'Trimestre' },
  { value: 'last_month',   label: 'Mês ant.' },
  { value: 'custom',       label: 'Datas' },
];

const MktPerformance = ({ onOpenChat }) => {
  const { brand, brandObj, isAll, setBrand } = window.useMktBrand();
  const [period, setPeriod] = React.useState('maximum');
  const [customSince, setCustomSince] = React.useState('');
  const [customUntil, setCustomUntil] = React.useState('');

  // Re-renderiza quando MKT_DM_DATA carrega (script injectado dinamicamente)
  // Cobre 3 cenários: carrega antes do mount, entre render e effect, ou depois do effect
  const [, forceUpdate] = React.useReducer(x => x + 1, 0);
  React.useEffect(() => {
    if (window.MKT_DM_DATA) { forceUpdate(); return; } // carregou entre render e effect
    const handler = () => forceUpdate();
    window.addEventListener('mkt-dm-loaded', handler);
    return () => window.removeEventListener('mkt-dm-loaded', handler);
  }, []);

  const numbers = getRealEffectiveNumbers();
  const funnel = getRealFunnel(brand) || (window.MKT_BRAND_FUNNEL || {})[brand];

  // KPIs portfolio — dados reais Meta + DM Report (CRM)
  const realAll = getRealPortfolioData();
  const dmAll = getDmTotals('mimaki');
  const syncDate = window.MKT_PERF_META ? new Date(window.MKT_PERF_META.syncedAt).toLocaleDateString('pt-PT', { day: '2-digit', month: 'short' }) : null;
  const kpisAll = realAll ? [
    { label: 'Leads', value: fmtN(funnel?.leads ?? realAll.leads), sub: syncDate ? `YTD 2026 · sync ${syncDate}` : 'YTD 2026', tone: 'success', accentColor: 'var(--success)' },
    { label: 'Investimento', value: fmtEur(realAll.spend), sub: `CPL médio ${fmtEur(realAll.leads > 0 ? realAll.spend / realAll.leads : 0)}`, tone: null },
    { label: 'Alcance', value: fmtN(realAll.reach), sub: `${fmtN(realAll.impressions)} impressões`, tone: null },
    dmAll
      ? { label: 'MQL · OPs', value: `${fmtN(dmAll.mql)} · ${fmtN(dmAll.sql)}`, sub: `Mimaki YTD · ${dmAll.sql > 0 && dmAll.mql > 0 ? Math.round(dmAll.sql / dmAll.mql * 100) + '% MQL→OP' : ''}`, tone: null }
      : { label: 'OPs', value: '—', sub: 'CRM pendente', tone: null },
    dmAll
      ? { label: 'Wins · Fat.', value: `${fmtN(dmAll.wins)} · ${fmtEur(dmAll.winValue)}`, sub: `Mimaki YTD · ticket médio ${dmAll.wins > 0 ? fmtEur(dmAll.winValue / dmAll.wins) : '—'}`, tone: 'success', accentColor: 'var(--success)' }
      : { label: 'Wins · Fat.', value: '—', sub: 'CRM pendente', tone: null },
  ] : [
    { label: 'Leads', value: '975', sub: '+18% vs 2024', tone: 'success' },
    { label: 'OPs', value: '458', sub: '47% conversão lead→OP', tone: null },
    { label: 'Wins', value: '25', sub: '5,5% de OPs convertidas', tone: null },
    { label: 'Faturação', value: '€802k', sub: 'Ticket médio €32k', tone: null },
    { label: 'ROAS médio', value: '78×', sub: 'Mimaki puxa o valor', tone: 'success', accentColor: 'var(--success)' },
  ];

  // KPIs single-brand — dados reais Meta + DM Report (CRM)
  const realBrand = brand !== 'todas' ? getRealBrandData(PERF_BRAND_MAP[brand]) : null;
  const dmBrand = brand !== 'todas' ? getDmTotals(brand) : null;
  const kpisBrand = brand !== 'todas' ? (
    realBrand ? [
      { label: 'Leads', value: fmtN(funnel?.leads ?? realBrand.leads), sub: brandObj.tagline, tone: null, accentColor: brandObj.cor },
      { label: 'Investimento', value: fmtEur(realBrand.spend), sub: `CPL ${fmtEur(realBrand.leads > 0 ? realBrand.spend / realBrand.leads : 0)}`, tone: null },
      { label: 'Alcance', value: fmtN(realBrand.reach), sub: `${fmtN(realBrand.impressions)} impressões`, tone: null },
      (() => {
        const fMql = dmBrand ? dmBrand.mql : (funnel?.mql || 0);
        const fSql = dmBrand ? dmBrand.sql : (funnel?.sql || 0);
        return fMql > 0 || fSql > 0
          ? { label: 'MQL · OPs', value: `${fmtN(fMql)} · ${fmtN(fSql)}`, sub: fMql > 0 ? `${Math.round(fSql / fMql * 100)}% MQL→OP` : '', tone: null }
          : { label: 'OPs', value: '—', sub: 'CRM pendente', tone: null };
      })(),
      (() => {
        const fWins = dmBrand ? dmBrand.wins : (funnel?.wins || 0);
        const fVal  = dmBrand ? dmBrand.winValue : 0;
        return dmBrand
          ? { label: 'Wins · Fat.', value: `${fmtN(fWins)} · ${fmtEur(fVal)}`, sub: `ticket médio ${fWins > 0 ? fmtEur(fVal / fWins) : '—'}`, tone: null, accentColor: brandObj.cor }
          : fWins > 0
            ? { label: 'Wins', value: fmtN(fWins), sub: brandObj.tagline, tone: null, accentColor: brandObj.cor }
            : { label: 'Wins', value: '—', sub: 'CRM pendente', tone: null };
      })(),
    ] : numbers[brand] ? [
      { label: 'Leads', value: fmtN(numbers[brand].leads), sub: brandObj.tagline, tone: null, accentColor: brandObj.cor },
      { label: 'OPs', value: fmtN(numbers[brand].ops), sub: `${Math.round((numbers[brand].ops / numbers[brand].leads) * 100)}% conversão`, tone: null },
      { label: 'Wins', value: fmtN(numbers[brand].wins), sub: numbers[brand].ops > 0 ? `${Math.round((numbers[brand].wins / numbers[brand].ops) * 100)}% de OPs` : '—', tone: null },
      { label: 'Faturação', value: fmtEur(numbers[brand].faturacao), sub: numbers[brand].wins > 0 ? `Ticket médio ${fmtEur(numbers[brand].faturacao / numbers[brand].wins)}` : '—', tone: null },
      { label: 'CPL · ROAS', value: `€${numbers[brand].cpl.toFixed(2)}`, sub: numbers[brand].roas > 0 ? `${numbers[brand].roas.toFixed(1)}× ROAS` : 'Sem ROAS (institucional)', tone: numbers[brand].roas > 50 ? 'success' : null, accentColor: numbers[brand].roas > 50 ? 'var(--success)' : null },
    ] : []
  ) : [];

  return (
    <div className="scrollbar" style={{ padding: '20px 24px 80px', height: '100%', overflowY: 'auto' }}>
      <div style={{ fontSize: 11, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.08em' }}>
        MARKETING · PERFORMANCE 2026 {!isAll && <>· <span style={{ color: brandObj.cor }}>{brandObj.nome.toUpperCase()}</span></>}
      </div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, margin: '6px 0 4px' }}>
        <h2 className="font-display" style={{ margin: 0, fontSize: 28, fontWeight: 500, letterSpacing: '-0.01em', display: 'flex', alignItems: 'center', gap: 10 }}>
          Performance
          {!isAll && (
            <span style={{
              fontSize: 14, padding: '4px 10px', borderRadius: 6,
              background: `color-mix(in oklch, ${brandObj.cor} 18%, transparent)`,
              color: brandObj.cor, fontWeight: 600, letterSpacing: '0.02em',
            }}>{brandObj.nome}</span>
          )}
        </h2>
        <div style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0, flexWrap: 'wrap' }}>
          {PERIOD_OPTIONS.map(opt => (
            <button
              key={opt.value}
              onClick={() => setPeriod(opt.value)}
              style={{
                padding: '4px 10px', borderRadius: 6, fontSize: 11,
                fontFamily: 'var(--font-mono)', cursor: 'pointer', border: 'none',
                background: period === opt.value ? 'var(--brand-900)' : 'var(--bg-elev)',
                color: period === opt.value ? '#fff' : 'var(--text-muted)',
                fontWeight: period === opt.value ? 600 : 400,
              }}
            >{opt.label}</button>
          ))}
          {period === 'custom' && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 4, marginLeft: 4 }}>
              <input
                type="date" value={customSince} onChange={e => setCustomSince(e.target.value)}
                style={{
                  fontSize: 11, padding: '3px 6px', borderRadius: 5, border: '1px solid var(--border)',
                  background: 'var(--bg-elev)', color: 'var(--text)', fontFamily: 'var(--font-mono)',
                }}
              />
              <span style={{ fontSize: 11, color: 'var(--text-dim)' }}>→</span>
              <input
                type="date" value={customUntil} onChange={e => setCustomUntil(e.target.value)}
                style={{
                  fontSize: 11, padding: '3px 6px', borderRadius: 5, border: '1px solid var(--border)',
                  background: 'var(--bg-elev)', color: 'var(--text)', fontFamily: 'var(--font-mono)',
                }}
              />
            </div>
          )}
        </div>
      </div>
      <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 18 }}>
        {isAll
          ? (() => {
              const r = getRealPortfolioData();
              if (r) return `Vista consolidada · Meta Ads YTD 2026 · ${fmtN(r.leads)} leads · ${fmtEur(r.spend)} investidos · CPL médio ${fmtEur(r.leads > 0 ? r.spend / r.leads : 0)}`;
              return `Vista consolidada das 4 marcas · dados Meta Ads`;
            })()
          : brandObj.descricao}
      </div>

      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        <PerfKpis kpis={isAll ? kpisAll : kpisBrand} />

        <PerfFunnel
          data={funnel}
          color={isAll ? 'var(--brand-900)' : brandObj.cor}
          label={isAll ? 'Portfolio · 2026' : `${brandObj.nome} · 2026`}
        />

        <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 14 }}>
          {isAll ? (
            <>
              <LeadsPorMarcaCard onPickBrand={setBrand} numbers={numbers} />
              <RankingROAS onPickBrand={setBrand} numbers={numbers} />
            </>
          ) : (
            <>
              <LeadsPorCampanha brandId={brand} color={brandObj.cor} period={period} customSince={customSince} customUntil={customUntil} />
              <TopProdutos brandId={brand} color={brandObj.cor} brandNome={brandObj.nome} />
            </>
          )}
        </div>

        {/* Digi insight */}
        <div className="ai-surface" style={{ padding: 16, borderRadius: 10, fontSize: 13, lineHeight: 1.6 }}>
          <span className="ai-chip"><span className="ai-dot" />Digi · Marketing</span>
          {isAll ? (() => {
            const r = getRealPortfolioData();
            const digi = getRealBrandData('digidelta');
            const decal = getRealBrandData('decal');
            const biond = getRealBrandData('biond');
            if (!r) return <p style={{ margin: '10px 0 0' }}>Dados Meta Ads não disponíveis.</p>;
            const digiPct = r.leads > 0 && digi ? Math.round(digi.leads / r.leads * 100) : 0;
            const digiCpl = digi?.leads > 0 ? (digi.spend / digi.leads).toFixed(2) : '—';
            const decalCpl = decal?.leads > 0 ? (decal.spend / decal.leads).toFixed(2) : '—';
            const biondCpl = biond?.leads > 0 ? (biond.spend / biond.leads).toFixed(2) : '—';
            return (
              <p style={{ margin: '10px 0 0' }}>
                <strong>Digidelta (Mimaki)</strong> gerou <strong>{digiPct}%</strong> dos leads YTD com CPL €{digiCpl}.{' '}
                <strong>Decal</strong> com CPL €{decalCpl} e <strong>BIOND</strong> com CPL €{biondCpl}.{' '}
                Total <strong>{fmtN(r.leads)} leads</strong> e <strong>{fmtEur(r.spend)}</strong> investidos em Meta Ads.{' '}
                {(() => {
                  const dmP = getDmTotals('mimaki');
                  return dmP
                    ? <>MQL <strong>{fmtN(dmP.mql)}</strong> · OPs <strong>{fmtN(dmP.sql)}</strong> · Wins <strong>{fmtN(dmP.wins)}</strong> · Faturação <strong>{fmtEur(dmP.winValue)}</strong> · ROAS <strong>{digi?.spend > 0 ? (dmP.winValue / digi.spend).toFixed(1) : '—'}×</strong> (Mimaki · DM Report YTD).</>
                    : <>OPs, Wins e ROAS pendentes de integração CRM.</>;
                })()}
              </p>
            );
          })() : (
            <p style={{ margin: '10px 0 0' }}>
              {(() => {
                const r = getRealBrandData(PERF_BRAND_MAP[brand]);
                if (!r) return `Sem dados Meta para ${brandObj.nome}.`;
                const cpl = r.leads > 0 ? (r.spend / r.leads).toFixed(2) : '—';
                const dm = getDmTotals(brand);
                return <>Para <strong style={{ color: brandObj.cor }}>{brandObj.nome}</strong>: {fmtN(r.leads)} leads · CPL €{cpl} · {fmtEur(r.spend)} investidos · {fmtN(r.reach)} alcance YTD 2026.{dm ? <> MQL <strong>{fmtN(dm.mql)}</strong> · OPs <strong>{fmtN(dm.sql)}</strong> · Wins <strong>{fmtN(dm.wins)}</strong> · Fat. <strong>{fmtEur(dm.winValue)}</strong> · ROAS <strong>{r.spend > 0 ? (dm.winValue / r.spend).toFixed(1) : '—'}×</strong>.</> : <> OPs e ROAS pendentes de integração CRM.</>}</>;
              })()}
            </p>
          )}
        </div>
      </div>
    </div>
  );
};

window.MktPerformance = MktPerformance;
