/* ===================== ADVERTENTIES PRO =====================
   Overkoepelende advertentie-analyse: verbindt ads (bol+Google),
   marge, voorraad, SEO, organisch verkeer en verkoop per product,
   en trekt eerlijke conclusies met directe acties. */

function advTokens(name) {
  return String(name || "").toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter(w => w.length >= 4 && !/^(kilogram|gram|voor|hout|doos|stuks|naar|met|van)$/.test(w));
}
/* gewicht (kg) uit een productnaam/titel halen — cruciaal om 5/15/20 KG-varianten uit elkaar te houden */
function advWeight(s) {
  const m = String(s || "").toLowerCase().match(/(\d+(?:[.,]\d+)?)\s*(?:kg|kilo)/);
  return m ? parseFloat(m[1].replace(",", ".")) : null;
}

/* per-product alles-in-één metriek + eerlijke conclusies */
function advBuild(db, period) {
  const g = (db.gadsData && db.gadsData()) || null;
  const gsc = (db.gscData && db.gscData()) || null;
  const ga4 = (db.ga4Data && db.ga4Data()) || null;
  const audit = (db.seoAudit && db.seoAudit()) || null;
  const out = [];
  db.products.forEach(p => {
    const a = db.adsFor ? db.adsFor(p.sku, period) : null;
    const di = db.periodOf(p, period) || { q: 0, rev: 0 };
    if (!(a && (a.cost > 0 || a.impressions > 0)) && !(di.q > 0)) return; // alleen producten die iets doen
    const price = (db.bestPrice && db.bestPrice(p, /bol/i)) || ((p.prices && p.prices.web) || 0);
    const inkoop = db.effCost(p);
    const ship = db.shipNL ? db.shipNL() : 0;
    const marge = (db.winstPer && price > 0) ? db.winstPer(p, price, "Bol.com NL") : null;
    const margePct = marge != null && price > 0 ? marge / price * 100 : null;
    const wi = db.winstInfo ? db.winstInfo(p, di) : null;
    const ads = a || { cost: 0, sales: 0, clicks: 0, impressions: 0, conversions: 0 };
    const roas = ads.cost > 0 && ads.sales > 0 ? ads.sales / ads.cost : null;
    const cpa = ads.cost > 0 && ads.conversions > 0 ? ads.cost / ads.conversions : null;
    const conv = ads.clicks > 0 ? ads.conversions / ads.clicks * 100 : null;
    const cpc = ads.clicks > 0 ? ads.cost / ads.clicks : null;
    const dagen = p.sales30 > 0 ? Math.round((p.stock || 0) / (p.sales30 / 30)) : null;
    // SEO: beste Google-positie van zoekwoorden die bij dit product passen
    const toks = advTokens(p.name);
    let seo = null;
    if (gsc && gsc.queries) {
      gsc.queries.forEach(q => { if (toks.some(t => q.query.indexOf(t) >= 0)) { if (!seo || q.position < seo.pos) seo = { pos: q.position, kw: q.query, clicks: q.clicks }; } });
    }
    // organisch verkeer: GA4-paginaweergaven van de productpagina
    let organic = null;
    if (ga4 && ga4.pages) {
      const hit = ga4.pages.find(pg => toks.some(t => pg.page.indexOf(t.replace(/\s/g, "-")) >= 0 || pg.page.indexOf(t) >= 0));
      if (hit) organic = { page: hit.page, views: hit.views };
    }
    let auditPage = null;
    if (audit && audit.pages) auditPage = audit.pages.find(pg => toks.some(t => pg.url.indexOf(t) >= 0)) || null;
    // breakeven-ROAS: prijs/marge — daaronder legt elke ad-euro toe
    const be = marge != null && marge > 0 ? price / marge : null;
    // marge-fractie gewogen naar NL/BE-advertentiekosten (BE-prijs/commissie kan afwijken)
    let mfBlend = (marge != null && price > 0) ? marge / price : null;
    try {
      const chBE = (p.channels || []).find(c2 => /bol/i.test(c2.name) && /\bbe\b|belgi/i.test(c2.name) && c2.price != null);
      const priceBE = chBE ? +chBE.price : null;
      const margeBE = (db.winstPer && priceBE > 0) ? db.winstPer(p, priceBE, "Bol.com BE") : null;
      const recAll = ((db.bolAds && db.bolAds()) || {}).bySku;
      const r2 = recAll && recAll[(p.sku || "").toUpperCase()];
      if (r2 && mfBlend != null && margeBE != null && priceBE > 0 && ((r2.nl || 0) + (r2.be || 0)) > 0) {
        mfBlend = ((marge / price) * (r2.nl || 0) + (margeBE / priceBE) * (r2.be || 0)) / ((r2.nl || 0) + (r2.be || 0));
      }
    } catch (e) {}
    const schoonV = mfBlend != null ? ads.sales * mfBlend - ads.cost : null;
    const schoon = schoonV != null && db.naBelasting ? db.naBelasting(schoonV) : schoonV;
    // ---- eerlijke conclusies ----
    const concl = [];
    const C = (sev, txt, why) => concl.push({ sev, txt, why });
    if (ads.cost > 0) {
      if (cpa != null && marge != null && cpa > marge) C("danger", "CPA hoger dan winst per verkoop", "Eén verkoop via ads kost " + fmtEur(cpa) + ", terwijl je er maar " + fmtEur(marge) + " aan verdient. Zo lever je toe op elke verkoop — bod verlagen of pauzeren.");
      else if (roas != null && be != null && roas < be) C("danger", "ROAS onder break-even", "Je hebt " + be.toFixed(1) + "× nodig om quitte te spelen; je zit op " + roas.toFixed(1) + "×. Bod verlagen of zoektermen aanscherpen.");
      if (margePct != null && margePct < 15 && roas != null && roas >= (be || 0)) C("warn", "Niet opschalen: marge te laag", "De marge is " + Math.round(margePct) + "% — winstgevend, maar te dun om hard te pushen. Eerst marge verbeteren (prijs of inkoop).");
      if (ads.clicks >= 30 && conv != null && conv < 1) C("warn", "Veel klikken, weinig verkopen", "Conversie is " + conv.toFixed(1) + "% — de advertentie trekt bezoekers, maar de productpagina overtuigt niet. Verbeter foto's, titel en bullets.");
      if ((p.stock || 0) > 0 && (p.stock || 0) < 15) C("warn", "Voorraad laag — advertentie afremmen", "Nog " + p.stock + " stuks. Hard adverteren op bijna-lege voorraad = straks nee verkopen. Bod tijdelijk verlagen.");
      if (roas != null && be != null && roas >= be * 1.5 && (dagen == null || dagen > 30) && (margePct == null || margePct >= 15)) C("ok", "Budget verhogen kan", "ROAS " + roas.toFixed(1) + "× bij break-even " + be.toFixed(1) + "× en voldoende voorraad. Verhoog stapsgewijs (+20%) en bewaak dat CPA onder " + (marge != null ? fmtEur(marge) : "je marge") + " blijft.");
      if (seo && seo.pos <= 5 && ads.cost > 5) C("info", "SEO scoort sterk — Ads kan mogelijk omlaag", "Je staat organisch al op #" + seo.pos.toFixed(1) + " voor \u201c" + seo.kw + "\u201d. Test of een lager budget dezelfde verkoop oplevert.");
    } else {
      if (di.q > 0 && seo && seo.pos <= 10) C("info", "Verkoopt organisch — onbenutte advertentiekans", "Dit product verkoopt zonder ads en staat op #" + seo.pos.toFixed(1) + ". Een kleine campagne kan het volume vergroten — mits de marge het toelaat.");
      else if (di.q > 0 && marge != null && margePct >= 25) C("info", "Advertentiekans", "Goede marge (" + Math.round(margePct) + "%) en het verkoopt al. Een testcampagne is het proberen waard.");
    }
    if (auditPage && auditPage.score < 65) C("warn", "Productpagina kan beter (SEO " + auditPage.score + "/100)", (auditPage.advice || [])[0] || "Bekijk de SEO-audit.");
    // reviews ↔ conversie: een lage reviewscore drukt je advertentie-rendement
    try {
      const rv = db.reviewFor ? db.reviewFor(p.sku) : null;
      if (rv && rv.rating != null && rv.rating < 4.2 && ads.cost > 5) C("warn", "Reviewscore drukt de conversie (" + (+rv.rating).toFixed(1) + "★)", "Kopers zien " + (+rv.rating).toFixed(1) + " sterren bij dit product — dat kost verkopen die je wél betaalt via ads. Pak eerst de oorzaak uit de reviews aan.");
    } catch (e) {}
    // ---- score 0-100 ----
    let score = 50;
    if (margePct != null) score += Math.max(-20, Math.min(20, (margePct - 15) * 1.2));
    if (roas != null && be != null) score += Math.max(-25, Math.min(25, (roas / be - 1) * 25));
    if (conv != null) score += Math.max(-10, Math.min(10, (conv - 2) * 3));
    if ((p.stock || 0) < 15) score -= 10; else if (dagen != null && dagen > 45) score += 5;
    if (seo && seo.pos <= 10) score += 8;
    score = Math.max(5, Math.min(98, Math.round(score)));
    // ---- korte labels ----
    const labels = [];
    if (concl.some(c => c.sev === "danger")) labels.push(["danger", "Niet rendabel"]);
    else if (concl.some(c => c.txt.indexOf("Budget verhogen") === 0)) labels.push(["ok", "Budget verhogen"]);
    else if (ads.cost > 0) labels.push(["ok", "Goed bezig"]);
    if (concl.some(c => c.txt.indexOf("Voorraad laag") === 0)) labels.push(["warn", "Voorraad controleren"]);
    if (concl.some(c => c.txt.indexOf("Veel klikken") === 0)) labels.push(["warn", "Productpagina verbeteren"]);
    if (concl.some(c => c.txt.indexOf("SEO scoort sterk") === 0)) labels.push(["info", "SEO kans"]);
    if (concl.some(c => c.txt.indexOf("onbenutte advertentiekans") >= 0 || c.txt === "Advertentiekans")) labels.push(["info", "Advertentie kans"]);
    out.push({ p, a: ads, hasAds: !!(a && (a.cost > 0 || a.impressions > 0)), price, inkoop, ship, marge, margePct, wi, di, roas, cpa, conv, cpc, dagen, seo, organic, auditPage, be, schoon, concl, score, labels });
  });
  return out.sort((x, y) => (y.a.cost || 0) - (x.a.cost || 0) || (y.di.rev || 0) - (x.di.rev || 0));
}

