/* Tráfego · GA4 — standalone app */
const { useState, useEffect, useRef } = React;

// ─── Formatters ───────────────────────────────────────────────────────────────

const fmt = {
  num(n) { if (n === null || n === undefined || isNaN(n)) return "—"; return Number(n).toLocaleString("pt-BR"); },
  pct(n, dec = 1) { if (n === null || n === undefined || isNaN(n)) return "—"; return Number(n).toFixed(dec) + "%"; },
  brl(n) { if (!n || isNaN(n) || Number(n) === 0) return "—"; return "R$ " + Number(n).toLocaleString("pt-BR", { minimumFractionDigits: 2 }); },
};

// ─── Icons ────────────────────────────────────────────────────────────────────
const ArrUp   = () => <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="m5 12 7-7 7 7M12 5v14"/></svg>;
const ArrDn   = () => <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5v14M5 12l7 7 7-7"/></svg>;
const ArrFlat = () => <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14"/></svg>;

// ─── Shared ───────────────────────────────────────────────────────────────────

function PageHeader({ title, subtitle, actions }) {
  return (
    <div className="gd-page-header">
      <div><h1 className="gd-page-title">{title}</h1>{subtitle && <p className="gd-page-subtitle">{subtitle}</p>}</div>
      {actions && <div className="gd-page-actions">{actions}</div>}
    </div>
  );
}

function Tabs({ items, active, onChange }) {
  return (
    <div className="gd-tabs" style={{ overflowX: "auto", flexWrap: "nowrap" }}>
      {items.map(it => (
        <button key={it.id} className={`gd-tab ${active === it.id ? "active" : ""}`} onClick={() => onChange(it.id)} style={{ whiteSpace: "nowrap" }}>
          {it.label}{it.count !== undefined && <span className="badge">{it.count}</span>}
        </button>
      ))}
    </div>
  );
}

function Empty({ msg }) {
  return <div style={{ padding: "28px", color: "var(--ink-3)", fontSize: "var(--t-sm)", fontFamily: "var(--font-mono)" }}>{msg || "Sem dados para o período."}</div>;
}

// ─── Date + URL picker ────────────────────────────────────────────────────────

function toYMD(d) { return d.toISOString().slice(0, 10); }

function Ga4DatePicker({ start, end, urlFilter, onApply, loading }) {
  const [s, setS] = useState(start);
  const [e, setE] = useState(end);
  const [url, setUrl] = useState(urlFilter || "");

  const presets = [
    { label: "7d",       fn: () => { const n = new Date(); return [toYMD(new Date(n - 6*864e5)), toYMD(n)]; } },
    { label: "30d",      fn: () => { const n = new Date(); return [toYMD(new Date(n - 29*864e5)), toYMD(n)]; } },
    { label: "90d",      fn: () => { const n = new Date(); return [toYMD(new Date(n - 89*864e5)), toYMD(n)]; } },
    { label: "Este mês", fn: () => { const n = new Date(); return [`${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,'0')}-01`, toYMD(n)]; } },
    { label: "Mês ant.", fn: () => { const n = new Date(new Date().getFullYear(), new Date().getMonth(), 0); return [toYMD(new Date(n.getFullYear(), n.getMonth(), 1)), toYMD(n)]; } },
    { label: "Este ano", fn: () => { const n = new Date(); return [`${n.getFullYear()}-01-01`, toYMD(n)]; } },
  ];

  const apply = (ns, ne) => { setS(ns); setE(ne); onApply(ns, ne, url); };
  const inp = { fontFamily: "var(--font-mono)", fontSize: "var(--t-xs)", padding: "4px 8px", height: 28, background: "var(--bg-2)", border: "1px solid var(--line-strong)", borderRadius: "var(--r-sm)", color: "var(--ink-1)", colorScheme: "dark" };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6, alignItems: "flex-end" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
        {presets.map(p => <button key={p.label} className="gd-btn ghost sm" onClick={() => { const [ns, ne] = p.fn(); apply(ns, ne); }}>{p.label}</button>)}
        <span style={{ width: 1, height: 18, background: "var(--line-strong)", margin: "0 2px" }}/>
        <input type="date" value={s} onChange={ev => setS(ev.target.value)} style={inp}/>
        <span className="muted" style={{ fontSize: "var(--t-xs)" }}>→</span>
        <input type="date" value={e} onChange={ev => setE(ev.target.value)} style={inp}/>
        <button className="gd-btn sm primary" onClick={() => apply(s, e)} disabled={loading}>{loading ? "…" : "Aplicar"}</button>
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
        <span style={{ fontSize: "var(--t-xs)", color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>URL contém</span>
        <input type="text" value={url} onChange={ev => setUrl(ev.target.value)}
          onKeyDown={ev => { if (ev.key === "Enter") apply(s, e); if (ev.key === "Escape") { setUrl(""); onApply(s, e, ""); }}}
          placeholder="ex: /carreiras/" style={{ ...inp, width: 200 }}/>
        {url && <button className="gd-btn ghost sm" onClick={() => { setUrl(""); onApply(s, e, ""); }}>✕</button>}
      </div>
    </div>
  );
}

// ─── KPI strip ────────────────────────────────────────────────────────────────

function Ga4Kpi({ label, value, delta, deltaSuffix, deltaGoodWhen, flagBad, hint, last }) {
  const up   = delta !== null && delta !== undefined && (deltaGoodWhen === "above" ? delta > 0 : delta < 0);
  const down = delta !== null && delta !== undefined && (deltaGoodWhen === "above" ? delta < 0 : delta > 0);
  return (
    <div className="gd-kpi" style={{ borderRight: last ? "none" : undefined }}>
      <div className="gd-kpi-label">{label}</div>
      <div className="gd-kpi-value text-mono" style={{ color: flagBad ? "var(--neg)" : undefined }}>{value}</div>
      {delta !== null && delta !== undefined && (
        <span className={`gd-kpi-delta ${up ? "up" : down ? "down" : "flat"}`}>
          {up ? <ArrUp/> : down ? <ArrDn/> : <ArrFlat/>}
          {(delta > 0 ? "+" : "") + Number(delta).toFixed(1)}{deltaSuffix || "%"}
        </span>
      )}
      {hint && <span style={{ fontSize: "var(--t-xs)", color: "var(--neg)", fontFamily: "var(--font-mono)" }}>{hint}</span>}
    </div>
  );
}

function Ga4KpiStrip({ data }) {
  const t = data.totais || {};
  const td = data.tendencia_7d || {};
  const bounceHigh = parseFloat(t.bounce_medio) > 60;
  const delta = td.delta ? parseFloat(td.delta) : null;
  const hasRevenue = t.receita && parseFloat(t.receita) > 0;
  const cols = hasRevenue ? 7 : 6;
  return (
    <div style={{ display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, borderBottom: "1px solid var(--line)", padding: "32px 40px" }}>
      <Ga4Kpi label="Sessões"         value={fmt.num(t.sessoes)}       delta={delta} deltaSuffix="% vs 7d ant." deltaGoodWhen="above"/>
      <Ga4Kpi label="Usuários ativos" value={fmt.num(t.usuarios)}/>
      <Ga4Kpi label="Novos usuários"  value={fmt.num(t.novos_usuarios)}/>
      <Ga4Kpi label="Conversões"      value={fmt.num(t.conversoes)}/>
      <Ga4Kpi label="Bounce médio"    value={t.bounce_medio} flagBad={bounceHigh} hint={bounceHigh ? "Acima de 60%" : null}/>
      <Ga4Kpi label="Duração média"   value={t.duracao_media} last={!hasRevenue}/>
      {hasRevenue && <Ga4Kpi label="Receita" value={fmt.brl(t.receita)} last/>}
    </div>
  );
}

// ─── Charts ───────────────────────────────────────────────────────────────────

function LineChart({ primary, secondary, labels, pColor, sColor, pLabel, sLabel }) {
  const W = 900, H = 180, pL = 44, pR = 16, pT = 16, pB = 28;
  const w = W - pL - pR, h = H - pT - pB;
  const all = [...primary, ...(secondary || [])].filter(v => v != null);
  if (!all.length) return null;
  const maxV = Math.max(...all, 1), range = maxV || 1;
  const xi = i => pL + (i / Math.max(primary.length - 1, 1)) * w;
  const yi = v => pT + h - (v / range) * h;
  const path = arr => arr.map((v, i) => (i === 0 ? "M" : "L") + xi(i).toFixed(1) + "," + yi(v).toFixed(1)).join(" ");
  const area = arr => { const last = arr.length - 1; return path(arr) + ` L ${xi(last).toFixed(1)},${(pT+h).toFixed(1)} L ${pL.toFixed(1)},${(pT+h).toFixed(1)} Z`; };
  const step = Math.ceil(labels.length / 7);
  const pc = pColor || "var(--brand)", sc = sColor || "var(--testing)";
  const li = primary.length - 1;
  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: "100%", height: H, display: "block" }}>
      {[0, 0.25, 0.5, 0.75, 1].map((f, i) => { const yy = yi(f * maxV); return <g key={i}><line x1={pL} x2={W-pR} y1={yy} y2={yy} stroke="var(--line)" strokeWidth="0.5"/><text x={pL-6} y={yy+3.5} textAnchor="end" fontSize="9" fill="var(--ink-3)" fontFamily="JetBrains Mono,monospace">{Math.round(f*maxV)}</text></g>; })}
      {secondary && secondary.length > 0 && <><path d={area(secondary)} fill={sc} opacity="0.08"/><path d={path(secondary)} fill="none" stroke={sc} strokeWidth="1.4" strokeDasharray="5 3" strokeLinecap="round" strokeLinejoin="round"/></>}
      <path d={area(primary)} fill={pc} opacity="0.10"/>
      <path d={path(primary)} fill="none" stroke={pc} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
      <circle cx={xi(li)} cy={yi(primary[li])} r="3.5" fill={pc}><animate attributeName="r" values="3.5;6;3.5" dur="2s" repeatCount="indefinite"/><animate attributeName="opacity" values="1;0.3;1" dur="2s" repeatCount="indefinite"/></circle>
      {labels.map((l, i) => (i % step === 0 || i === labels.length - 1) ? <text key={i} x={xi(i)} y={H-6} textAnchor="middle" fontSize="9" fill="var(--ink-3)" fontFamily="JetBrains Mono,monospace">{l}</text> : null)}
      <g><circle cx={pL+8} cy={pT+4} r="3" fill={pc}/><text x={pL+15} y={pT+8} fontSize="9" fill="var(--ink-2)" fontFamily="JetBrains Mono,monospace">{pLabel}</text>{secondary && secondary.length > 0 && <><line x1={pL+72} y1={pT+4} x2={pL+84} y2={pT+4} stroke={sc} strokeWidth="1.4" strokeDasharray="4 2"/><text x={pL+88} y={pT+8} fontSize="9" fill="var(--ink-2)" fontFamily="JetBrains Mono,monospace">{sLabel}</text></>}</g>
    </svg>
  );
}

