/* Primitivas visuais de Resultados — funil, KPIs e barras.
   Partilhadas por Resultados e Início. Nomes globais Res* (já usados no módulo). */

const RES_LIGHT = { verde: 'var(--success)', amarelo: 'var(--warning)', vermelho: 'var(--danger)' };
const RES_FUNIL_CORES = ['#3859D0', '#F59E0B', '#E11D48', '#16A34A'];

function resFmtEur(v, cents) {
  if (v == null || !Number.isFinite(Number(v))) return '—';
  const n = Number(v);
  if (!cents && Math.abs(n) >= 1e6) return '€' + (n / 1e6).toFixed(1).replace('.', ',') + 'M';
  if (!cents && Math.abs(n) >= 1000) return '€' + Math.round(n).toLocaleString('pt-PT');
  return '€' + n.toLocaleString('pt-PT', { minimumFractionDigits: cents ? 2 : 0, maximumFractionDigits: cents ? 2 : 0 });
}
function resFmtN(v) {
  if (v == null || !Number.isFinite(Number(v))) return '—';
  return Math.round(Number(v)).toLocaleString('pt-PT');
}

const ResKpi = ({ label, value, sub, light }) => (
  <div style={{ padding: 14, border: '1px solid var(--border)', borderRadius: 10, background: 'var(--bg-elev)' }}>
    <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '.04em', textTransform: 'uppercase' }}>{label}</div>
    <div className="font-display" style={{ fontSize: 22, fontWeight: 650, marginTop: 4 }}>{value}</div>
    {sub && <div style={{ fontSize: 11, color: light ? RES_LIGHT[light] : 'var(--text-muted)', marginTop: 2 }}>{sub}</div>}
  </div>
);

function resSectorFunil(brand, isAll) {
  if (isAll || !brand || brand === 'todas' || brand === 'all') return 'comum';
  if (brand === 'mimaki') return 'equipamento';
  if (brand === 'decal' || brand === 'biond' || brand === 'alldecor' || brand === 'sensek') return 'materiais';
  return 'comum';
}

function resPctFunil(part, whole) {
  const p = whole ? (Number(part) || 0) / whole * 100 : 0;
  if (p > 0 && p < 10) return p.toFixed(1).replace('.', ',') + '%';
  return Math.round(p) + '%';
}

function resFunilEtapas(k, sector) {
  const leads = Number(k.leads?.real) || 0;
  const mql = Number(k.qualificados?.real) || 0;
  const etapas = [
    { key: 'leads', label: 'Leads', real: leads },
    { key: 'qualificados', label: 'MQL', real: mql },
  ];
  if (sector === 'equipamento') {
    const demosPortal = Number(k.demos?.real) || 0;
    etapas.push({
      key: 'demos',
      label: 'Demos',
      real: demosPortal > 0 ? demosPortal : (Number(k.oportunidades?.real) || 0),
    });
    etapas.push({ key: 'fechos', label: 'Fechos', real: Number(k.fechos?.real) || 0, valor: k.fechos?.valor_eur });
  } else if (sector === 'materiais') {
    etapas.push({ key: 'testing_rolls', label: 'Testing Rolls', real: Number(k.testing_rolls?.real) || 0 });
    etapas.push({ key: 'primeira_encomenda', label: '1ª Encomenda', real: Number(k.primeira_encomenda?.real) || 0, valor: k.primeira_encomenda?.valor_eur });
  } else {
    etapas.push({ key: 'oportunidades', label: 'Oportunidades', real: Number(k.oportunidades?.real) || 0 });
    etapas.push({ key: 'fechos', label: 'Fechos', real: Number(k.fechos?.real) || 0, valor: k.fechos?.valor_eur });
  }
  return etapas;
}

function resBanda(pts) {
  let d = `M ${pts[0][0]} ${pts[0][1]}`;
  for (let i = 0; i < pts.length - 1; i++) {
    const p0 = pts[Math.max(0, i - 1)];
    const p1 = pts[i];
    const p2 = pts[i + 1];
    const p3 = pts[Math.min(pts.length - 1, i + 2)];
    const c1x = p1[0] + (p2[0] - p0[0]) / 6;
    const c1y = p1[1] + (p2[1] - p0[1]) / 6;
    const c2x = p2[0] - (p3[0] - p1[0]) / 6;
    const c2y = p2[1] - (p3[1] - p1[1]) / 6;
    d += ` C ${c1x} ${c1y}, ${c2x} ${c2y}, ${p2[0]} ${p2[1]}`;
  }
  return d;
}