/* kleine visuals */
function AdvBar({ pct, color }) {
  return <div style={{ height: 6, borderRadius: 99, background: "var(--surface-3)", flex: 1 }}><div style={{ height: "100%", width: Math.max(3, Math.min(100, pct)) + "%", borderRadius: 99, background: color, transition: "width .4s" }}></div></div>;
}
function AdvStat({ label, value, hint, color }) {
  return (
    <div title={hint || ""} style={{ background: "var(--bg)", border: "1px solid var(--border)", borderRadius: 9, padding: "7px 9px", minWidth: 0 }}>
      <div className="muted" style={{ fontSize: 10, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".04em", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{label}</div>
      <div className="tnum" style={{ fontSize: 14.5, fontWeight: 700, marginTop: 1, color: color || "var(--text)", whiteSpace: "nowrap" }}>{value}</div>
    </div>
  );
}
function AdvScore({ score }) {
  const col = score >= 70 ? "var(--ok)" : (score >= 45 ? "var(--warn)" : "var(--danger)");
  const r = 17, c = 2 * Math.PI * r;
  return (
    <span style={{ position: "relative", width: 44, height: 44, flex: "none", display: "grid", placeContent: "center" }}>
      <svg width="44" height="44" style={{ position: "absolute", inset: 0, transform: "rotate(-90deg)" }}>
        <circle cx="22" cy="22" r={r} fill="none" stroke="var(--surface-3)" strokeWidth="4"></circle>
        <circle cx="22" cy="22" r={r} fill="none" stroke={col} strokeWidth="4" strokeLinecap="round" strokeDasharray={c} strokeDashoffset={c * (1 - score / 100)}></circle>
      </svg>
      <span className="tnum" style={{ fontSize: 12.5, fontWeight: 800, color: col }}>{score}</span>
    </span>
  );
}
const ADV_SEV = { ok: "var(--ok)", warn: "var(--warn)", danger: "var(--danger)", info: "var(--accent)" };

/* koppeling Google Shopping-product → eigen product (EAN/SKU in item-id, anders titel) */
/* vaste koppeling Google Item-ID (WooCommerce) → SKU — door Cars bevestigd 12-06-2026 */
const ADV_ITEM_SKU = { "958": "PH5", "85573": "PH20", "961": "H20", "89538": "BLK5", "89515": "KR15", "86467": "H20", "88234": "PH20" };
/* alternatieve Google-listings van eigen producten (zelfde product, andere titel) */
const ADV_ALIAS = [
  { re: /solo\s*stove/i, name: "pizzahout kleine oven" },
];
function advFindProd(db, x) {
  const hard = ADV_ITEM_SKU[String(x.itemId || "")];
  if (hard) { const ph = db.products.find(q => String(q.sku || "").toUpperCase() === hard); if (ph) return ph; }
  const iid = String(x.itemId || "").toLowerCase();
  if (iid) {
    const hit = db.products.find(q => String(q.ean || "").toLowerCase() === iid || (q.extraEans || []).some(e2 => String(e2).toLowerCase() === iid) || String(q.sku || "").toLowerCase() === iid);
    if (hit) return hit;
  }
  let tl = String(x.title || "").toLowerCase();
  if (!tl) return null;
  const w0 = advWeight(tl);
  for (const al of ADV_ALIAS) if (al.re.test(tl)) { tl = al.name + (w0 != null ? " " + w0 + " kg" : ""); break; }
  const w = advWeight(tl);
  let best = null, bestScore = 0;
  db.products.forEach(q => {
    const qn = String(q.name || "").toLowerCase();
    const qw = advWeight(qn);
    if (w != null && qw != null && w !== qw) return; // gewicht MOET kloppen (5/15/20 KG-varianten)
    const toks = advTokens(qn);
    if (!toks.length) return;
    let s = toks.filter(t => tl.indexOf(t) >= 0).length;
    if (!s) return;
    if (w != null && qw != null && w === qw) s += 2;       // gewicht-match telt zwaar
    s += s / Math.max(1, toks.length);                      // vollediger naamoverlap wint bij gelijke stand
    if (s > bestScore) { bestScore = s; best = q; }
  });
  return bestScore >= (w != null ? 3 : 2) ? best : null;    // liever geen koppeling dan een foute
}
function advMfOf(db, p) {
  const price = (db.bestPrice && db.bestPrice(p, /doosjehout|woo|webshop|eigen/i)) || ((p.prices && p.prices.web) || null);
  const wp = price ? db.winstPer(p, price, "Doosjehout.nl") : null;
  return (wp != null && price > 0) ? wp / price : null;
}

/* ===== Google Ads: campagne-analyse met eerlijke conclusies ===== */
function advBuildGoogle(db, period, g, gRows) {
  if (!g || !g.campaigns) return [];
  // verkoop-gewogen webshopmarge (fractie van de prijs) — om campagnewinst te schatten
  let mfSum = 0, mfN = 0;
  db.products.forEach(p => {
    const price = (p.prices && p.prices.web) || null;
    const wp = price ? db.winstPer(p, price, "Doosjehout.nl") : null;
    const di = db.periodOf(p, "d30");
    if (wp != null && price > 0 && di && di.q > 0) { mfSum += (wp / price) * di.q; mfN += di.q; }
  });
  const mf = mfN > 0 ? mfSum / mfN : null;
  const gp = (g.products || []);
  const mfOf = (p) => advMfOf(db, p);
  const findProd = (x) => advFindProd(db, x);
  const out = [];
  gRows.forEach(row => {
    const meta = g.campaigns[row.name] || {};
    const cost = row.cost, clicks = row.clicks, conv = row.conversions || 0, value = row.value || 0;
    const roas = cost > 0 && value > 0 ? value / cost : null;
    const cpa = cost > 0 && conv > 0 ? cost / conv : null;
    const cpc = clicks > 0 ? cost / clicks : null;
    const convPct = clicks > 0 ? conv / clicks * 100 : null;
    // schone winst: échte productmarges via Shopping-data waar mogelijk, anders gem. webshopmarge
    let winst = null, winstExact = false;
    {
      const cps = gp.filter(x => x.campaign === row.name && x.value > 0);
      let v = 0, vw = 0, matchedV = 0;
      cps.forEach(x => { const p2 = findProd(x); const f = p2 ? mfOf(p2) : null; v += x.value; if (f != null) { vw += x.value * f; matchedV += x.value; } });
      let useMf = mf;
      if (v > 0 && matchedV / v >= 0.5) { useMf = (vw + (v - matchedV) * (mf != null ? mf : 0)) / v; winstExact = true; }
      if (cost > 0 || value > 0) {
        if (useMf != null) winst = db.naBelasting ? db.naBelasting(value * useMf - cost) : (value * useMf - cost);
        else if (value === 0 && cost > 0) winst = -cost;
      }
    }
    // CPC-trend: laatste 7 dagen vs de 7 dagen ervoor (uit dagdata)
    let cpcTrend = null, trend = [];
    const days = Object.keys(meta.days || {}).sort();
    if (days.length >= 6) {
      const last7 = days.slice(-7), prev7 = days.slice(-14, -7);
      const agg = (ks) => ks.reduce((s, k) => { const d = meta.days[k]; s.c += d.cost; s.k += d.clicks; return s; }, { c: 0, k: 0 });
      const a1 = agg(last7), a0 = agg(prev7);
      if (a1.k > 5 && a0.k > 5) cpcTrend = (a1.c / a1.k) / (a0.c / a0.k) - 1;
      trend = days.slice(-14).map(k => ({ d: k, cost: meta.days[k].cost, value: meta.days[k].value || 0 }));
    }
    const concl = [];
    const C = (sev, txt, why) => concl.push({ sev, txt, why });
    if (winst != null && winst < 0 && cost >= 10 && conv > 0) C("warn", "Per saldo verlies", "Na aftrek van productkosten en belasting blijft er naar schatting " + fmtEur(winst) + " over — de conversiewaarde dekt de advertentiekosten niet. Verlaag het bod of richt de campagne scherper.");
    if (cost >= 10 && conv === 0) C("danger", "Geld zonder conversies", "Al " + fmtEur(cost) + " uitgegeven zonder één meetbare verkoop (" + clicks + " clicks). Pauzeer, of scherp de zoektermen flink aan.");
    else if (roas != null && roas < 2 && cost >= 10) C("warn", "ROAS rond of onder break-even", "Je krijgt " + roas.toFixed(1) + "× je inzet terug — na productkosten blijft daar meestal niets van over. Verlaag biedingen of sluit slechte zoektermen uit.");
    if (clicks >= 40 && convPct != null && convPct < 1) C("warn", "Veel klikken, weinig verkopen", "Conversie is " + convPct.toFixed(1) + "% — bezoekers haken af op de site. Check de landingspagina (foto's, prijs, laadtijd).");
    if (cpcTrend != null && cpcTrend > 0.25) C("warn", "CPC loopt op", "Een klik is deze week " + Math.round(cpcTrend * 100) + "% duurder dan vorige week — mogelijk meer concurrentie. Houd je maximale bod in de gaten.");
    if (roas != null && roas >= 4 && cost >= 5) C("ok", "Budget verhogen kan", "ROAS " + roas.toFixed(1) + "× is sterk. Verhoog het dagbudget stapsgewijs (+20%) en check na 7 dagen of de ROAS overeind blijft.");
    if (meta.status === "PAUSED" && value > cost * 3) C("info", "Gepauzeerd terwijl hij goed liep", "Deze campagne haalde " + fmtEur(value) + " conversiewaarde bij " + fmtEur(cost) + " kosten. Overweeg hervatten.");
    if (!concl.length && cost > 0) C("ok", "Draait stabiel", "Geen bijzonderheden — rendement is gezond voor deze periode.");
    let score = 50;
    if (roas != null) score += Math.max(-30, Math.min(30, (roas - 2.5) * 12));
    if (convPct != null) score += Math.max(-10, Math.min(10, (convPct - 2) * 3));
    if (cost >= 10 && conv === 0) score -= 25;
    score = Math.max(5, Math.min(98, Math.round(score)));
    out.push({ name: row.name, id: meta.id, status: meta.status, cost, clicks, conv, value, roas, cpa, cpc, convPct, cpcTrend, trend, concl, score, winst, winstExact, mfEst: mf != null });
  });
  return out.sort((a, b) => b.cost - a.cost);
}

/* Google campagnekaart met score, trend, conclusies en directe acties */
function GAdsCard({ c, db, onAsk }) {
  const [open, setOpen] = React.useState(false);
  const [busy, setBusy] = React.useState(null);
  const [msg, setMsg] = React.useState(null);
  const E = (v) => v != null ? fmtEur(v) : "—";
  const top = c.concl[0];
  const maxC = Math.max(...c.trend.map(t => Math.max(t.cost, t.value / 4)), 0.01);
  async function act(action) {
    let payload = { campaignId: c.id };
    if (action === "budget") {
      const v = window.prompt("Nieuw dagbudget (€) voor “" + c.name + "”:");
      if (!v) return;
      const eur = parseFloat(String(v).replace(",", "."));
      if (!(eur > 0)) { window.alert("Ongeldig bedrag."); return; }
      payload.amountEur = eur;
    } else if (!window.confirm("Campagne “" + c.name + "” " + (action === "pause" ? "pauzeren" : "weer activeren") + "? Dit wordt direct doorgevoerd in Google Ads.")) return;
    setBusy(action);
    const res = await db.adsAction(action, payload);
    setBusy(null);
    if (res.ok) setMsg(action === "budget" ? "✓ Budget aangepast" : (action === "pause" ? "✓ Gepauzeerd" : "✓ Geactiveerd"));
    else window.alert("Actie mislukt: " + (res.error || res.status || "onbekende fout"));
  }
  return (
    <Card>
      <div className="card-pad" style={{ paddingBottom: 12 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 10 }}>
          <AdvScore score={c.score} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontWeight: 700, fontSize: 14, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{c.name}</div>
            <div style={{ display: "flex", gap: 5, flexWrap: "wrap", marginTop: 4 }}>
              {c.status === "ENABLED" && <span className="pill ok" style={{ fontSize: 10.5 }}>Actief</span>}
              {c.status === "PAUSED" && <span className="pill neutral" style={{ fontSize: 10.5 }}>Gepauzeerd</span>}
              {top && top.sev === "danger" && <span className="pill danger" style={{ fontSize: 10.5 }}>Niet rendabel</span>}
              {top && top.txt === "Budget verhogen kan" && <span className="pill ok" style={{ fontSize: 10.5 }}>Budget verhogen</span>}
              {c.concl.some(x => x.txt === "CPC loopt op") && <span className="pill warn" style={{ fontSize: 10.5 }}>CPC stijgt</span>}
            </div>
          </div>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 6, marginBottom: 10 }}>
          <AdvStat label="Kosten" value={E(c.cost)} />
          <AdvStat label="Conv.waarde" value={c.value > 0 ? E(c.value) : "—"} hint="omzet toegeschreven aan deze campagne" />
          <AdvStat label="Schone winst" value={c.winst != null ? (c.winst >= 0 ? "+" : "−") + fmtEur(Math.abs(c.winst)) : "—"} color={c.winst != null ? (c.winst >= 0 ? "var(--ok)" : "var(--danger)") : null} hint={c.winstExact ? "o.b.v. échte productmarges uit je Shopping-data, na adkosten en winstbelasting" : (c.mfEst ? "geschat: conversiewaarde × gem. webshopmarge − adkosten, na winstbelasting" : "vul inkoopprijzen in om winst te schatten")} />
          <AdvStat label="ROAS" value={c.roas != null ? c.roas.toFixed(1) + "×" : "—"} color={c.roas != null ? (c.roas >= 4 ? "var(--ok)" : (c.roas < 2 ? "var(--danger)" : undefined)) : null} hint="conversiewaarde ÷ kosten" />
          <AdvStat label="CPA" value={c.cpa != null ? E(c.cpa) : "—"} hint="wat één verkoop via deze campagne kost" />
          <AdvStat label="Clicks" value={String(c.clicks)} />
          <AdvStat label="CPC" value={c.cpc != null ? E(c.cpc) : "—"} color={c.cpcTrend != null && c.cpcTrend > 0.25 ? "var(--warn)" : null} hint={c.cpcTrend != null ? "CPC-trend week-op-week: " + (c.cpcTrend >= 0 ? "+" : "") + Math.round(c.cpcTrend * 100) + "%" : "kosten per klik"} />
          <AdvStat label="Conversies" value={String(c.conv)} />
          <AdvStat label="Conversie%" value={c.convPct != null ? c.convPct.toFixed(1) + "%" : "—"} hint="hoeveel klikkers kopen" />
        </div>
        {c.trend.length > 3 && (
          <div style={{ marginBottom: 10 }}>
            <div className="muted" style={{ fontSize: 10.5, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".04em", marginBottom: 4 }}>Laatste 14 dagen · kosten (rood) vs conversiewaarde (groen)</div>
            <div style={{ display: "flex", gap: 2, alignItems: "flex-end", height: 38 }}>
              {c.trend.map(t => (
                <div key={t.d} title={t.d + " · kosten " + fmtEur(t.cost) + " · waarde " + fmtEur(t.value)} style={{ flex: 1, display: "flex", gap: 1, alignItems: "flex-end", height: "100%" }}>
                  <div style={{ flex: 1, height: Math.max(4, t.cost / maxC * 100) + "%", background: "var(--brand-soft)", borderRadius: 2 }}></div>
                  <div style={{ flex: 1, height: Math.max(2, (t.value / 4) / maxC * 100) + "%", background: "var(--ok-soft)", borderRadius: 2 }}></div>
                </div>
              ))}
            </div>
          </div>
        )}
        {top && (
          <div style={{ display: "flex", gap: 9, alignItems: "flex-start", background: "var(--surface-2)", border: "1px solid var(--border)", borderLeft: "3px solid " + ADV_SEV[top.sev], borderRadius: 9, padding: "9px 11px", fontSize: 12.5, lineHeight: 1.45 }}>
            <span><b>{top.txt}.</b> <span className="muted">{top.why}</span></span>
          </div>
        )}
        <div style={{ display: "flex", gap: 6, marginTop: 10, flexWrap: "wrap", alignItems: "center" }}>
          {msg ? <span style={{ fontSize: 12.5, color: "var(--ok)", fontWeight: 600 }}>{msg}</span> : (
            <React.Fragment>
              {c.id && c.status === "ENABLED" && <button className="btn btn-sm btn-ghost" disabled={busy === "pause"} onClick={() => act("pause")}>{busy === "pause" ? "Bezig…" : "Pauzeer"}</button>}
              {c.id && c.status === "PAUSED" && <button className="btn btn-sm btn-ghost" disabled={busy === "enable"} onClick={() => act("enable")}>{busy === "enable" ? "Bezig…" : "Activeer"}</button>}
              {c.id && <button className="btn btn-sm btn-ghost" disabled={busy === "budget"} onClick={() => act("budget")}>{busy === "budget" ? "Bezig…" : "Budget…"}</button>}
            </React.Fragment>
          )}
          {c.concl.length > 1 && <button className="btn btn-sm btn-ghost" onClick={() => setOpen(!open)}>{open ? "Verberg uitleg" : "Waarom? (" + c.concl.length + ")"}</button>}
          <button className="btn btn-sm btn-ghost" onClick={() => onAsk("Wat moet ik doen met mijn Google-campagne “" + c.name + "”? Wees eerlijk en concreet.")}>Vraag AdPilot</button>
        </div>
        {open && (
          <div style={{ display: "grid", gap: 7, marginTop: 10 }}>
            {c.concl.map((x, i) => (
              <div key={i} style={{ fontSize: 12.5, lineHeight: 1.5, padding: "8px 10px", background: "var(--bg)", border: "1px solid var(--border)", borderLeft: "3px solid " + ADV_SEV[x.sev], borderRadius: 8 }}>
                <b>{x.txt}.</b> <span className="muted">{x.why}</span>
              </div>
            ))}
          </div>
        )}
      </div>
    </Card>
  );
}