function BarChart({ values, labels, color, height }) {
  const W = 900, H = height || 140, pL = 36, pR = 8, pT = 12, pB = 24;
  const w = W - pL - pR, h = H - pT - pB;
  const maxV = Math.max(...values, 1);
  const bW = w / values.length;
  const col = color || "var(--brand)";
  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: "100%", height: H, display: "block" }}>
      {[0, 0.5, 1].map((f, i) => { const yy = pT + h - f * h; return <g key={i}><line x1={pL} x2={W-pR} y1={yy} y2={yy} stroke="var(--line)" strokeWidth="0.5"/><text x={pL-4} y={yy+3} textAnchor="end" fontSize="9" fill="var(--ink-3)" fontFamily="JetBrains Mono,monospace">{Math.round(f*maxV)}</text></g>; })}
      {values.map((v, i) => { const bh = (v / maxV) * h; const x = pL + i * bW + bW * 0.15; return <rect key={i} x={x} y={pT+h-bh} width={bW*0.7} height={bh} fill={col} opacity="0.75" rx="1"/>; })}
      {labels.map((l, i) => i % 2 === 0 ? <text key={i} x={pL+i*bW+bW/2} y={H-4} textAnchor="middle" fontSize="8" fill="var(--ink-3)" fontFamily="JetBrains Mono,monospace">{l}</text> : null)}
    </svg>
  );
}

// ─── Mini row ─────────────────────────────────────────────────────────────────