function resFunilPath(values, w, h, escala) {
  const n = values.length || 1;
  const max = Math.max(values[0] || 0, 1);
  const col = w / n;
  const knots = [{ x: 0, v: values[0] || 0 }];
  for (let i = 0; i < n; i++) {
    const v = values[i] || 0;
    knots.push({ x: i * col + col * 0.22, v });
    knots.push({ x: (i + 1) * col - col * 0.22, v });
  }
  knots.push({ x: w, v: values[n - 1] || 0 });
  const yOf = (v, lado) => {
    const half = Math.max(7, (v / max) * h * 0.42) * (escala || 1);
    return h / 2 + lado * half;
  };
  const top = knots.map(k => [k.x, yOf(k.v, -1)]);
  const bot = knots.map(k => [k.x, yOf(k.v, 1)]);
  const volta = resBanda([...bot].reverse()).replace(/^M\s*[-\d.eE]+\s+[-\d.eE]+\s*/, '');
  return `${resBanda(top)} L ${bot[bot.length - 1][0]} ${bot[bot.length - 1][1]} ${volta} Z`;
}

function ResFunil({ kpis, sector, periodo, campanhasNoAr, gidPrefix, altura }) {
  const etapas = resFunilEtapas(kpis || {}, sector);
  const primeiro = etapas[0]?.real || 0;
  const ultimo = etapas[etapas.length - 1];
  const taxa = primeiro ? (ultimo.real / primeiro) * 100 : 0;
  const taxaTxt = primeiro ? (taxa > 0 && taxa < 10 ? taxa.toFixed(1).replace('.', ',') : String(Math.round(taxa))) + '%' : '0%';
  const nota = sector === 'equipamento'
    ? 'Demos: oportunidades no Gestor a partir do stage Demo.'
    : sector === 'materiais' && primeiro > 0 && etapas.slice(2).every(e => !e.real)
      ? 'Testing Rolls e 1ª Encomenda ainda sem registos neste período.'
      : '';
  const fraseUltima = ultimo.key === 'primeira_encomenda'
    ? (ultimo.real === 1 ? '1 primeira encomenda' : `${resFmtN(ultimo.real)} primeiras encomendas`)
    : ultimo.key === 'fechos'
      ? (ultimo.real === 1 ? '1 fecho' : `${resFmtN(ultimo.real)} fechos`)
      : `${resFmtN(ultimo.real)} ${ultimo.label.toLowerCase()}`;
  const noAr = campanhasNoAr != null ? ` · ${resFmtN(campanhasNoAr)} no ar` : '';
  const sub = primeiro
    ? `${fraseUltima} de ${resFmtN(primeiro)} leads${ultimo.valor ? ` · ${resFmtEur(ultimo.valor)}` : ''} · ${periodo || 'YTD'}${noAr}`
    : `Sem leads neste período · ${periodo || 'YTD'}${noAr}`;
  const gid = (gidPrefix || 'res-funil-') + sector;
  const n = Math.max(etapas.length, 1);
  const H = Number(altura) > 80 ? Number(altura) : 200;
  return (
    <div className="card" style={{ padding: '18px 18px 8px', marginBottom: 12 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', gap: 16, alignItems: 'flex-end' }}>
        <div>
          <div className="font-display" style={{ fontSize: 40, fontWeight: 650, letterSpacing: '-0.03em', lineHeight: 1 }}>{taxaTxt}</div>
          <div style={{ fontSize: 13, color: 'var(--text-muted)', marginTop: 6 }}>{sub}</div>
        </div>
      </div>
      <div style={{ position: 'relative', marginTop: 16, width: '100%' }}>
        <svg viewBox={`0 0 800 ${H}`} preserveAspectRatio="none" width="100%" height={H} role="img" aria-label="Funil de resultados" style={{ display: 'block', position: 'absolute', left: 0, top: 28, width: '100%', height: H }}>
          <defs>
            <linearGradient id={gid} x1="0" y1="0" x2="1" y2="0" gradientUnits="objectBoundingBox">
              {RES_FUNIL_CORES.map((c, i) => (
                <stop key={c} offset={n <= 1 ? 0 : i / (n - 1)} stopColor={c} />
              ))}
            </linearGradient>
          </defs>
          <path d={resFunilPath(etapas.map(e => e.real), 800, H, 1.18)} fill="rgba(17,41,84,.18)" />
          <path d={resFunilPath(etapas.map(e => e.real), 800, H, 1.08)} fill="rgba(26,53,104,.22)" />
          <path d={resFunilPath(etapas.map(e => e.real), 800, H, 1)} fill={`url(#${gid})`} />
        </svg>
        <div style={{ position: 'relative', display: 'grid', gridTemplateColumns: `repeat(${etapas.length}, 1fr)`, width: '100%' }}>
          {etapas.map((e, i) => (
            <div key={e.key} style={{ textAlign: 'center', minWidth: 0, borderLeft: i ? '1px solid var(--border)' : 'none', padding: '0 8px 10px' }}>
              <div className="font-display" style={{ fontWeight: 650, fontSize: 20, lineHeight: '28px' }}>{resFmtN(e.real)}</div>
              <div style={{ height: H, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <div style={{ background: '#fff', color: '#112954', borderRadius: 999, padding: '4px 12px', fontSize: 13, fontWeight: 700, boxShadow: '0 0 0 1px rgba(17,41,84,.12)' }}>{resPctFunil(e.real, primeiro)}</div>
              </div>
              <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>{e.label}</div>
            </div>
          ))}
        </div>
      </div>
      {nota && <div style={{ fontSize: 11, color: 'var(--text-dim)', margin: '2px 0 8px' }}>{nota}</div>}
    </div>
  );
}

function ResLinhas({ linhas, onPick }) {
  const max = Math.max(1, ...linhas.map(l => Number(l.leads) || 0));
  if (!linhas.length) return <div className="card" style={{ padding: 12, fontSize: 12, color: 'var(--text-dim)' }}>Sem dados neste filtro.</div>;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      {linhas.map(l => (
        <button key={l.id} type="button" onClick={() => onPick && onPick(l)} className="card" style={{ textAlign: 'left', padding: 12, cursor: onPick ? 'pointer' : 'default', width: '100%' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8 }}>
            <strong>{l.nome}</strong>
            <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{resFmtEur(l.spend)}</span>
          </div>
          <div style={{ height: 8, borderRadius: 99, background: 'var(--surface-muted)', marginTop: 8, overflow: 'hidden' }}>
            <div style={{ width: `${Math.max(((Number(l.leads) || 0) / max) * 100, l.leads ? 3 : 0)}%`, height: '100%', borderRadius: 99, background: 'linear-gradient(90deg, #d6e2f0, #3859D0)' }} />
          </div>
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginTop: 6, fontSize: 11, color: 'var(--text-muted)' }}>
            <span>{resFmtN(l.leads)} leads</span>
            <span>{resFmtN(l.mql)} MQL</span>
            <span>{resFmtN(l.ops)} OPs</span>
            <span>{Number(l.fechos) === 1 ? '1 fecho' : `${resFmtN(l.fechos)} fechos`}{l.fechos_eur ? ` · ${resFmtEur(l.fechos_eur)}` : ''}</span>
          </div>
        </button>
      ))}
    </div>
  );
}

const RES_ETAPA_LABEL = {
  reach: 'Reach',
  leads: 'Leads',
  qualificados: 'MQL',
  demos: 'Demos',
  testing_rolls: 'Testing Rolls',
  primeira_encomenda: '1ª Encomenda',
  oportunidades: 'Oportunidades',
  fechos: 'Fechos',
  wins: 'Fechos',
};

function resBar(pct, light) {
  const w = Math.max(0, Math.min(100, Number(pct) || 0));
  return (
    <div style={{ height: 4, borderRadius: 2, background: 'var(--border)', marginTop: 4 }}>
      <div style={{ width: w + '%', height: '100%', borderRadius: 2, background: light ? RES_LIGHT[light] : 'var(--ai-500)' }} />
    </div>
  );
}

function resEtapaKeys(key) {
  if (key === 'fechos' || key === 'wins') return ['fechos', 'wins'];
  return [key];
}

/** Agrega objectivo só em campanhas com objectivo > 0 (não dilui com Meta/CRM). */
function resAggEtapa(campanhas, key, realOverride) {
  const keys = resEtapaKeys(key);
  let real = 0;
  let objectivo = 0;
  let realObj = 0;
  let light = null;
  const lightRank = { vermelho: 0, amarelo: 1, verde: 2 };
  for (const c of campanhas || []) {
    const e = (c.etapas || []).find(x => keys.includes(x.key));
    if (!e) continue;
    real += Number(e.real) || 0;
    if (Number(e.objectivo) > 0) {
      objectivo += Number(e.objectivo) || 0;
      realObj += Number(e.real) || 0;
      if (e.light && (light == null || (lightRank[e.light] ?? 9) < (lightRank[light] ?? 9))) light = e.light;
    }
  }
  const obj = objectivo > 0 ? objectivo : null;
  return {
    real: realOverride != null ? realOverride : real,
    real_com_objectivo: realObj,
    objectivo: obj,
    pct: obj ? Math.round(realObj / obj * 100) : null,
    light,
  };
}

function resKpiOuAgg(kpis, campanhas, key, realOverride) {
  const k = kpis?.[key];
  const agg = resAggEtapa(campanhas, key, realOverride);
  if (k && (k.objectivo != null || k.real_com_objectivo != null || k.pct != null)) {
    return {
      real: realOverride != null ? realOverride : (Number(k.real) || 0),
      real_com_objectivo: Number(k.real_com_objectivo) || 0,
      objectivo: k.objectivo != null && Number(k.objectivo) > 0 ? Number(k.objectivo) : null,
      pct: k.pct,
      light: k.light || agg.light,
    };
  }
  if (k && realOverride == null) {
    return { ...agg, real: Number(k.real) || 0, light: k.light || agg.light };
  }
  return agg;
}

function resDemosReal(kpis, campanhas) {
  const demosPortal = Number(kpis?.demos?.real) || 0;
  if (demosPortal > 0) return demosPortal;
  if (campanhas) {
    const demos = resAggEtapa(campanhas, 'demos').real;
    if (demos > 0) return demos;
    return resAggEtapa(campanhas, 'oportunidades').real;
  }
  return Number(kpis?.oportunidades?.real) || 0;
}

function resCardEtapa(key, data) {
  return { key, label: RES_ETAPA_LABEL[key] || key, ...data };
}

function ResObjCard({ card }) {
  const temObj = card.objectivo != null && Number(card.objectivo) > 0;
  const pct = temObj
    ? (card.pct != null ? card.pct : Math.round((Number(card.real_com_objectivo) || 0) / card.objectivo * 100))
    : null;
  const lightColor = card.light ? RES_LIGHT[card.light] : null;
  return (
    <div style={{ padding: 14, border: '1px solid var(--border)', borderRadius: 10, background: 'var(--bg-elev)', minWidth: 0 }}>
      <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '.04em', textTransform: 'uppercase' }}>{card.label}</div>
      <div className="font-display" style={{ fontSize: 22, fontWeight: 650, marginTop: 4, lineHeight: 1.15 }}>
        {resFmtN(card.real)}
        {temObj && <span style={{ fontWeight: 450, color: 'var(--text-muted)', fontSize: 15 }}> / {resFmtN(card.objectivo)}</span>}
      </div>
      <div style={{ fontSize: 11, marginTop: 4, color: lightColor || 'var(--text-muted)' }}>
        {temObj ? `${pct}% do objectivo` : 'sem objectivo'}
      </div>
      {temObj && resBar(pct, card.light)}
    </div>
  );
}