/* Shopping/PMax-producten binnen Google-campagnes */
function GProductsCard({ g, db }) {
  const prods = (g && g.products) || [];
  if (!prods.length) return null;
  const rec = (x, winst) => {
    const r = x.cost > 0 && x.value > 0 ? x.value / x.cost : null;
    if (winst != null && winst < 0 && x.cost >= 3) return ["danger", "Niet rendabel"];
    if (x.cost >= 5 && !x.conversions) return ["danger", "Uitsluiten"];
    if (r != null && r >= 4 && (winst == null || winst > 0)) return ["ok", "Opschalen"];
    if (r != null && r < 2) return ["warn", "Bod verlagen"];
    return ["neutral", "Monitoren"];
  };
  const rows2 = prods.slice(0, 14).map(x => {
    const p2 = advFindProd(db, x);
    const f = p2 ? advMfOf(db, p2) : null;
    let winst = null;
    if (f != null && (x.cost > 0 || x.value > 0)) { const voor = x.value * f - x.cost; winst = db.naBelasting ? db.naBelasting(voor) : voor; }
    const lowStock = p2 && (p2.stock || 0) > 0 && (p2.stock || 0) < 15;
    return { x, p2, winst, lowStock };
  });
  return (
    <Card style={{ marginTop: "var(--space)" }}>
      <CardHead title="Producten in je Google-campagnes" icon="tag" sub="Shopping / Performance Max · laatste 30 dagen · gekoppeld aan je eigen marges" />
      <div style={{ overflowX: "auto" }}>
        <table className="tbl">
          <thead><tr><th>Product</th><th className="num">Kosten</th><th className="num">Clicks</th><th className="num">Conversies</th><th className="num">Waarde</th><th className="num">ROAS</th><th className="num" title="winst op de conversiewaarde, na adkosten en winstbelasting — o.b.v. jouw marge">Schone winst</th><th>Aanbeveling</th></tr></thead>
          <tbody>
            {rows2.map(({ x, p2, winst, lowStock }) => { const r = x.cost > 0 && x.value > 0 ? x.value / x.cost : null; const rc = lowStock ? ["warn", "Voorraad laag — afremmen"] : rec(x, winst); return (
              <tr key={(x.campaign || "") + (x.itemId || x.title)}>
                <td style={{ fontWeight: 600, fontSize: 13 }}>{x.title}{p2 && <span className="pill neutral" style={{ marginLeft: 6, fontSize: 10 }}>{p2.sku}</span>}{lowStock && <span className="pill warn" style={{ marginLeft: 5, fontSize: 10 }}>{p2.stock} op voorraad</span>}</td>
                <td className="num tnum">{fmtEur(x.cost)}</td>
                <td className="num tnum muted">{x.clicks}</td>
                <td className="num tnum muted">{x.conversions}</td>
                <td className="num tnum">{x.value > 0 ? fmtEur(x.value) : "—"}</td>
                <td className="num tnum" style={{ fontWeight: 600, color: r != null ? (r >= 4 ? "var(--ok)" : (r < 2 ? "var(--danger)" : undefined)) : undefined }}>{r != null ? r.toFixed(1) + "×" : "—"}</td>
                <td className="num tnum" style={{ fontWeight: 700, color: winst != null ? (winst >= 0 ? "var(--ok)" : "var(--danger)") : undefined }}>{winst != null ? (winst >= 0 ? "+" : "−") + fmtEur(Math.abs(winst)) : "—"}</td>
                <td><span className={"pill " + rc[0]}>{rc[1]}</span></td>
              </tr>
            ); })}
          </tbody>
        </table>
      </div>
    </Card>
  );
}