function MiniRow({ label, value, bar, barMax, sub, color }) {
  const pct = Math.min(100, (bar / barMax) * 100);
  return (
    <div style={{ padding: "7px 0", borderBottom: "1px solid var(--line)" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 4 }}>
        <span style={{ fontSize: "var(--t-xs)", color: "var(--ink-1)", fontFamily: "var(--font-mono)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: "72%", display: "block" }}>{label}</span>
        <div style={{ display: "flex", gap: 8, alignItems: "baseline", flexShrink: 0 }}>
          {sub && <span style={{ fontSize: "var(--t-xs)", color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>{sub}</span>}
          <span style={{ fontSize: "var(--t-sm)", fontWeight: 600, fontFamily: "var(--font-mono)", color: "var(--ink-0)" }}>{value}</span>
        </div>
      </div>
      <div style={{ height: 2, background: "var(--bg-3)", borderRadius: 2 }}><div style={{ height: 2, width: pct + "%", background: color || "var(--brand-dim)", borderRadius: 2 }}/></div>
    </div>
  );
}

// ─── Generic table ────────────────────────────────────────────────────────────

function DataTable({ cols, rows, maxBar }) {
  if (!rows || !rows.length) return <Empty/>;
  return (
    <div className="gd-camp-table">
      <div className="gd-camp-head" style={{ gridTemplateColumns: cols.map(c => c.w || "1fr").join(" ") }}>
        {cols.map(c => <div key={c.key}>{c.label}</div>)}
      </div>
      {rows.map((r, i) => (
        <div key={i} className="gd-camp-row" style={{ gridTemplateColumns: cols.map(c => c.w || "1fr").join(" ") }}>
          {cols.map(c => {
            const val = r[c.key];
            if (c.bar && maxBar) {
              return <div key={c.key}><div style={{ height: 4, background: "var(--bg-3)", borderRadius: 2 }}><div style={{ height: 4, width: Math.min(100, (Number(r[c.barSource || c.key]) / maxBar) * 100) + "%", background: "var(--brand-dim)", borderRadius: 2 }}/></div></div>;
            }
            const color = c.colorFn ? c.colorFn(val) : undefined;
            return <div key={c.key} className={c.mono ? "text-mono" : ""} style={{ fontSize: c.xs ? "var(--t-xs)" : undefined, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color }}>{val ?? "—"}</div>;
          })}
        </div>
      ))}
    </div>
  );
}

// ─── Overview tab ─────────────────────────────────────────────────────────────

function Ga4Overview({ data }) {
  const serie = data.serie_diaria || [];
  const labels = serie.map(r => { const s = String(r.data); return s.slice(4,6)+"/"+s.slice(6,8); });
  return (
    <div className="gd-trend">
      <div className="gd-trend-card">
        <div className="gd-trend-head"><h4>Sessões e usuários ativos</h4><span className="muted text-mono" style={{ fontSize:"var(--t-xs)" }}>{data.periodo}</span></div>
        <LineChart primary={serie.map(r => Number(r.sessoes))} secondary={serie.map(r => Number(r.usuarios))} labels={labels} pColor="var(--brand)" sColor="var(--testing)" pLabel="Sessões" sLabel="Usuários"/>
      </div>
      <div className="gd-trend-mini-grid">
        <div className="gd-trend-card">
          <div className="gd-trend-head"><h4>Top páginas</h4><span className="muted text-mono" style={{ fontSize:"var(--t-xs)" }}>por sessões</span></div>
          {(data.top_paginas || []).slice(0, 6).map((p, i) => <MiniRow key={i} label={p.pagina} value={fmt.num(p.sessoes)} bar={p.sessoes} barMax={data.top_paginas[0]?.sessoes||1} sub={`bounce ${p.bounce}`}/>)}
        </div>
        <div className="gd-trend-card">
          <div className="gd-trend-head"><h4>Top fontes</h4><span className="muted text-mono" style={{ fontSize:"var(--t-xs)" }}>por sessões</span></div>
          {(data.top_fontes || []).slice(0, 6).map((f, i) => <MiniRow key={i} label={`${f.fonte} / ${f.meio}`} value={fmt.num(f.sessoes)} bar={f.sessoes} barMax={data.top_fontes[0]?.sessoes||1} sub={f.conversoes > 0 ? `${f.conversoes} conv.` : null}/>)}
        </div>
      </div>
    </div>
  );
}

// ─── Realtime tab ─────────────────────────────────────────────────────────────

function Ga4Realtime() {
  const [rt, setRt] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);
  const [lastUpdate, setLastUpdate] = useState(null);
  const timerRef = useRef(null);

  const fetchRt = async () => {
    setLoading(true);
    try {
      const r = await fetch("/api/ga4/realtime");
      if (!r.ok) throw new Error(await r.text());
      setRt(await r.json()); setLastUpdate(new Date()); setError(null);
    } catch (err) { setError(err.message); }
    finally { setLoading(false); }
  };

  useEffect(() => { fetchRt(); timerRef.current = setInterval(fetchRt, 30000); return () => clearInterval(timerRef.current); }, []);

  return (
    <div className="gd-trend">
      <div style={{ display:"flex", alignItems:"center", gap:10, padding:"12px 0 0" }}>
        <div style={{ width:8, height:8, borderRadius:"50%", background:"var(--pos)", boxShadow:"0 0 6px var(--pos)" }}/>
        <span style={{ fontFamily:"var(--font-mono)", fontSize:"var(--t-xs)", color:"var(--ink-2)" }}>Ao vivo · atualiza a cada 30s {lastUpdate ? `· ${lastUpdate.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}` : ""}</span>
        <button className="gd-btn ghost sm" onClick={fetchRt} disabled={loading} style={{ marginLeft:"auto" }}>{loading ? "…" : "↻ Atualizar"}</button>
      </div>
      {error && <div style={{ margin:"8px 0", padding:"10px 14px", background:"var(--neg-bg)", border:"1px solid var(--neg-line)", borderRadius:"var(--r-md)", color:"var(--neg)", fontSize:"var(--t-sm)", fontFamily:"var(--font-mono)" }}>{error}</div>}
      {rt && (
        <>
          <div style={{ display:"grid", gridTemplateColumns:"repeat(4,1fr)", gap:12, margin:"16px 0" }}>
            <div className="gd-trend-card" style={{ textAlign:"center", padding:"24px 12px" }}>
              <div style={{ fontSize:"var(--t-xs)", color:"var(--ink-3)", fontFamily:"var(--font-mono)", marginBottom:6 }}>Usuários ativos agora</div>
              <div style={{ fontSize:40, fontWeight:700, fontFamily:"var(--font-mono)", color:"var(--pos)", lineHeight:1 }}>{fmt.num(rt.total_ativo)}</div>
            </div>
            <div className="gd-trend-card" style={{ gridColumn:"span 3" }}>
              <div className="gd-trend-head"><h4>Páginas ativas</h4></div>
              {(rt.paginas_ativas||[]).slice(0,8).map((p,i) => <MiniRow key={i} label={p.pagina} value={fmt.num(p.usuarios)} bar={p.usuarios} barMax={rt.paginas_ativas[0]?.usuarios||1} color="var(--pos)"/>)}
              {!(rt.paginas_ativas||[]).length && <Empty msg="Sem tráfego ativo no momento."/>}
            </div>
          </div>
          <div className="gd-trend-mini-grid">
            <div className="gd-trend-card">
              <div className="gd-trend-head"><h4>Dispositivos</h4></div>
              {(rt.dispositivos_ativos||[]).map((d,i) => <MiniRow key={i} label={d.tipo} value={fmt.num(d.usuarios)} bar={d.usuarios} barMax={rt.dispositivos_ativos[0]?.usuarios||1}/>)}
            </div>
            <div className="gd-trend-card">
              <div className="gd-trend-head"><h4>Países</h4></div>
              {(rt.paises_ativos||[]).map((p,i) => <MiniRow key={i} label={p.pais} value={fmt.num(p.usuarios)} bar={p.usuarios} barMax={rt.paises_ativos[0]?.usuarios||1}/>)}
            </div>
          </div>
        </>
      )}
    </div>
  );
}

// ─── Pages tab ────────────────────────────────────────────────────────────────

function Ga4Pages({ rows, titulos }) {
  const [view, setView] = useState("path");
  const data = view === "path" ? rows : titulos;
  if (!data || !data.length) return <Empty/>;
  const maxS = Math.max(...data.map(r => r.sessoes), 1);
  return (
    <div className="gd-trend">
      <div style={{ display:"flex", gap:8, padding:"12px 0 4px" }}>
        <button className={`gd-btn sm ${view==="path"?"primary":"ghost"}`} onClick={() => setView("path")}>Por URL</button>
        <button className={`gd-btn sm ${view==="title"?"primary":"ghost"}`} onClick={() => setView("title")}>Por Título</button>
      </div>
      <DataTable
        cols={[
          { key: view==="path"?"pagina":"titulo", label: view==="path"?"URL":"Título", mono:true, xs:true },
          { key:"sessoes", label:"Sessões", w:"80px", mono:true },
          { key:"_bar", label:"Volume", w:"100px", bar:true, barSource:"sessoes" },
          { key:"bounce", label:"Bounce", w:"65px", mono:true, colorFn: v => parseFloat(v)>70?"var(--neg)":parseFloat(v)<40?"var(--pos)":undefined },
          { key:"duracao", label:"Duração", w:"65px", mono:true },
        ]}
        rows={data.map(r => ({ ...r, _bar: r.sessoes }))}
        maxBar={maxS}
      />
    </div>
  );
}

// ─── Sources tab ──────────────────────────────────────────────────────────────

function Ga4Sources({ rows }) {
  if (!rows.length) return <Empty/>;
  const maxS = Math.max(...rows.map(r => r.sessoes), 1);
  return (
    <div className="gd-trend">
      <DataTable
        cols={[
          { key:"fonte", label:"Fonte" },
          { key:"meio", label:"Meio", w:"100px", mono:true, xs:true },
          { key:"_bar", label:"Volume", w:"1fr", bar:true, barSource:"sessoes" },
          { key:"sessoes", label:"Sessões", w:"80px", mono:true },
          { key:"conversoes", label:"Conv.", w:"70px", mono:true, colorFn: v => v>0?"var(--pos)":"var(--ink-3)" },
        ]}
        rows={rows.map(r => ({ ...r, _bar: r.sessoes }))}
        maxBar={maxS}
      />
    </div>
  );
}

// ─── Channels tab ─────────────────────────────────────────────────────────────

function Ga4Channels({ canais }) {
  if (!canais || !canais.length) return <Empty/>;
  const maxS = Math.max(...canais.map(r => r.sessoes), 1);
  const total = canais.reduce((s, r) => s + r.sessoes, 0) || 1;
  return (
    <div className="gd-trend">
      <div className="gd-trend-mini-grid">
        {canais.map((c, i) => (
          <div key={i} className="gd-trend-card" style={{ textAlign:"center", padding:"14px 8px" }}>
            <div style={{ fontSize:"var(--t-xs)", color:"var(--ink-3)", fontFamily:"var(--font-mono)", marginBottom:4 }}>{c.canal}</div>
            <div style={{ fontSize:22, fontWeight:700, fontFamily:"var(--font-mono)", color:"var(--brand)" }}>{((c.sessoes/total)*100).toFixed(1)}%</div>
            <div style={{ fontSize:"var(--t-xs)", color:"var(--ink-2)", fontFamily:"var(--font-mono)" }}>{fmt.num(c.sessoes)} sess.</div>
            {c.conversoes > 0 && <div style={{ fontSize:"var(--t-xs)", color:"var(--pos)", fontFamily:"var(--font-mono)" }}>{c.conversoes} conv.</div>}
          </div>
        ))}
      </div>
      <DataTable
        cols={[
          { key:"canal", label:"Canal" },
          { key:"sessoes", label:"Sessões", w:"80px", mono:true },
          { key:"_bar", label:"Volume", w:"1fr", bar:true, barSource:"sessoes" },
          { key:"usuarios", label:"Usuários", w:"80px", mono:true },
          { key:"bounce", label:"Bounce", w:"65px", mono:true, colorFn: v => parseFloat(v)>70?"var(--neg)":undefined },
          { key:"conversoes", label:"Conv.", w:"70px", mono:true, colorFn: v => v>0?"var(--pos)":"var(--ink-3)" },
        ]}
        rows={canais.map(r => ({ ...r, _bar: r.sessoes }))}
        maxBar={maxS}
      />
    </div>
  );
}

// ─── Campaigns tab ────────────────────────────────────────────────────────────

function Ga4Campaigns({ campanhas, atribuicao }) {
  const [view, setView] = useState("last");
  const data = view === "last" ? campanhas : atribuicao;
  if (!data || !data.length) return (
    <div className="gd-trend">
      <div style={{ display:"flex", gap:8, padding:"12px 0 4px" }}>
        <button className={`gd-btn sm ${view==="last"?"primary":"ghost"}`} onClick={() => setView("last")}>Última sessão</button>
        <button className={`gd-btn sm ${view==="first"?"primary":"ghost"}`} onClick={() => setView("first")}>Primeiro toque</button>
      </div>
      <Empty msg="Sem dados de campanha para o período."/>
    </div>
  );
  const maxS = Math.max(...data.map(r => r.sessoes || r.usuarios || 0), 1);
  return (
    <div className="gd-trend">
      <div style={{ display:"flex", gap:8, padding:"12px 0 4px" }}>
        <button className={`gd-btn sm ${view==="last"?"primary":"ghost"}`} onClick={() => setView("last")}>Última sessão</button>
        <button className={`gd-btn sm ${view==="first"?"primary":"ghost"}`} onClick={() => setView("first")}>Primeiro toque</button>
      </div>
      {view === "last" && <DataTable
        cols={[
          { key:"campanha", label:"Campanha", xs:true },
          { key:"fonte", label:"Fonte", w:"100px" },
          { key:"meio", label:"Meio", w:"80px", mono:true, xs:true },
          { key:"sessoes", label:"Sessões", w:"80px", mono:true },
          { key:"usuarios", label:"Usuários", w:"80px", mono:true },
          { key:"conversoes", label:"Conv.", w:"70px", mono:true, colorFn: v => v>0?"var(--pos)":"var(--ink-3)" },
        ]}
        rows={campanhas}
        maxBar={maxS}
      />}
      {view === "first" && <DataTable
        cols={[
          { key:"fonte", label:"Fonte 1º Toque" },
          { key:"meio", label:"Meio", w:"100px", mono:true, xs:true },
          { key:"campanha", label:"Campanha", xs:true },
          { key:"usuarios", label:"Usuários", w:"80px", mono:true },
          { key:"novos", label:"Novos", w:"70px", mono:true },
          { key:"conversoes", label:"Conv.", w:"70px", mono:true, colorFn: v => v>0?"var(--pos)":"var(--ink-3)" },
        ]}
        rows={atribuicao}
        maxBar={maxS}
      />}
    </div>
  );
}

// ─── Landing pages tab ────────────────────────────────────────────────────────

function Ga4Landing({ rows }) {
  if (!rows || !rows.length) return <Empty/>;
  const maxS = Math.max(...rows.map(r => r.sessoes), 1);
  return (
    <div className="gd-trend">
      <DataTable
        cols={[
          { key:"pagina", label:"Landing Page", mono:true, xs:true },
          { key:"sessoes", label:"Sessões", w:"80px", mono:true },
          { key:"_bar", label:"Volume", w:"100px", bar:true, barSource:"sessoes" },
          { key:"bounce", label:"Bounce", w:"65px", mono:true, colorFn: v => parseFloat(v)>70?"var(--neg)":parseFloat(v)<40?"var(--pos)":undefined },
          { key:"duracao", label:"Duração", w:"65px", mono:true },
          { key:"conversoes", label:"Conv.", w:"70px", mono:true, colorFn: v => v>0?"var(--pos)":"var(--ink-3)" },
        ]}
        rows={rows.map(r => ({ ...r, _bar: r.sessoes }))}
        maxBar={maxS}
      />
    </div>
  );
}

// ─── Devices tab ──────────────────────────────────────────────────────────────

function Ga4Devices({ dispositivos }) {
  if (!dispositivos || !dispositivos.length) return <Empty/>;
  const total = dispositivos.reduce((s, d) => s + d.sessoes, 0) || 1;
  const colors = { desktop:"var(--brand)", mobile:"var(--testing)", tablet:"var(--pos)" };
  return (
    <div className="gd-trend">
      <div style={{ display:"grid", gridTemplateColumns:"repeat(3,1fr)", gap:12, margin:"16px 0" }}>
        {dispositivos.map(d => {
          const col = colors[d.tipo] || "var(--brand-dim)";
          const pct = ((d.sessoes/total)*100).toFixed(1);
          return (
            <div key={d.tipo} className="gd-trend-card" style={{ textAlign:"center", padding:"20px 12px" }}>
              <div style={{ fontSize:"var(--t-xs)", color:"var(--ink-3)", fontFamily:"var(--font-mono)", marginBottom:6, textTransform:"capitalize" }}>{d.tipo}</div>
              <div style={{ fontSize:28, fontWeight:700, fontFamily:"var(--font-mono)", color:col, lineHeight:1, marginBottom:4 }}>{pct}%</div>
              <div style={{ fontSize:"var(--t-xs)", color:"var(--ink-2)", fontFamily:"var(--font-mono)" }}>{fmt.num(d.sessoes)} sessões</div>
              <div style={{ height:3, background:"var(--bg-3)", borderRadius:2, marginTop:10 }}><div style={{ height:3, width:pct+"%", background:col, borderRadius:2 }}/></div>
            </div>
          );
        })}
      </div>
      <DataTable
        cols={[
          { key:"tipo", label:"Dispositivo" },
          { key:"sessoes", label:"Sessões", w:"90px", mono:true },
          { key:"usuarios", label:"Usuários", w:"90px", mono:true },
          { key:"conversoes", label:"Conv.", w:"80px", mono:true, colorFn: v => v>0?"var(--pos)":"var(--ink-3)" },
          { key:"bounce", label:"Bounce", w:"70px", mono:true, colorFn: v => parseFloat(v)>70?"var(--neg)":undefined },
        ]}
        rows={dispositivos}
      />
    </div>
  );
}

// ─── Technology tab ───────────────────────────────────────────────────────────

function Ga4Technology({ navegadores, sistemas_operacionais, resolucoes, plataformas }) {
  const [view, setView] = useState("browser");
  const views = { browser: navegadores||[], os: sistemas_operacionais||[], screen: resolucoes||[], platform: plataformas||[] };
  const data = views[view];
  const maxS = data.length ? Math.max(...data.map(r => r.sessoes||r.usuarios||0), 1) : 1;
  return (
    <div className="gd-trend">
      <div style={{ display:"flex", gap:8, padding:"12px 0 4px" }}>
        <button className={`gd-btn sm ${view==="browser"?"primary":"ghost"}`} onClick={() => setView("browser")}>Navegadores</button>
        <button className={`gd-btn sm ${view==="os"?"primary":"ghost"}`} onClick={() => setView("os")}>S. Operacional</button>
        <button className={`gd-btn sm ${view==="screen"?"primary":"ghost"}`} onClick={() => setView("screen")}>Resoluções</button>
        <button className={`gd-btn sm ${view==="platform"?"primary":"ghost"}`} onClick={() => setView("platform")}>Plataforma</button>
      </div>
      {(view === "browser" || view === "os") && (
        <DataTable
          cols={[
            { key: view==="browser"?"navegador":"sistema", label: view==="browser"?"Navegador":"Sistema" },
            { key:"sessoes", label:"Sessões", w:"80px", mono:true },
            { key:"_bar", label:"Volume", w:"1fr", bar:true, barSource:"sessoes" },
            { key:"usuarios", label:"Usuários", w:"80px", mono:true },
            { key:"bounce", label:"Bounce", w:"65px", mono:true, colorFn: v => parseFloat(v)>70?"var(--neg)":undefined },
          ]}
          rows={data.map(r => ({ ...r, _bar: r.sessoes }))}
          maxBar={maxS}
        />
      )}
      {view === "screen" && (
        <DataTable
          cols={[
            { key:"resolucao", label:"Resolução", mono:true },
            { key:"sessoes", label:"Sessões", w:"80px", mono:true },
            { key:"_bar", label:"Volume", w:"1fr", bar:true, barSource:"sessoes" },
            { key:"usuarios", label:"Usuários", w:"80px", mono:true },
          ]}
          rows={data.map(r => ({ ...r, _bar: r.sessoes }))}
          maxBar={maxS}
        />
      )}
      {view === "platform" && (
        <DataTable
          cols={[
            { key:"plataforma", label:"Plataforma" },
            { key:"sessoes", label:"Sessões", w:"80px", mono:true },
            { key:"_bar", label:"Volume", w:"1fr", bar:true, barSource:"sessoes" },
            { key:"usuarios", label:"Usuários", w:"80px", mono:true },
            { key:"conversoes", label:"Conv.", w:"70px", mono:true, colorFn: v => v>0?"var(--pos)":"var(--ink-3)" },
          ]}
          rows={data.map(r => ({ ...r, _bar: r.sessoes }))}
          maxBar={maxS}
        />
      )}
    </div>
  );
}

// ─── Geography tab ────────────────────────────────────────────────────────────

function Ga4Geography({ geografia, regioes, idiomas }) {
  const [view, setView] = useState("paises");
  const { paises=[], cidades=[] } = geografia || {};
  const views = { paises, cidades, regioes: regioes||[], idiomas: idiomas||[] };
  const data = views[view];
  const maxS = data.length ? Math.max(...data.map(r => r.sessoes||0), 1) : 1;
  return (
    <div className="gd-trend">
      <div style={{ display:"flex", gap:8, padding:"12px 0 4px" }}>
        <button className={`gd-btn sm ${view==="paises"?"primary":"ghost"}`} onClick={() => setView("paises")}>Países</button>
        <button className={`gd-btn sm ${view==="regioes"?"primary":"ghost"}`} onClick={() => setView("regioes")}>Regiões</button>
        <button className={`gd-btn sm ${view==="cidades"?"primary":"ghost"}`} onClick={() => setView("cidades")}>Cidades</button>
        <button className={`gd-btn sm ${view==="idiomas"?"primary":"ghost"}`} onClick={() => setView("idiomas")}>Idiomas</button>
      </div>
      {view === "paises" && <DataTable cols={[{key:"pais",label:"País"},{key:"sessoes",label:"Sessões",w:"80px",mono:true},{key:"_bar",label:"Volume",w:"1fr",bar:true,barSource:"sessoes"},{key:"usuarios",label:"Usuários",w:"80px",mono:true},{key:"conversoes",label:"Conv.",w:"70px",mono:true,colorFn:v=>v>0?"var(--pos)":"var(--ink-3)"}]} rows={data.map(r=>({...r,_bar:r.sessoes}))} maxBar={maxS}/>}
      {view === "regioes" && <DataTable cols={[{key:"regiao",label:"Região"},{key:"pais",label:"País",w:"100px"},{key:"sessoes",label:"Sessões",w:"80px",mono:true},{key:"_bar",label:"Volume",w:"1fr",bar:true,barSource:"sessoes"},{key:"conversoes",label:"Conv.",w:"70px",mono:true,colorFn:v=>v>0?"var(--pos)":"var(--ink-3)"}]} rows={data.map(r=>({...r,_bar:r.sessoes}))} maxBar={maxS}/>}
      {view === "cidades" && <DataTable cols={[{key:"cidade",label:"Cidade"},{key:"pais",label:"País",w:"100px"},{key:"sessoes",label:"Sessões",w:"80px",mono:true},{key:"_bar",label:"Volume",w:"1fr",bar:true,barSource:"sessoes"}]} rows={data.map(r=>({...r,_bar:r.sessoes}))} maxBar={maxS}/>}
      {view === "idiomas" && <DataTable cols={[{key:"idioma",label:"Idioma",mono:true},{key:"sessoes",label:"Sessões",w:"80px",mono:true},{key:"_bar",label:"Volume",w:"1fr",bar:true,barSource:"sessoes"},{key:"usuarios",label:"Usuários",w:"80px",mono:true}]} rows={data.map(r=>({...r,_bar:r.sessoes}))} maxBar={maxS}/>}
      {!data.length && <Empty/>}
    </div>
  );
}

// ─── Behavior tab ─────────────────────────────────────────────────────────────

function Ga4Behavior({ tipo_usuario, horario }) {
  const novo = tipo_usuario?.novo || { sessoes:0, usuarios:0, conversoes:0 };
  const rec  = tipo_usuario?.recorrente || { sessoes:0, usuarios:0, conversoes:0 };
  const total = (novo.sessoes + rec.sessoes) || 1;
  const novoPct = ((novo.sessoes/total)*100).toFixed(1);
  const recPct  = ((rec.sessoes/total)*100).toFixed(1);
  const hValues = (horario||[]).map(h => h.sessoes);
  const hLabels = (horario||[]).map(h => h.hora+"h");
  const peak = horario ? horario.reduce((b,h) => h.sessoes>b.sessoes?h:b, horario[0]||{hora:"—",sessoes:0}) : null;
  return (
    <div className="gd-trend">
      <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:12 }}>
        <div className="gd-trend-card">
          <div className="gd-trend-head"><h4>Novos vs Recorrentes</h4></div>
          <div style={{ display:"flex", gap:12, marginBottom:10 }}>
            {[{label:"Novos",pct:novoPct,col:"var(--brand)",data:novo},{label:"Recorrentes",pct:recPct,col:"var(--testing)",data:rec}].map(item => (
              <div key={item.label} style={{ flex:1, textAlign:"center", padding:"14px 8px", background:"var(--bg-2)", borderRadius:"var(--r-sm)" }}>
                <div style={{ fontSize:"var(--t-xs)", color:"var(--ink-3)", fontFamily:"var(--font-mono)", marginBottom:4 }}>{item.label}</div>
                <div style={{ fontSize:24, fontWeight:700, color:item.col, fontFamily:"var(--font-mono)" }}>{item.pct}%</div>
                <div style={{ fontSize:"var(--t-xs)", color:"var(--ink-3)", fontFamily:"var(--font-mono)" }}>{fmt.num(item.data.sessoes)} sess.</div>
                {item.data.conversoes > 0 && <div style={{ fontSize:"var(--t-xs)", color:"var(--pos)", fontFamily:"var(--font-mono)" }}>{item.data.conversoes} conv.</div>}
              </div>
            ))}
          </div>
          <div style={{ height:8, background:"var(--bg-3)", borderRadius:4, overflow:"hidden" }}><div style={{ height:8, width:novoPct+"%", background:"var(--brand)", borderRadius:4 }}/></div>
        </div>
        <div className="gd-trend-card">
          <div className="gd-trend-head"><h4>Distribuição horária</h4>{peak && <span className="muted text-mono" style={{ fontSize:"var(--t-xs)" }}>pico: {peak.hora}h ({fmt.num(peak.sessoes)})</span>}</div>
          {hValues.length > 0 ? <BarChart values={hValues} labels={hLabels} color="var(--brand)" height={130}/> : <Empty/>}
        </div>
      </div>
    </div>
  );
}

// ─── Calendar tab ─────────────────────────────────────────────────────────────

function Ga4Calendar({ dia_semana, semanal, mensal }) {
  const [view, setView] = useState("dow");
  const DOW_ORDER = [1,2,3,4,5,6,0]; // Mon-Sun for display

  const dowOrdered = DOW_ORDER.map(d => (dia_semana||[]).find(r => r.numero===d) || {dia:"",sessoes:0,usuarios:0,conversoes:0});

  const fmtWeek = w => { const s = String(w); return `S${s.slice(4)} '${s.slice(2,4)}`; };
  const fmtMonth = m => { const s = String(m); const months = ["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"]; return months[parseInt(s.slice(4))-1] + " '" + s.slice(2,4); };

  return (
    <div className="gd-trend">
      <div style={{ display:"flex", gap:8, padding:"12px 0 4px" }}>
        <button className={`gd-btn sm ${view==="dow"?"primary":"ghost"}`} onClick={() => setView("dow")}>Dia da semana</button>
        <button className={`gd-btn sm ${view==="weekly"?"primary":"ghost"}`} onClick={() => setView("weekly")}>Por semana</button>
        <button className={`gd-btn sm ${view==="monthly"?"primary":"ghost"}`} onClick={() => setView("monthly")}>Por mês</button>
      </div>

      {view === "dow" && (
        <div className="gd-trend-card">
          <div className="gd-trend-head"><h4>Sessões por dia da semana</h4><span className="muted text-mono" style={{ fontSize:"var(--t-xs)" }}>agregado do período</span></div>
          <BarChart values={dowOrdered.map(d => d.sessoes)} labels={dowOrdered.map(d => d.dia)} color="var(--brand)" height={130}/>
          <div style={{ display:"grid", gridTemplateColumns:"repeat(7,1fr)", gap:6, marginTop:8 }}>
            {dowOrdered.map((d, i) => (
              <div key={i} style={{ textAlign:"center", padding:"6px 4px", background:"var(--bg-2)", borderRadius:"var(--r-sm)" }}>
                <div style={{ fontSize:"var(--t-xs)", color:"var(--ink-3)", fontFamily:"var(--font-mono)" }}>{d.dia}</div>
                <div style={{ fontSize:"var(--t-xs)", fontWeight:600, fontFamily:"var(--font-mono)", color:"var(--ink-1)" }}>{fmt.num(d.sessoes)}</div>
                {d.conversoes > 0 && <div style={{ fontSize:"9px", color:"var(--pos)", fontFamily:"var(--font-mono)" }}>{d.conversoes} cv</div>}
              </div>
            ))}
          </div>
        </div>
      )}

      {view === "weekly" && semanal && semanal.length > 0 && (
        <div className="gd-trend-card">
          <div className="gd-trend-head"><h4>Tendência semanal</h4></div>
          <LineChart
            primary={semanal.map(r => r.sessoes)} secondary={semanal.map(r => r.conversoes)}
            labels={semanal.map(r => fmtWeek(r.semana))}
            pColor="var(--brand)" sColor="var(--pos)" pLabel="Sessões" sLabel="Conv."/>
        </div>
      )}

      {view === "monthly" && mensal && mensal.length > 0 && (
        <div className="gd-trend-card">
          <div className="gd-trend-head"><h4>Tendência mensal</h4></div>
          <LineChart
            primary={mensal.map(r => r.sessoes)} secondary={mensal.map(r => r.conversoes)}
            labels={mensal.map(r => fmtMonth(r.mes))}
            pColor="var(--brand)" sColor="var(--pos)" pLabel="Sessões" sLabel="Conv."/>
        </div>
      )}

      {(view === "weekly" && (!semanal || !semanal.length)) && <Empty msg="Dados semanais disponíveis para períodos ≥ 2 semanas."/>}
      {(view === "monthly" && (!mensal || !mensal.length)) && <Empty msg="Dados mensais disponíveis para períodos ≥ 2 meses."/>}
    </div>
  );
}

// ─── Events tab ───────────────────────────────────────────────────────────────

function Ga4Events({ todos_eventos }) {
  if (!todos_eventos || !todos_eventos.length) return <Empty/>;
  const maxT = todos_eventos[0]?.total || 1;
  return (
    <div className="gd-trend">
      <DataTable
        cols={[
          { key:"evento", label:"Evento", mono:true, xs:true },
          { key:"total", label:"Total", w:"90px", mono:true },
          { key:"_bar", label:"Volume", w:"1fr", bar:true, barSource:"total" },
          { key:"sessoes", label:"Sessões", w:"80px", mono:true },
        ]}
        rows={todos_eventos.map(r => ({ ...r, _bar: r.total }))}
        maxBar={maxT}
      />
    </div>
  );
}

// ─── Conversions tab ──────────────────────────────────────────────────────────

function Ga4Conversions({ events, serie, serie_receita }) {
  const evList = Object.entries(events).sort((a, b) => b[1] - a[1]);
  const convSerie = serie.map(r => Number(r.conversoes||0));
  const labels = serie.map(r => { const s = String(r.data); return s.slice(4,6)+"/"+s.slice(6,8); });
  const hasConv = convSerie.some(v => v > 0);
  const hasRev = (serie_receita||[]).some(r => r.receita > 0);

  return (
    <div className="gd-trend">
      {evList.length > 0 ? (
        <div className="gd-bench-grid">
          {evList.map(([name, count]) => (
            <div key={name} className="gd-bench-card">
              <div className="gd-bench-head"><div className="gd-bench-name">{name}</div></div>
              <div className="gd-bench-cpl-main"><span className="lbl">ocorrências</span><span className="val text-mono">{fmt.num(count)}</span></div>
            </div>
          ))}
        </div>
      ) : <div className="gd-trend-card" style={{ color:"var(--ink-3)", fontSize:"var(--t-sm)" }}>Nenhum evento de conversão. Verifique o setup no GA4.</div>}
      {hasConv && (
        <div className="gd-trend-card">
          <div className="gd-trend-head"><h4>Conversões diárias</h4></div>
          <LineChart primary={convSerie} labels={labels} pColor="var(--pos)" pLabel="Conversões"/>
        </div>
      )}
      {hasRev && (
        <div className="gd-trend-card">
          <div className="gd-trend-head"><h4>Receita diária</h4></div>
          <LineChart primary={(serie_receita||[]).map(r => r.receita)} labels={(serie_receita||[]).map(r => { const s=String(r.data); return s.slice(4,6)+"/"+s.slice(6,8); })} pColor="var(--testing)" pLabel="Receita (R$)"/>
        </div>
      )}
    </div>
  );
}

// ─── Search terms tab ─────────────────────────────────────────────────────────

function Ga4SearchTerms({ termos }) {
  if (!termos || !termos.length) return <Empty msg="Sem dados de busca interna. Configure o rastreamento de site search no GA4."/>;
  const maxS = Math.max(...termos.map(r => r.sessoes), 1);
  return (
    <div className="gd-trend">
      <DataTable
        cols={[
          { key:"termo", label:"Termo de busca" },
          { key:"sessoes", label:"Sessões", w:"80px", mono:true },
          { key:"_bar", label:"Volume", w:"1fr", bar:true, barSource:"sessoes" },
          { key:"usuarios", label:"Usuários", w:"80px", mono:true },
        ]}
        rows={termos.map(r => ({ ...r, _bar: r.sessoes }))}
        maxBar={maxS}
      />
    </div>
  );
}

// ─── Cohort tab ───────────────────────────────────────────────────────────────

function Ga4Cohort() {
  const [cohortData, setCohortData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchCohort = async () => {
    setLoading(true); setError(null);
    try {
      const r = await fetch("/api/ga4/cohort");
      if (!r.ok) throw new Error(await r.text());
      setCohortData(await r.json());
    } catch (err) { setError(err.message); }
    finally { setLoading(false); }
  };

  useEffect(() => { fetchCohort(); }, []);

  if (loading) return <div style={{ padding:"28px", color:"var(--ink-3)", fontFamily:"var(--font-mono)", fontSize:"var(--t-sm)" }}>Consultando API de Coorte…</div>;
  if (error) return <div style={{ padding:"12px", background:"var(--neg-bg)", border:"1px solid var(--neg-line)", borderRadius:"var(--r-md)", color:"var(--neg)", fontSize:"var(--t-sm)", fontFamily:"var(--font-mono)", margin:"12px 0" }}>{error}</div>;
  if (!cohortData || !cohortData.length) return <Empty msg="Sem dados de coorte suficientes para o período."/>;

  // Group by cohort name
  const cohorts = {};
  for (const r of cohortData) {
    if (!cohorts[r.cohort]) cohorts[r.cohort] = [];
    cohorts[r.cohort].push({ week: parseInt(r.cohortNthWeek||0), users: Number(r.cohortActiveUsers||0), retention: Number(r.cohortRetentionRate||0) });
  }
  const cohortNames = Object.keys(cohorts).sort();
  const maxWeeks = Math.max(...Object.values(cohorts).map(c => c.length), 1);

  return (
    <div className="gd-trend">
      <div className="gd-trend-card">
        <div className="gd-trend-head"><h4>Retenção por coorte semanal</h4><span className="muted text-mono" style={{ fontSize:"var(--t-xs)" }}>4 últimas semanas completas</span></div>
        <div style={{ overflowX:"auto", marginTop:8 }}>
          <table style={{ borderCollapse:"collapse", fontFamily:"var(--font-mono)", fontSize:"var(--t-xs)", width:"100%" }}>
            <thead>
              <tr>
                <th style={{ textAlign:"left", padding:"6px 12px 6px 0", color:"var(--ink-3)", fontWeight:400, whiteSpace:"nowrap" }}>Coorte</th>
                {Array.from({ length: maxWeeks }, (_, i) => (
                  <th key={i} style={{ padding:"6px 8px", color:"var(--ink-3)", fontWeight:400, textAlign:"center", whiteSpace:"nowrap" }}>S+{i}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {cohortNames.map(name => (
                <tr key={name}>
                  <td style={{ padding:"6px 12px 6px 0", color:"var(--ink-1)", whiteSpace:"nowrap" }}>{name}</td>
                  {cohorts[name].sort((a,b) => a.week-b.week).map((w, i) => {
                    const pct = (w.retention * 100).toFixed(1);
                    const intensity = Math.min(1, w.retention);
                    return (
                      <td key={i} style={{ padding:"4px 8px", textAlign:"center" }}>
                        <div style={{ background:`rgba(var(--brand-rgb,59,130,246),${0.1 + intensity*0.7})`, borderRadius:"var(--r-sm)", padding:"3px 6px", color: intensity > 0.5 ? "var(--ink-0)" : "var(--ink-2)", fontWeight: i===0?700:400 }}>
                          {i === 0 ? fmt.num(w.users) : pct + "%"}
                        </div>
                      </td>
                    );
                  })}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <div style={{ marginTop:10, fontSize:"var(--t-xs)", color:"var(--ink-3)", fontFamily:"var(--font-mono)" }}>S+0 = usuários da coorte · S+1, S+2… = % que voltaram nas semanas seguintes</div>
      </div>
    </div>
  );
}

// ─── Screen root ──────────────────────────────────────────────────────────────

function Ga4Screen({ data: initialData }) {
  const today = toYMD(new Date());
  const dft30 = toYMD(new Date(Date.now() - 29*864e5));
  const [tab, setTab]           = useState("overview");
  const [data, setData]         = useState(initialData);
  const [start, setStart]       = useState(dft30);
  const [end, setEnd]           = useState(today);
  const [urlFilter, setUrlFilter] = useState("");
  const [loading, setLoading]   = useState(false);
  const [error, setError]       = useState(null);

  useEffect(() => { if (initialData) setData(initialData); }, [initialData]);

  const fetchRange = async (s, e, url) => {
    setLoading(true); setError(null);
    const params = new URLSearchParams({ start: s, end: e });
    if (url) params.set("url", url);
    try {
      const r = await fetch(`/api/ga4/query?${params}`);
      if (!r.ok) throw new Error(await r.text());
      setData(await r.json());
      setStart(s); setEnd(e); setUrlFilter(url || "");
    } catch (err) { setError(err.message); }
    finally { setLoading(false); }
  };

  if (!data && !loading) return (
    <div style={{ display:"flex", alignItems:"center", justifyContent:"center", height:"100vh", color:"var(--ink-3)", fontFamily:"var(--font-mono)", fontSize:"var(--t-sm)" }}>
      Carregando dados de site…
    </div>
  );

  const tabs = [
    { id:"realtime",    label:"🟢 Ao Vivo" },
    { id:"overview",    label:"Visão Geral" },
    { id:"pages",       label:"Páginas",        count: data?.top_paginas?.length },
    { id:"sources",     label:"Fontes",          count: data?.top_fontes?.length },
    { id:"channels",    label:"Canais",          count: data?.canais?.length },
    { id:"campaigns",   label:"Campanhas" },
    { id:"landing",     label:"Landing Pages",   count: data?.landing_pages?.length },
    { id:"devices",     label:"Dispositivos" },
    { id:"technology",  label:"Tecnologia" },
    { id:"geography",   label:"Geografia" },
    { id:"behavior",    label:"Comportamento" },
    { id:"calendar",    label:"Calendário" },
    { id:"search",      label:"Busca Interna",   count: data?.termos_busca?.length },
    { id:"events",      label:"Eventos",         count: data?.todos_eventos?.length },
    { id:"conversions", label:"Conversões" },
    { id:"cohort",      label:"Coorte" },
  ];

  return (
    <>
      <PageHeader
        title="Tráfego · Google Analytics 4"
        subtitle={data ? `${data.periodo}${urlFilter ? ` · URL contém "${urlFilter}"` : ""}` : "Consultando API…"}
        actions={
          <div style={{ display:"flex", alignItems:"center", gap:10 }}>
            <Ga4DatePicker start={start} end={end} urlFilter={urlFilter} onApply={fetchRange} loading={loading}/>
            <button className="gd-btn ghost" onClick={() => window.open("https://analytics.google.com","_blank")}>Abrir GA4</button>
          </div>
        }
      />
      {error && <div style={{ margin:"0 28px 12px", padding:"10px 14px", background:"var(--neg-bg)", border:"1px solid var(--neg-line)", borderRadius:"var(--r-md)", color:"var(--neg)", fontSize:"var(--t-sm)", fontFamily:"var(--font-mono)" }}>{error}</div>}
      {loading && <div style={{ padding:"48px 28px", color:"var(--ink-3)", fontSize:"var(--t-sm)", fontFamily:"var(--font-mono)" }}>Consultando Google Analytics 4… (24 relatórios)</div>}
      {!loading && data && <>
        <Ga4KpiStrip data={data}/>
        <Tabs items={tabs} active={tab} onChange={setTab}/>
        {tab==="realtime"   && <Ga4Realtime/>}
        {tab==="overview"   && <Ga4Overview data={data}/>}
        {tab==="pages"      && <Ga4Pages rows={data.top_paginas||[]} titulos={data.titulos_paginas||[]}/>}
        {tab==="sources"    && <Ga4Sources rows={data.top_fontes||[]}/>}
        {tab==="channels"   && <Ga4Channels canais={data.canais||[]}/>}
        {tab==="campaigns"  && <Ga4Campaigns campanhas={data.campanhas||[]} atribuicao={data.atribuicao||[]}/>}
        {tab==="landing"    && <Ga4Landing rows={data.landing_pages||[]}/>}
        {tab==="devices"    && <Ga4Devices dispositivos={data.dispositivos||[]}/>}
        {tab==="technology" && <Ga4Technology navegadores={data.navegadores} sistemas_operacionais={data.sistemas_operacionais} resolucoes={data.resolucoes} plataformas={data.plataformas}/>}
        {tab==="geography"  && <Ga4Geography geografia={data.geografia} regioes={data.regioes} idiomas={data.idiomas}/>}
        {tab==="behavior"   && <Ga4Behavior tipo_usuario={data.tipo_usuario} horario={data.horario}/>}
        {tab==="calendar"   && <Ga4Calendar dia_semana={data.dia_semana} semanal={data.semanal} mensal={data.mensal}/>}
        {tab==="search"     && <Ga4SearchTerms termos={data.termos_busca||[]}/>}
        {tab==="events"     && <Ga4Events todos_eventos={data.todos_eventos||[]}/>}
        {tab==="conversions"&& <Ga4Conversions events={data.eventos_conversao||{}} serie={data.serie_diaria||[]} serie_receita={data.serie_receita}/>}
        {tab==="cohort"     && <Ga4Cohort/>}
      </>}
    </>
  );
}

// ─── App root ─────────────────────────────────────────────────────────────────

function App() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  useEffect(() => {
    fetch("/api/ga4-context")
      .then(r => {
        if (!r.ok) throw new Error(`HTTP ${r.status}`);
        return r.json();
      })
      .then(d => { if (d) setData(d); })
      .catch(err => setError(err.message || "Falha ao carregar contexto GA4"));
  }, []);

  if (error) {
    return (
      <div style={{ background:"var(--bg-0)", minHeight:"100vh", display:"flex", alignItems:"center", justifyContent:"center", color:"#fff", flexDirection:"column", gap:12 }}>
        <div style={{ fontSize:18 }}>Erro ao carregar GA4: {error}</div>
        <button className="gd-btn primary" onClick={() => window.location.reload()}>Tentar de novo</button>
      </div>
    );
  }
  return <div style={{ background:"var(--bg-0)", minHeight:"100vh" }}><Ga4Screen data={data}/></div>;
}

ReactDOM.createRoot(document.getElementById("root")).render(<App/>);