function ResObjCta({ label, title, sub, onClick }) {
  return (
    <button
      type="button"
      onClick={onClick}
      style={{
        padding: 14, border: '1px solid var(--border)', borderRadius: 10, background: 'var(--bg-elev)',
        minWidth: 0, width: '100%', height: '100%', textAlign: 'left', cursor: 'pointer', color: 'inherit',
        display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
      }}
    >
      <div>
        <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '.04em', textTransform: 'uppercase' }}>{label}</div>
        <div className="font-display" style={{ fontSize: 22, fontWeight: 650, marginTop: 4, lineHeight: 1.15, display: 'flex', alignItems: 'baseline', gap: 8 }}>
          {title}
          <span style={{ fontWeight: 450, color: 'var(--text-muted)', fontSize: 15 }}>→</span>
        </div>
      </div>
      <div style={{ fontSize: 11, marginTop: 4, color: 'var(--text-muted)' }}>{sub}</div>
    </button>
  );
}

function ResObjectivoCards({ kpis, campanhas, brand, isAll, isMobile, cta }) {
  const k = kpis || {};
  const lista = campanhas || [];
  const sector = resSectorFunil(brand, isAll);
  const reach = resAggEtapa(lista, 'reach');
  const leads = resKpiOuAgg(k, lista, 'leads');
  const mql = resKpiOuAgg(k, lista, 'qualificados');
  const ctaCard = cta && cta.onClick ? (
    <ResObjCta
      label={cta.label || 'Resultados'}
      title={cta.title || 'Ver todos'}
      sub={cta.sub || 'Campanhas, canais e marcas'}
      onClick={cta.onClick}
    />
  ) : null;

  if (isAll || brand === 'todas') {
    const comuns = [
      resCardEtapa('reach', reach),
      resCardEtapa('leads', leads),
      resCardEtapa('qualificados', mql),
    ];
    const equip = lista.filter(c => c.sector === 'equipamento');
    const mat = lista.filter(c => c.sector === 'materiais');
    const com = lista.filter(c => c.sector === 'comum' || (!c.sector && (c.brand_slug === 'netscreen' || c.marca_nome === 'NetScreen')));
    const demosReal = resDemosReal(null, equip);
    const grupos = [
      {
        titulo: 'Equipamento',
        cards: [
          resCardEtapa('demos', resAggEtapa(equip, 'demos', demosReal)),
          resCardEtapa('fechos', resAggEtapa(equip, 'fechos')),
        ],
      },
      {
        titulo: 'Materiais',
        cards: [
          resCardEtapa('testing_rolls', resAggEtapa(mat, 'testing_rolls')),
          resCardEtapa('primeira_encomenda', resAggEtapa(mat, 'primeira_encomenda')),
        ],
      },
      {
        titulo: 'NetScreen / comum',
        cards: [
          resCardEtapa('oportunidades', resAggEtapa(com, 'oportunidades')),
          resCardEtapa('fechos', resAggEtapa(com, 'fechos')),
        ],
      },
    ];
    return (
      <div style={{ marginBottom: 18 }}>
        <div style={{ display: 'grid', gridTemplateColumns: `repeat(${isMobile ? 1 : (ctaCard ? 4 : 3)}, 1fr)`, gap: 10, marginBottom: 12 }}>
          {comuns.map(card => <ResObjCard key={'c-' + card.key} card={card} />)}
          {ctaCard}
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(3, 1fr)', gap: 12 }}>
          {grupos.map(g => (
            <div key={g.titulo}>
              <div style={{ fontSize: 11, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '.04em', textTransform: 'uppercase', marginBottom: 6 }}>{g.titulo}</div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                {g.cards.map(card => <ResObjCard key={g.titulo + '-' + card.key} card={card} />)}
              </div>
            </div>
          ))}
        </div>
      </div>
    );
  }

  let cards;
  if (sector === 'equipamento') {
    const demosReal = resDemosReal(k, lista);
    cards = [
      resCardEtapa('reach', reach),
      resCardEtapa('leads', leads),
      resCardEtapa('qualificados', mql),
      resCardEtapa('demos', resKpiOuAgg(k, lista, 'demos', demosReal)),
      resCardEtapa('fechos', resKpiOuAgg(k, lista, 'fechos')),
    ];
  } else if (sector === 'materiais') {
    cards = [
      resCardEtapa('reach', reach),
      resCardEtapa('leads', leads),
      resCardEtapa('qualificados', mql),
      resCardEtapa('testing_rolls', resKpiOuAgg(k, lista, 'testing_rolls')),
      resCardEtapa('primeira_encomenda', resKpiOuAgg(k, lista, 'primeira_encomenda')),
    ];
  } else {
    cards = [
      resCardEtapa('reach', reach),
      resCardEtapa('leads', leads),
      resCardEtapa('qualificados', mql),
      resCardEtapa('oportunidades', resKpiOuAgg(k, lista, 'oportunidades')),
      resCardEtapa('fechos', resKpiOuAgg(k, lista, 'fechos')),
    ];
  }

  const nCols = cards.length + (ctaCard ? 1 : 0);
  return (
    <div style={{ display: 'grid', gridTemplateColumns: `repeat(${isMobile ? 2 : nCols}, 1fr)`, gap: 10, marginBottom: 18 }}>
      {cards.map(card => <ResObjCard key={card.key} card={card} />)}
      {ctaCard}
    </div>
  );
}

window.ResFunil = ResFunil;
window.ResKpi = ResKpi;
window.ResLinhas = ResLinhas;
window.ResObjCard = ResObjCard;
window.ResObjCta = ResObjCta;
window.ResObjectivoCards = ResObjectivoCards;
window.resFmtEur = resFmtEur;
window.resFmtN = resFmtN;
window.resBar = resBar;
window.resAggEtapa = resAggEtapa;
window.resSectorFunil = resSectorFunil;
window.RES_LIGHT = RES_LIGHT;
window.RES_ETAPA_LABEL = RES_ETAPA_LABEL;