/* productkaart */
function AdvCard({ r, db, onAsk }) {
  const [open, setOpen] = React.useState(false);
  const p = r.p, a = r.a;
  const E = (v) => v != null ? fmtEur(v) : "—";
  const stockPct = r.dagen != null ? Math.min(100, r.dagen / 60 * 100) : ((p.stock || 0) > 0 ? 60 : 0);
  const stockCol = (p.stock || 0) < 15 ? "var(--danger)" : (r.dagen != null && r.dagen < 25 ? "var(--warn)" : "var(--ok)");
  const top = r.concl[0];
  return (
    <Card>
      <div className="card-pad" style={{ paddingBottom: 12 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 10 }}>
          <AdvScore score={r.score} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontWeight: 700, fontSize: 14, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{p.name}</div>
            <div style={{ display: "flex", gap: 5, flexWrap: "wrap", marginTop: 4 }}>
              {r.labels.slice(0, 3).map(([sev, txt]) => <span key={txt} className={"pill " + (sev === "info" ? "accent" : sev)} style={{ fontSize: 10.5 }}>{txt}</span>)}
              {!r.hasAds && <span className="pill neutral" style={{ fontSize: 10.5 }}>geen ads actief</span>}
            </div>
          </div>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 6, marginBottom: 8 }}>
          <AdvStat label="Verkoop" value={r.di.q + "×"} hint="verkochte stuks in deze periode" />
          <AdvStat label="Omzet" value={E(Math.round(r.di.rev))} />
          <AdvStat label="Winst" value={r.wi ? E(Math.round(r.wi.na)) : "—"} color={r.wi ? (r.wi.na >= 0 ? "var(--ok)" : "var(--danger)") : null} hint="winst na belasting (deze periode)" />
          <AdvStat label="Adkosten" value={E(a.cost)} />
          <AdvStat label="ROAS" value={r.roas != null ? r.roas.toFixed(1) + "×" : "—"} color={r.roas != null && r.be != null ? (r.roas >= r.be ? "var(--ok)" : "var(--danger)") : null} hint={"omzet per ad-euro" + (r.be != null ? " · break-even: " + r.be.toFixed(1) + "×" : "")} />
          <AdvStat label="CPA" value={r.cpa != null ? E(r.cpa) : "—"} color={r.cpa != null && r.marge != null ? (r.cpa <= r.marge ? "var(--ok)" : "var(--danger)") : null} hint="wat één verkoop via ads kost" />
          <AdvStat label="Conversie" value={r.conv != null ? r.conv.toFixed(1) + "%" : "—"} hint="hoeveel klikkers kopen" />
          <AdvStat label="SEO" value={r.seo ? "#" + r.seo.pos.toFixed(1) : "—"} hint={r.seo ? "beste positie · \u201c" + r.seo.kw + "\u201d" : "geen organische positie gevonden"} />
        </div>
        <div style={{ display: "grid", gap: 5, marginBottom: 10 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 11.5 }}>
            <span className="muted" style={{ width: 62, flex: "none" }}>Marge</span>
            <AdvBar pct={(r.margePct || 0) * 2.2} color={r.margePct != null ? (r.margePct >= 20 ? "var(--ok)" : (r.margePct >= 10 ? "var(--warn)" : "var(--danger)")) : "var(--surface-3)"} />
            <span className="tnum" style={{ width: 70, textAlign: "right", fontWeight: 600 }}>{r.marge != null ? E(r.marge) + " (" + Math.round(r.margePct) + "%)" : "—"}</span>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 11.5 }}>
            <span className="muted" style={{ width: 62, flex: "none" }}>Voorraad</span>
            <AdvBar pct={stockPct} color={stockCol} />
            <span className="tnum" style={{ width: 70, textAlign: "right", fontWeight: 600 }}>{(p.stock || 0)}{r.dagen != null ? " · " + r.dagen + "d" : ""}</span>
          </div>
        </div>
        {top && (
          <div style={{ display: "flex", gap: 9, alignItems: "flex-start", background: "var(--surface-2)", border: "1px solid var(--border)", borderLeft: "3px solid " + ADV_SEV[top.sev], borderRadius: 9, padding: "9px 11px", fontSize: 12.5, lineHeight: 1.45 }}>
            <span style={{ fontWeight: 700, whiteSpace: "nowrap" }}>{top.txt}.</span>
          </div>
        )}
        <div style={{ display: "flex", gap: 6, marginTop: 10, flexWrap: "wrap" }}>
          {r.concl.length > 0 && <button className="btn btn-sm btn-ghost" onClick={() => setOpen(!open)}>{open ? "Verberg uitleg" : "Waarom? (" + r.concl.length + ")"}</button>}
          <button className="btn btn-sm btn-ghost" onClick={() => onAsk("Wat moet ik nu doen met " + p.name + "? Wees eerlijk en concreet.")}>Vraag AdPilot</button>
        </div>
        {open && (
          <div style={{ display: "grid", gap: 7, marginTop: 10 }}>
            {r.concl.map((c, i) => (
              <div key={i} style={{ fontSize: 12.5, lineHeight: 1.5, padding: "8px 10px", background: "var(--bg)", border: "1px solid var(--border)", borderLeft: "3px solid " + ADV_SEV[c.sev], borderRadius: 8 }}>
                <b>{c.txt}.</b> <span className="muted">{c.why}</span>
              </div>
            ))}
            <div className="muted" style={{ fontSize: 11.5 }}>Prijs {E(r.price)} · inkoop {E(r.inkoop)} · verzending {E(r.ship)} · CPC {r.cpc != null ? E(r.cpc) : "—"} {r.organic ? "· organisch " + r.organic.views + " weergaven (" + r.organic.page + ")" : ""}</div>
          </div>
        )}
      </div>
    </Card>
  );
}

/* heldere samenvatting in spreektaal */
function AdvSummary({ list, gList, perLabel }) {
  const gl = gList || [];
  const danger = list.filter(r => r.concl.some(c => c.sev === "danger"));
  const gDanger = gl.filter(c => c.concl.some(x => x.sev === "danger"));
  const gScale = gl.filter(c => c.concl.some(x => x.txt === "Budget verhogen kan"));
  const scale = list.filter(r => r.concl.some(c => c.txt.indexOf("Budget verhogen") === 0));
  const lowStock = list.filter(r => r.concl.some(c => c.txt.indexOf("Voorraad laag") === 0));
  const kans = list.filter(r => !r.hasAds && r.labels.some(l => l[1].indexOf("kans") >= 0));
  const healthy = !danger.length && !lowStock.length && !gDanger.length;
  const items = [];
  items.push([healthy ? "ok" : "warn", healthy ? "Je advertenties draaien gezond (" + perLabel.toLowerCase() + ")." : "Je advertenties vragen aandacht (" + perLabel.toLowerCase() + ")."]);
  if (scale.length) items.push(["ok", scale.length + " product" + (scale.length > 1 ? "en verdienen" : " verdient") + " extra budget: " + scale.map(r => r.p.name).slice(0, 3).join(", ") + "."]);
  if (danger.length) items.push(["danger", danger.length + " product" + (danger.length > 1 ? "en kosten" : " kost") + " geld zonder duidelijke opbrengst: " + danger.map(r => r.p.name).slice(0, 3).join(", ") + "."]);
  if (lowStock.length) items.push(["warn", lowStock.length + " product" + (lowStock.length > 1 ? "en hebben" : " heeft") + " voorraadrisico: " + lowStock.map(r => r.p.name).slice(0, 3).join(", ") + "."]);
  if (kans.length) items.push(["info", kans.length + " onbenutte kans" + (kans.length > 1 ? "en" : "") + ": " + kans.map(r => r.p.name).slice(0, 3).join(", ") + "."]);
  if (gScale.length) items.push(["ok", "Google: " + gScale.map(c => c.name).slice(0, 2).join(", ") + " kan meer budget aan."]);
  if (gDanger.length) items.push(["danger", "Google: " + gDanger.map(c => c.name).slice(0, 2).join(", ") + " kost geld zonder conversies."]);
  return (
    <Card style={{ marginBottom: "var(--space)" }}>
      <div className="card-pad" style={{ display: "grid", gap: 8 }}>
        {items.map(([sev, txt], i) => (
          <div key={i} style={{ display: "flex", gap: 10, alignItems: "flex-start", fontSize: i === 0 ? 15 : 13, fontWeight: i === 0 ? 700 : 500, lineHeight: 1.45 }}>
            <span style={{ width: 9, height: 9, borderRadius: 99, marginTop: i === 0 ? 7 : 5, flex: "none", background: ADV_SEV[sev] }}></span>
            <span>{txt}</span>
          </div>
        ))}
      </div>
    </Card>
  );
}

/* producten vergelijken */
function AdvCompare({ list }) {
  const [a, setA] = React.useState(list[0] ? list[0].p.sku : "");
  const [b, setB] = React.useState(list[1] ? list[1].p.sku : "");
  const ra = list.find(r => r.p.sku === a), rb = list.find(r => r.p.sku === b);
  if (list.length < 2) return null;
  const E = (v) => v != null ? fmtEur(v) : "—";
  const rowsDef = [
    ["Marge per verkoop", r => r.marge, E, true],
    ["Verkopen (periode)", r => r.di.q, v => v + "×", true],
    ["Adkosten", r => r.a.cost, E, false],
    ["ROAS", r => r.roas, v => v != null ? v.toFixed(1) + "×" : "—", true],
    ["CPA", r => r.cpa, E, false],
    ["SEO-positie", r => r.seo ? r.seo.pos : null, v => v != null ? "#" + v.toFixed(1) : "—", false],
    ["Score", r => r.score, v => v + "/100", true],
  ];
  const Sel = ({ val, set }) => (
    <select className="input" value={val} onChange={e => set(e.target.value)} style={{ fontSize: 13 }}>
      {list.map(r => <option key={r.p.sku} value={r.p.sku}>{r.p.name}</option>)}
    </select>
  );
  let advice = null;
  if (ra && rb && ra.p.sku !== rb.p.sku) {
    const wa = (ra.roas || 0) / (ra.be || 99) + (ra.margePct || 0) / 50, wb = (rb.roas || 0) / (rb.be || 99) + (rb.margePct || 0) / 50;
    const win = wa >= wb ? ra : rb, lose = wa >= wb ? rb : ra;
    advice = win.p.name + " is de sterkste combinatie van marge en advertentie-rendement — die verdient als eerste extra budget. " + lose.p.name + (lose.concl.some(c => c.sev === "danger") ? " is op dit moment niet rendabel: eerst bijsturen." : " kan meelopen op het huidige budget.");
  }
  return (
    <Card style={{ marginTop: "var(--space)" }}>
      <CardHead title="Producten vergelijken" icon="chart" sub="zet twee producten naast elkaar" />
      <div className="card-pad">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 12 }}>
          <Sel val={a} set={setA} /><Sel val={b} set={setB} />
        </div>
        {ra && rb && (
          <table className="tbl">
            <tbody>
              {rowsDef.map(([lbl, get, fmt, highGood]) => {
                const va = get(ra), vb = get(rb);
                const aWin = va != null && vb != null && va !== vb && (highGood ? va > vb : va < vb);
                const bWin = va != null && vb != null && va !== vb && !aWin;
                return (
                  <tr key={lbl}>
                    <td className="muted" style={{ fontSize: 12.5, width: "34%" }}>{lbl}</td>
                    <td className="tnum" style={{ fontWeight: aWin ? 800 : 500, color: aWin ? "var(--ok)" : undefined }}>{fmt(va)}</td>
                    <td className="tnum" style={{ fontWeight: bWin ? 800 : 500, color: bWin ? "var(--ok)" : undefined }}>{fmt(vb)}</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
        {advice && <div style={{ marginTop: 10, fontSize: 12.5, lineHeight: 1.5, background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 9, padding: "9px 11px" }}>💡 {advice}</div>}
      </div>
    </Card>
  );
}

/* begrippen voor niet-experts */
function AdvLegend() {
  const terms = [["ROAS", "hoeveel omzet je terugkrijgt per euro advertentiekosten"], ["CPA", "wat één verkoop via advertenties gemiddeld kost"], ["Conversie", "hoeveel procent van de klikkers ook echt koopt"], ["Break-even", "de ROAS die je minimaal nodig hebt om quitte te spelen"], ["CPC", "wat één klik gemiddeld kost"]];
  return (
    <div className="muted" style={{ fontSize: 11.5, lineHeight: 1.7, padding: "10px 4px 0" }}>
      {terms.map(([t, d]) => <span key={t} style={{ marginRight: 14 }}><b>{t}</b> = {d}</span>)}
    </div>
  );
}

/* ===== hoofdpagina ===== */
function AdvertentiesPro({ db, onNav }) {
  const period = db.period();
  const perLabel = (db.PERIODS.find(x => x.id === period) || {}).label || "";
  const list = React.useMemo(() => advBuild(db, period), [db, period, db.adsSyncedAt && db.adsSyncedAt()]);
  const g = (db.gadsData && db.gadsData()) || null;
  // props voor AdPilot-chat (zelfde brein als voorheen)
  const rows = list.filter(r => r.hasAds).map(r => ({ p: r.p, a: r.a }));
  const tot = rows.reduce((s, r) => { s.cost += r.a.cost; s.sales += r.a.sales; s.clicks += r.a.clicks; s.impressions += r.a.impressions; return s; }, { cost: 0, sales: 0, clicks: 0, impressions: 0 });
  const gRows = (db.gadsCampaigns && db.gadsCampaigns(period)) || [];
  const gTot = (db.gadsCost && db.gadsCost(period)) || 0;
  const gList = advBuildGoogle(db, period, g, gRows);
  const advies = list.flatMap(r => r.concl.map(c => ({ sev: c.sev === "info" ? "ok" : c.sev, txt: r.p.name + ": " + c.txt + ". " + c.why })))
    .concat(gList.flatMap(c => c.concl.filter(x => x.txt !== "Draait stabiel").map(x => ({ sev: x.sev === "info" ? "ok" : x.sev, txt: "Google · " + c.name + ": " + x.txt + ". " + x.why }))));
  const warns = list.flatMap(r => r.concl.filter(c => c.sev === "danger" || c.sev === "warn").map(c => ({ sev: c.sev, p: r.p.name, txt: c.txt })))
    .concat(gList.flatMap(c => c.concl.filter(x => x.sev === "danger" || x.sev === "warn").map(x => ({ sev: x.sev, p: "Google · " + c.name, txt: x.txt }))));
  const onAsk = (q) => {
    window.dispatchEvent(new CustomEvent("adpilot-ask", { detail: q }));
    const m = document.querySelector(".main"); if (m) m.scrollTop = 0;
    try { window.scrollTo({ top: 0, behavior: "smooth" }); } catch (e) {}
  };
  const Chat = window.AdPilotChat;
  const Zoek = window.ZoektermenCard, Acties = window.ActiesCard;
  const [src, setSrcState] = React.useState(() => { try { return localStorage.getItem("stocers_ads_tab") || "bol"; } catch (e) { return "bol"; } });
  const setSource = (s) => { setSrcState(s); try { localStorage.setItem("stocers_ads_tab", s); } catch (e) {} };
  const gValue = gRows.reduce((s, c) => s + (c.value || 0), 0);
  return (
    <div className="view">
      <div className="page-head">
        <div className="ph-row">
          <div>
            <h1>Advertenties</h1>
            <div className="ph-sub">Jouw slimme marketingmedewerker: ads, marge, voorraad en SEO in één eerlijk verhaal — ververst elke sync.</div>
          </div>
          <div className="seg" style={{ flexWrap: "wrap" }}>
            {db.PERIODS.map(per => (
              <button key={per.id} className={period === per.id ? "on" : ""} onClick={() => window.STORE.setPeriod(per.id)}>{per.label}</button>
            ))}
          </div>
        </div>
      </div>

      {(() => {
        const tips = {
          today: ["warn", "Vandaag: alleen kosten bewaken — bol rekent verkopen tot 14 dagen later toe, dus ROAS lijkt nu slechter dan hij is. Beslis op 30 dagen."],
          yesterday: ["warn", "Gisteren: handig voor kostencheck, maar nog niet alle ad-omzet is toegerekend. Beslis op 30 dagen."],
          d7: ["info", "7 dagen: goed om trends te checken. Voor beslissingen (budget op/af, pauzeren) is 30 dagen betrouwbaarder."],
          d30: ["ok", "30 dagen — aanbevolen: vangt bol's 14-daagse toerekening volledig af. De conclusies hieronder zijn nu het meest betrouwbaar."],
        };
        const [sev, txt] = tips[period] || ["info", "Lange periode: handig voor seizoenspatronen. Voor actuele beslissingen is 30 dagen de beste keuze."];
        return (
          <div style={{ display: "flex", gap: 9, alignItems: "flex-start", fontSize: 12.5, lineHeight: 1.45, background: "var(--surface-2)", border: "1px solid var(--border)", borderLeft: "3px solid " + ADV_SEV[sev], borderRadius: 9, padding: "8px 12px", marginBottom: "var(--space)" }}>
            <span>{period === "d30" ? "✓" : "💡"} {txt}</span>
          </div>
        );
      })()}

      {(() => {
        const span = { d90: 90, d180: 180, d365: 365 }[period];
        if (!span) return null;
        let minDay = null;
        try { const bs = ((db.bolAds && db.bolAds()) || {}).bySku || {}; for (const k in bs) for (const d in (bs[k].days || {})) if (!minDay || d < minDay) minDay = d; } catch (e) {}
        try { const gd = (g && g.byDay) || {}; for (const d in gd) if (!minDay || d < minDay) minDay = d; } catch (e) {}
        if (!minDay) return null;
        const from = new Date(Date.now() - span * 86400000);
        if (new Date(minDay) <= from) return null;
        return (
          <div style={{ display: "flex", gap: 9, alignItems: "flex-start", fontSize: 12.5, lineHeight: 1.45, background: "var(--surface-2)", border: "1px solid var(--border)", borderLeft: "3px solid var(--accent)", borderRadius: 9, padding: "8px 12px", marginBottom: "var(--space)" }}>
            <span>📆 Advertentiedata is beschikbaar vanaf <b>{new Date(minDay).toLocaleDateString("nl-NL", { day: "numeric", month: "short", year: "numeric" })}</b> — deze periode toont dus alleen dat deel. De bol-historie groeit nu automatisch aan (bol levert max ±35 dagen per rapport).</span>
          </div>
        );
      })()}

      {Chat && <Chat db={db} advies={advies} g={g} rows={rows} tot={tot} gRows={gRows} gTot={gTot} perLabel={perLabel} />}

      <AdvSummary list={list} gList={gList} perLabel={perLabel} />

      <div style={{ display: "inline-flex", background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 12, padding: 4, gap: 4, marginBottom: "var(--space)" }}>
        {[["bol", "bol.com · NL + BE"], ["google", "Google Ads · doosjehout.nl"]].map(([id, label]) => (
          <button key={id} onClick={() => setSource(id)} style={{ border: "none", cursor: "pointer", borderRadius: 9, padding: "9px 18px", fontSize: 13, fontWeight: 700, background: src === id ? "var(--brand)" : "transparent", color: src === id ? "#fff" : "var(--text-2)", transition: ".15s" }}>{label}</button>
        ))}
      </div>

      {src === "bol" && <React.Fragment>
      {warns.length > 0 && (
        <Card style={{ marginBottom: "var(--space)" }}>
          <CardHead title="Slimme waarschuwingen" icon="alert" />
          <div className="card-pad" style={{ display: "grid", gap: 8, paddingTop: 4 }}>
            {warns.slice(0, 6).map((w, i) => (
              <div key={i} style={{ display: "flex", gap: 9, alignItems: "flex-start", fontSize: 12.5, lineHeight: 1.45 }}>
                <span style={{ width: 8, height: 8, borderRadius: 99, marginTop: 5, flex: "none", background: ADV_SEV[w.sev] }}></span>
                <span><b>{w.p}</b> — {w.txt}.</span>
              </div>
            ))}
          </div>
        </Card>
      )}

      <div className="muted" style={{ fontSize: 12, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em", margin: "4px 2px 10px" }}>Per product · bol-advertenties, marge, voorraad & SEO verbonden</div>
      <div className="muted" style={{ fontSize: 11.5, lineHeight: 1.5, margin: "-4px 2px 10px" }}>Let op: de “ad-omzet” hieronder is het deel van je gewone omzet dat bol aan advertenties toeschrijft (14 dagen) — tel hem dus niet óp bij de omzet van de Winst-pagina.</div>
      <div className="grid cols-2" style={{ gap: "var(--space)", marginBottom: "var(--space)", alignItems: "start" }}>
        {list.map(r => <AdvCard key={r.p.sku} r={r} db={db} onAsk={onAsk} />)}
        {!list.length && <Card><div className="card-pad muted" style={{ fontSize: 13 }}>Nog geen advertentie- of verkoopdata in deze periode.</div></Card>}
      </div>

      <AdvCompare list={list} />
      </React.Fragment>}

      {src === "google" && <React.Fragment>
      {(period === "today" || period === "yesterday") && (
        <div style={{ display: "flex", gap: 9, alignItems: "flex-start", fontSize: 12.5, lineHeight: 1.45, background: "var(--surface-2)", border: "1px solid var(--border)", borderLeft: "3px solid var(--warn)", borderRadius: 9, padding: "8px 12px", marginBottom: "var(--space)" }}>
          <span>⏳ {period === "today" ? "Google levert dagcijfers t/m gisteren — vandaag toont daarom nog €0. Dit is normaal; morgen staan de cijfers van vandaag erin." : "Gisteren is de meest recente dag die Google aanlevert — conversies kunnen nog nadruppelen."}</span>
        </div>
      )}
      <div className="grid cols-4" style={{ marginBottom: "var(--space)" }}>
        <KPI icon="euro" iconBg="var(--accent-soft)" iconColor="var(--accent)" label={"Adkosten Google · " + perLabel.toLowerCase()} value={fmtEur(Math.round(gTot))} foot="doosjehout.nl" />
        <KPI icon="chart" iconBg="var(--ok-soft)" iconColor="var(--ok)" label="Conversiewaarde" value={gValue > 0 ? fmtEur(Math.round(gValue)) : "—"} foot="toegeschreven aan ads" />
        <KPI icon="trending" iconBg="var(--brand-soft)" iconColor="var(--brand)" label="ROAS" value={gTot > 0 && gValue > 0 ? (gValue / gTot).toFixed(2) + "×" : "—"} foot="conversiewaarde ÷ kosten" />
        <KPI icon="check" iconBg="var(--surface-3)" iconColor="var(--text-2)" label="Campagnes met kosten" value={gRows.length} foot={"in " + perLabel.toLowerCase()} />
      </div>
      <div className="muted" style={{ fontSize: 12, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em", margin: "4px 2px 10px" }}>Per campagne · eerlijke analyse + directe acties</div>
      <div className="grid cols-2" style={{ gap: "var(--space)", marginBottom: "var(--space)", alignItems: "start" }}>
        {gList.map(c => <GAdsCard key={c.name} c={c} db={db} onAsk={onAsk} />)}
        {!gList.length && <Card><div className="card-pad muted" style={{ fontSize: 13 }}>Geen Google-campagnes met kosten in deze periode — kies een langere periode of ververs de data.</div></Card>}
      </div>
      <GProductsCard g={g} db={db} />
      {Zoek && <Zoek g={g} db={db} />}
      </React.Fragment>}

      <AdvLegend />
    </div>
  );
}

Object.assign(window, { AdvertentiesPro });



