/* More views: Reviews, Rankings, SEO, Meldingen, Instellingen. Exported to window. */

/* ============================ REVIEWS ============================ */
function Reviews({ db, onNav }) {
  const ai = db.reviewAI;
  const maxPos = Math.max(...ai.positives.map(x => x.count));
  const maxNeg = Math.max(...ai.negatives.map(x => x.count));
  const rv = (p) => db.reviewFor(p.sku);
  const realList = db.products.map(p => rv(p)).filter(Boolean);
  const hasReal = realList.length > 0;
  // totalen/gemiddelde over unieke review-bronnen (varianten delen reviews → 1× tellen)
  const realGroups = db.reviewGroups ? db.reviewGroups() : realList.map(r => ({ count: r.count, rating: r.rating }));
  const realCount = realGroups.reduce((s, r) => s + (r.count || 0), 0);
  const realAvg = realGroups.length ? (realGroups.reduce((s, r) => s + (r.rating || 0) * (r.count || 1), 0) / realGroups.reduce((s, r) => s + (r.count || 1), 0)) : 0;
  const syncedAt = db.reviewsSyncedAt && db.reviewsSyncedAt();
  const warnings = db.products.filter(p => { const r = rv(p); return r ? (r.rating != null && r.rating < 4.0) : (p.rev.trend === "down" || p.rev.avg < 4.0); });
  const totalReviews = hasReal ? realCount : db.products.reduce((s, p) => s + p.rev.count, 0);
  const newReviews = db.products.reduce((s, p) => s + p.rev.newC, 0);

  return (
    <div className="view">
      <div className="page-head">
        <div className="ph-row">
          <div>
            <h1>Reviews</h1>
            <div className="ph-sub">{hasReal
              ? <span>Automatisch van bol.com{syncedAt ? " · bijgewerkt " + new Date(syncedAt).toLocaleDateString("nl-NL", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }) : ""} <span className="pill ok" style={{ marginLeft: 6 }}><span className="pdot" />Live</span></span>
              : <span>Wekelijks van bol.com · <span className="pill warn" style={{ marginLeft: 2 }}><span className="pdot" />nog niet opgehaald</span></span>}</div>
          </div>
          {hasReal && <button className="btn btn-sm btn-ghost" onClick={() => db.refreshReviews()}><Icon name="refresh" size={14} />Nu ophalen</button>}
        </div>
      </div>

      <div className="grid cols-4" style={{ marginBottom: "var(--space)" }}>
        <KPI icon="star" iconBg="var(--warn-soft)" iconColor="var(--warn)" label="Gem. score" value={hasReal ? realAvg.toFixed(1) : db.kpis.reviewAvg.toFixed(1)} foot={hasReal ? "gewogen, van bol" : "alle producten"} />
        <KPI icon="doc" iconBg="var(--surface-3)" iconColor="var(--text-2)" label="Totaal reviews" value={fmtNum(totalReviews)} foot={hasReal ? "van bol.com" : "over alle bronnen"} />
        <KPI icon="tag" iconBg="var(--accent-soft)" iconColor="var(--accent)" label="Producten gemeten" value={hasReal ? realList.length : db.products.length} foot="met bol-reviewlink" />
        <KPI icon="alert" iconBg="var(--danger-soft)" iconColor="var(--danger)" label="Onder 4,0" value={warnings.length} foot="producten met lage score" />
      </div>

      {/* AI analysis */}

      <div>
        <Card>
          <CardHead title="Per product" icon="tag" />
          <table className="tbl">
            <thead><tr><th>Product</th><th>Score</th><th className="num">Reviews</th><th className="num">Nieuw</th><th>Bol</th></tr></thead>
            <tbody>
              {db.products.slice().map(p => ({ p, r: rv(p) })).sort((a, b) => (db.reviewIsNew(b.r) - db.reviewIsNew(a.r)) || ((b.r && b.r.since) || "").localeCompare((a.r && a.r.since) || "") || ((b.r ? b.r.count : b.p.rev.count) || 0) - ((a.r ? a.r.count : a.p.rev.count) || 0)).map(({ p, r }) => {
                const link = (window.STORE && window.STORE.reviewLink(p.sku)) || (r && r.url);
                const score = r && r.rating != null ? r.rating : p.rev.avg;
                const cnt = r && r.count != null ? r.count : p.rev.count;
                const nw = r ? (r["new"] || 0) : 0;
                const isNew = db.reviewIsNew(r);
                return (
                <tr key={p.id} className="row-click" onClick={() => onNav("producten", p.id)}>
                  <td><div className="prod"><ProductThumb p={p} size={32} /><span style={{ fontWeight: 600, fontSize: 13 }}>{p.name}</span></div></td>
                  <td><div style={{ display: "flex", alignItems: "center", gap: 6 }}><Stars value={score} size={13} /><b>{score.toFixed(1)}</b></div></td>
                  <td className="num tnum muted">{cnt}</td>
                  <td className="num">{isNew ? <NieuwBadge sku={p.sku} style={{ fontSize: 11 }}>Nieuw +{nw}</NieuwBadge> : <span className="muted">—</span>}</td>
                  <td>{link ? <a href={link} target="_blank" rel="noreferrer" title="Open op bol.com" onClick={e => e.stopPropagation()} style={{ color: "var(--accent)", display: "inline-flex" }}><Icon name="external" size={15} /></a> : <span className="muted">—</span>}</td>
                </tr>
              );})}
            </tbody>
          </table>
        </Card>
      </div>
    </div>
  );
}

/* ============================ RANKINGS ============================ */
function Rankings({ db, onNav }) {
  const gsc = (db.gscData && db.gscData()) || null;
  const rows = React.useMemo(() => {
    if (!gsc || !gsc.queries) return [];
    const prev = {}; (gsc.prevQueries || []).forEach(q => { prev[q.query] = q; });
    return gsc.queries.filter(q => q.clicks > 0 || q.impressions >= 30).map(q => {
      const p2 = prev[q.query];
      return { kw: q.query, cur: q.position, prevPos: p2 ? p2.position : null, clicks: q.clicks, imp: q.impressions, ctr: q.ctr, delta: p2 ? +(p2.position - q.position).toFixed(1) : null };
    });
  }, [gsc]);
  const [sel, setSel] = React.useState(null);
  const kw = rows.find(r => r.kw === sel) || rows[0];
  if (!rows.length) {
    return (
      <div className="view">
        <div className="page-head"><h1>Rankings</h1><div className="ph-sub">Google-posities per zoekwoord, live uit Search Console.</div></div>
        <Card><div className="card-pad"><Placeholder label="Nog geen data" note="De Search Console-koppeling staat klaar — data verschijnt na de eerste sync." height={120} /></div></Card>
      </div>
    );
  }
  const movers = rows.filter(r => r.delta != null && Math.abs(r.delta) >= 1 && (r.clicks > 0 || r.imp >= 100)).sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta)).slice(0, 8);
  return (
    <div className="view">
      <div className="page-head">
        <h1>Rankings</h1>
        <div className="ph-sub">Google-posities per zoekwoord · laatste 30 dagen vs. de 28 dagen daarvoor · live uit Search Console. <span className="pill ok" style={{ marginLeft: 6 }}><span className="pdot" />Live</span></div>
      </div>

      <div className="grid col-5-7" style={{ marginBottom: "var(--space)" }}>
        <Card>
          <CardHead title="Zoekwoorden" icon="search2" sub={rows.length + " met vertoningen"} right={<button className="btn btn-sm btn-ghost" onClick={() => db.refreshGsc && db.refreshGsc()}><Icon name="refresh" size={14} />Verversen</button>} />
          <div style={{ maxHeight: 430, overflowY: "auto" }}>
            {rows.map(k => (
              <button key={k.kw} onClick={() => setSel(k.kw)} className="lrow" style={{ width: "100%", border: "none", background: kw && kw.kw === k.kw ? "var(--surface-2)" : "none", borderLeft: kw && kw.kw === k.kw ? "3px solid var(--brand)" : "3px solid transparent", padding: "11px 16px", textAlign: "left", cursor: "pointer" }}>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontWeight: 600, fontSize: 13.5, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{k.kw}</div>
                  <div className="muted mono" style={{ fontSize: 11 }}>{fmtNum(k.imp)} vertoningen · {k.clicks} clicks</div>
                </div>
                <span className="pill neutral" style={{ minWidth: 44, justifyContent: "center" }}>#{k.cur.toFixed(1)}</span>
                {k.delta != null && Math.abs(k.delta) >= 0.5 && <span className={"delta " + (k.delta > 0 ? "up" : "down")} style={{ minWidth: 34 }}><Icon name={k.delta > 0 ? "arrowUp" : "arrowDown"} size={12} sw={2.4} />{Math.abs(k.delta).toFixed(1)}</span>}
              </button>
            ))}
          </div>
        </Card>

        <Card>
          <CardHead title={"\u201c" + kw.kw + "\u201d"} sub="Google-zoekresultaten · doosjehout.nl" icon="trending"
            right={kw.delta != null ? <span className={"pill " + (kw.delta >= 0 ? "ok" : "danger")}><Icon name={kw.delta >= 0 ? "arrowUp" : "arrowDown"} size={13} />{kw.delta >= 0 ? "+" : ""}{kw.delta} vs. vorige periode</span> : <span className="pill neutral">nieuw zoekwoord</span>} />
          <div className="card-pad">
            <div style={{ display: "flex", gap: 28, marginBottom: 16, flexWrap: "wrap" }}>
              <div><div className="muted" style={{ fontSize: 12 }}>Positie nu</div><div style={{ fontSize: 32, fontWeight: 700 }}>#{kw.cur.toFixed(1)}</div></div>
              <div><div className="muted" style={{ fontSize: 12 }}>Vorige periode</div><div style={{ fontSize: 32, fontWeight: 700, color: "var(--text-3)" }}>{kw.prevPos != null ? "#" + kw.prevPos.toFixed(1) : "—"}</div></div>
              <div><div className="muted" style={{ fontSize: 12 }}>Vertoningen</div><div style={{ fontSize: 32, fontWeight: 700, color: "var(--text-3)" }}>{fmtNum(kw.imp)}</div></div>
              <div><div className="muted" style={{ fontSize: 12 }}>Clicks</div><div style={{ fontSize: 32, fontWeight: 700, color: "var(--text-3)" }}>{kw.clicks}</div></div>
              <div><div className="muted" style={{ fontSize: 12 }}>CTR</div><div style={{ fontSize: 32, fontWeight: 700, color: "var(--text-3)" }}>{(kw.ctr * 100).toFixed(1)}%</div></div>
            </div>
            <div className="muted" style={{ fontSize: 12.5, lineHeight: 1.5 }}>
              {kw.cur <= 3 ? "Toppositie — je staat in de top 3 van Google. Vasthouden: houd de pagina actueel en bewaak je reviews." :
               kw.cur <= 10 ? "Eerste pagina van Google. Met een sterkere paginatitel en meer interne links kan dit richting de top 3." :
               "Pagina 2 of lager — hier valt te winnen. Check de SEO-audit van de bijbehorende pagina voor concrete verbeterpunten."}
            </div>
            <div style={{ marginTop: 10 }}><button className="btn btn-sm btn-ghost" onClick={() => onNav && onNav("seo")}>Bekijk SEO-audit van je pagina's →</button></div>
          </div>
        </Card>
      </div>

      <Card>
        <CardHead title="Opvallende bewegingen" icon="alert" sub="grootste positieveranderingen · 30 dgn vs. periode ervoor" />
        <div className="card-pad" style={{ display: "grid", gap: 10, gridTemplateColumns: "1fr 1fr" }}>
          {!movers.length && <div className="muted" style={{ fontSize: 13 }}>Geen grote verschuivingen — je posities zijn stabiel.</div>}
          {movers.map(k => {
            const up = k.delta > 0;
            return (
              <div key={k.kw} className="att-item" style={{ borderColor: up ? "var(--ok-line)" : "var(--danger-line)" }}>
                <span className="att-ico" style={{ background: up ? "var(--ok-soft)" : "var(--danger-soft)", color: up ? "var(--ok)" : "var(--danger)" }}><Icon name={up ? "arrowUp" : "arrowDown"} size={18} /></span>
                <div className="att-body">
                  <div className="att-title">“{k.kw}” {up ? "gestegen" : "gedaald"}</div>
                  <div className="att-desc">Positie #{k.prevPos.toFixed(1)} → #{k.cur.toFixed(1)} · {fmtNum(k.imp)} vertoningen</div>
                </div>
              </div>
            );
          })}
        </div>
      </Card>
    </div>
  );
}

/* ============================ SEO ============================ */
const SEO_CHECKS = [
  { k: "title", label: "Paginatitel" }, { k: "meta", label: "Meta description" },
  { k: "h1", label: "H1" }, { k: "h2", label: "H2-structuur" },
  { k: "alt", label: "Alt-teksten" }, { k: "links", label: "Interne links" },
  { k: "schema", label: "Structured data" }, { k: "kw", label: "Zoekwoordgebruik" },
  { k: "speed", label: "Paginasnelheid" },
];
function SEO({ db, onNav }) {
  const [sel, setSel] = React.useState(db.seoPages[1].id);
  const page = db.seoPages.find(s => s.id === sel);
  const p = db.byId(page.id);
  const avg = Math.round(db.seoPages.reduce((s, x) => s + x.score, 0) / db.seoPages.length);
  const gsc = (db.gscData && db.gscData()) || null;
  const ga4 = (db.ga4Data && db.ga4Data()) || null;
  const audit = (db.seoAudit && db.seoAudit()) || null;
  const pct = (now, before) => (before > 0) ? Math.round((now - before) / before * 100) : null;
  const D = ({ now, before, invert }) => {
    const d = pct(now, before);
    if (d == null) return null;
    const good = invert ? d <= 0 : d >= 0;
    return <span style={{ fontWeight: 700, color: good ? "var(--ok)" : "var(--danger)" }}>{d >= 0 ? "+" + d : d}%</span>;
  };

  return (
    <div className="view">
      <div className="page-head">
        <h1>SEO</h1>
        <div className="ph-sub">Vindbaarheid van doosjehout.nl — live uit Google Search Console en Analytics, plus audit per productpagina.</div>
      </div>

      {gsc && gsc.total && (
        <React.Fragment>
          <div className="grid cols-4" style={{ marginBottom: "var(--space)" }}>
            <KPI icon="search2" iconBg="var(--accent-soft)" iconColor="var(--accent)" label="Google-clicks · 30 dgn" value={gsc.total.clicks.toLocaleString("nl-NL")} foot={<span>vorige periode {gsc.prevTotal ? gsc.prevTotal.clicks.toLocaleString("nl-NL") : "—"} · <D now={gsc.total.clicks} before={gsc.prevTotal && gsc.prevTotal.clicks} /></span>} />
            <KPI icon="chart" iconBg="var(--surface-3)" iconColor="var(--text-2)" label="Vertoningen" value={gsc.total.impressions.toLocaleString("nl-NL")} foot={<span><D now={gsc.total.impressions} before={gsc.prevTotal && gsc.prevTotal.impressions} /> vs vorige 28 dgn</span>} />
            <KPI icon="trending" iconBg="var(--brand-soft)" iconColor="var(--brand)" label="Gem. positie" value={gsc.total.position.toFixed(1)} foot={<span>{gsc.prevTotal ? "was " + gsc.prevTotal.position.toFixed(1) : ""} (lager = beter)</span>} />
            <KPI icon="star" iconBg="var(--ok-soft)" iconColor="var(--ok)" label="CTR" value={(gsc.total.ctr * 100).toFixed(1) + "%"} foot={gsc.prevTotal ? "was " + (gsc.prevTotal.ctr * 100).toFixed(1) + "%" : ""} />
          </div>
          <div className="grid col-7-5" style={{ marginBottom: "var(--space)" }}>
            <Card>
              <CardHead title="Topzoekwoorden · Google" icon="search2" sub="laatste 30 dagen · Search Console" right={<button className="btn btn-sm btn-ghost" onClick={() => db.refreshGsc && db.refreshGsc()}><Icon name="refresh" size={14} />Verversen</button>} />
              <div style={{ overflowX: "auto" }}>
                <table className="tbl">
                  <thead><tr><th>Zoekwoord</th><th className="num">Positie</th><th className="num">Clicks</th><th className="num">Vertoningen</th><th className="num">CTR</th></tr></thead>
                  <tbody>
                    {(gsc.queries || []).slice(0, 12).map(q => (
                      <tr key={q.query}>
                        <td style={{ fontWeight: 600, fontSize: 13 }}>“{q.query}”</td>
                        <td className="num tnum" style={{ fontWeight: 700, color: q.position <= 3 ? "var(--ok)" : (q.position > 10 ? "var(--text-3)" : undefined) }}>{q.position.toFixed(1)}</td>
                        <td className="num tnum">{q.clicks}</td>
                        <td className="num tnum muted">{q.impressions.toLocaleString("nl-NL")}</td>
                        <td className="num tnum muted">{(q.ctr * 100).toFixed(1)}%</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </Card>
            <Card>
              <CardHead title="Best gevonden pagina's" icon="doc" sub="clicks uit Google · 30 dagen" />
              <div className="card-pad" style={{ paddingTop: 4 }}>
                {(gsc.pages || []).slice(0, 10).map((pg, i) => {
                  const path = pg.page.replace(/^https?:\/\/[^/]+/, "") || "/";
                  const max = Math.max(...(gsc.pages || []).map(x => x.clicks), 1);
                  return (
                    <div key={pg.page} style={{ padding: "7px 0", borderTop: i ? "1px solid var(--border)" : "none" }}>
                      <div style={{ display: "flex", justifyContent: "space-between", gap: 10, fontSize: 12.5, marginBottom: 4 }}>
                        <span className="mono" style={{ whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{path}</span>
                        <span className="tnum" style={{ fontWeight: 700, whiteSpace: "nowrap" }}>{pg.clicks}</span>
                      </div>
                      <div style={{ height: 4, borderRadius: 99, background: "var(--surface-3)" }}><div style={{ height: "100%", width: Math.max(3, pg.clicks / max * 100) + "%", borderRadius: 99, background: "var(--brand)" }}></div></div>
                    </div>
                  );
                })}
              </div>
            </Card>
          </div>
        </React.Fragment>
      )}

      {ga4 && (ga4.total || (ga4.byDay || []).length > 0) && (
        <Card style={{ marginBottom: "var(--space)" }}>
          <CardHead title="Bezoek & conversie · doosjehout.nl" icon="chart" sub="laatste 30 dagen · Google Analytics 4" right={<button className="btn btn-sm btn-ghost" onClick={() => db.refreshGa4 && db.refreshGa4()}><Icon name="refresh" size={14} />Verversen</button>} />
          <div className="card-pad">
            {ga4.total && (
              <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(120px, 1fr))", gap: 10, marginBottom: 14 }}>
                {[["Bezoekers", ga4.total.users.toLocaleString("nl-NL"), ga4.prevTotal && <D now={ga4.total.users} before={ga4.prevTotal.users} />], ["Sessies", ga4.total.sessions.toLocaleString("nl-NL"), ga4.prevTotal && <D now={ga4.total.sessions} before={ga4.prevTotal.sessions} />], ["Webshop-conversies (GA4)", ga4.total.conversions.toLocaleString("nl-NL"), ga4.prevTotal && <D now={ga4.total.conversions} before={ga4.prevTotal.conversions} />], ["Omzet (GA4)", fmtEur(ga4.total.revenue), ga4.prevTotal && <D now={ga4.total.revenue} before={ga4.prevTotal.revenue} />]].map(([l, v, d]) => (
                  <div key={l} style={{ background: "var(--bg)", border: "1px solid var(--border)", borderRadius: 10, padding: "10px 12px" }}>
                    <div className="muted" style={{ fontSize: 10.5, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em" }}>{l}</div>
                    <div className="tnum" style={{ fontSize: 18, fontWeight: 700, marginTop: 2 }}>{v} <span style={{ fontSize: 12 }}>{d}</span></div>
                  </div>
                ))}
              </div>
            )}
            <div className="grid col-7-5">
              <div>
                <div className="muted" style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em", marginBottom: 4 }}>Meest bekeken pagina's</div>
                <table className="tbl">
                  <thead><tr><th>Pagina</th><th className="num">Weergaven</th><th className="num">Bezoekers</th></tr></thead>
                  <tbody>
                    {(ga4.pages || []).slice(0, 8).map(pg => (
                      <tr key={pg.page}><td className="mono" style={{ fontSize: 12 }}>{pg.page}</td><td className="num tnum">{pg.views.toLocaleString("nl-NL")}</td><td className="num tnum muted">{pg.users.toLocaleString("nl-NL")}</td></tr>
                    ))}
                  </tbody>
                </table>
              </div>
              <div>
                <div className="muted" style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em", marginBottom: 4 }}>Verkeersbronnen</div>
                {(ga4.channels || []).sort((a, b) => b.sessions - a.sessions).map((c, i) => {
                  const max = Math.max(...(ga4.channels || []).map(x => x.sessions), 1);
                  return (
                    <div key={c.channel} style={{ padding: "7px 0", borderTop: i ? "1px solid var(--border)" : "none" }}>
                      <div style={{ display: "flex", justifyContent: "space-between", gap: 10, fontSize: 12.5, marginBottom: 4 }}>
                        <span style={{ fontWeight: 600 }}>{c.channel}</span>
                        <span className="tnum" style={{ whiteSpace: "nowrap" }}>{c.sessions.toLocaleString("nl-NL")} <span className="muted">· {c.conversions} conv.</span></span>
                      </div>
                      <div style={{ height: 4, borderRadius: 99, background: "var(--surface-3)" }}><div style={{ height: "100%", width: Math.max(3, c.sessions / max * 100) + "%", borderRadius: 99, background: "var(--accent)" }}></div></div>
                    </div>
                  );
                })}
              </div>
            </div>
          </div>
        </Card>
      )}

      <div className="muted" style={{ fontSize: 12, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em", margin: "4px 2px 10px" }}>Audit per productpagina {audit ? <span className="pill ok" style={{ marginLeft: 6 }}><span className="pdot" />Live · best gevonden pagina's gescand</span> : <span className="pill warn" style={{ marginLeft: 6 }}><span className="pdot" />Demo</span>}</div>

      {audit ? <SEOAuditReal audit={audit} db={db} /> : <React.Fragment>
      <div className="grid cols-4" style={{ marginBottom: "var(--space)" }}>
        <KPI icon="search2" iconBg="var(--accent-soft)" iconColor="var(--accent)" label="Gem. SEO-score" value={avg + "/100"} foot="over auditpagina's" />
        <KPI icon="doc" iconBg="var(--surface-3)" iconColor="var(--text-2)" label="Pagina's" value={db.seoPages.length} foot="in audit" />
        <KPI icon="alert" iconBg="var(--danger-soft)" iconColor="var(--danger)" label="< 65 score" value={db.seoPages.filter(s => s.score < 65).length} foot="vragen aandacht" />
        <KPI icon="check" iconBg="var(--ok-soft)" iconColor="var(--ok)" label="≥ 80 score" value={db.seoPages.filter(s => s.score >= 80).length} foot="op orde" />
      </div>

      <div className="grid col-5-7">
        <Card>
          <CardHead title="Productpagina's" icon="doc" />
          <div>
            {db.seoPages.map(s => (
              <button key={s.id} onClick={() => setSel(s.id)} className="lrow" style={{ width: "100%", border: "none", background: sel === s.id ? "var(--surface-2)" : "none", borderLeft: sel === s.id ? "3px solid var(--brand)" : "3px solid transparent", padding: "12px 16px", textAlign: "left", cursor: "pointer", gap: 12 }}>
                <ScoreRing score={s.score} size={42} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontWeight: 600, fontSize: 13 }}>{db.byId(s.id).name}</div>
                  <div className="mono muted" style={{ fontSize: 11, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{s.url}</div>
                </div>
              </button>
            ))}
          </div>
        </Card>

        <Card>
          <CardHead title={page.url} icon="search2" sub={p.name}
            right={<a className="btn btn-sm" href={db.company.shopUrl} target="_blank" rel="noreferrer">Bekijk pagina<Icon name="external" size={14} /></a>} />
          <div className="card-pad">
            <div style={{ display: "flex", gap: 20, alignItems: "center", marginBottom: 18 }}>
              <ScoreRing score={page.score} size={76} />
              <div>
                <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 2 }}>SEO Score: {page.score}/100</div>
                <div className="muted" style={{ fontSize: 12.5 }}>{page.words} woorden · {SEO_CHECKS.filter(c => page.checks[c.k]).length}/{SEO_CHECKS.length} checks geslaagd</div>
              </div>
            </div>

            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 20 }}>
              {SEO_CHECKS.map(c => (
                <div key={c.k} style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 12.5 }}>
                  <span style={{ width: 18, height: 18, borderRadius: 5, display: "grid", placeContent: "center", background: page.checks[c.k] ? "var(--ok-soft)" : "var(--danger-soft)", color: page.checks[c.k] ? "var(--ok)" : "var(--danger)", flex: "none" }}>
                    <Icon name={page.checks[c.k] ? "check" : "x"} size={12} sw={2.6} />
                  </span>
                  <span style={{ color: page.checks[c.k] ? "var(--text-2)" : "var(--text)" }}>{c.label}</span>
                </div>
              ))}
            </div>

            <div className="ai-tag" style={{ marginBottom: 12 }}><Icon name="sparkles" size={13} />AI SEO-adviseur · specifiek voor deze pagina</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              {page.advice.map((a, i) => (
                <div key={i} style={{ display: "flex", gap: 10, alignItems: "flex-start", background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 9, padding: "10px 12px" }}>
                  <span style={{ width: 20, height: 20, borderRadius: 6, background: "var(--accent-soft)", color: "var(--accent)", display: "grid", placeContent: "center", fontSize: 11, fontWeight: 700, flex: "none" }}>{i + 1}</span>
                  <span style={{ fontSize: 13, lineHeight: 1.5 }}>{a}</span>
                </div>
              ))}
            </div>
          </div>
        </Card>
      </div>
      </React.Fragment>}
    </div>
  );
}

/* echte SEO-audit — gescande pagina's uit de datakraan */
const AUDIT_LABELS = { title: "Paginatitel", meta: "Meta description", h1: "H1", h2: "H2-structuur", alt: "Alt-teksten", links: "Interne links", schema: "Structured data", words: "Tekstlengte", speed: "Laadtijd" };
function SEOAuditReal({ audit, db }) {
  const pages = (audit.pages || []).slice().sort((a, b) => (b.clicks || 0) - (a.clicks || 0));
  const [sel, setSel] = React.useState(0);
  const pg = pages[Math.min(sel, pages.length - 1)];
  if (!pg) return null;
  const avg = Math.round(pages.reduce((s, x) => s + x.score, 0) / pages.length);
  const keys = Object.keys(AUDIT_LABELS);
  return (
    <React.Fragment>
      <div className="grid cols-4" style={{ marginBottom: "var(--space)" }}>
        <KPI icon="search2" iconBg="var(--accent-soft)" iconColor="var(--accent)" label="Gem. SEO-score" value={avg + "/100"} foot={"over " + pages.length + " gescande pagina's"} />
        <KPI icon="doc" iconBg="var(--surface-3)" iconColor="var(--text-2)" label="Pagina's" value={pages.length} foot="best gevonden via Google" />
        <KPI icon="alert" iconBg="var(--danger-soft)" iconColor="var(--danger)" label="< 65 score" value={pages.filter(s => s.score < 65).length} foot="vragen aandacht" />
        <KPI icon="check" iconBg="var(--ok-soft)" iconColor="var(--ok)" label="≥ 80 score" value={pages.filter(s => s.score >= 80).length} foot="op orde" />
      </div>

      <div className="grid col-5-7">
        <Card>
          <CardHead title="Gescande pagina's" icon="doc" sub={"gescand " + new Date(audit.at).toLocaleDateString("nl-NL", { day: "numeric", month: "short" })} right={<button className="btn btn-sm btn-ghost" onClick={() => db.refreshSeoAudit && db.refreshSeoAudit()}><Icon name="refresh" size={14} />Opnieuw scannen</button>} />
          <div style={{ maxHeight: 430, overflowY: "auto" }}>
            {pages.map((s, i) => (
              <button key={s.url} onClick={() => setSel(i)} className="lrow" style={{ width: "100%", border: "none", background: i === sel ? "var(--surface-2)" : "none", borderLeft: i === sel ? "3px solid var(--brand)" : "3px solid transparent", padding: "12px 16px", textAlign: "left", cursor: "pointer", gap: 12 }}>
                <ScoreRing score={s.score} size={42} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontWeight: 600, fontSize: 13, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{s.title || s.url}</div>
                  <div className="mono muted" style={{ fontSize: 11, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{s.url} · {s.clicks} clicks</div>
                </div>
              </button>
            ))}
          </div>
        </Card>

        <Card>
          <CardHead title={pg.url} icon="search2" sub={pg.title}
            right={<a className="btn btn-sm" href={pg.fullUrl} target="_blank" rel="noreferrer">Bekijk pagina<Icon name="external" size={14} /></a>} />
          <div className="card-pad">
            <div style={{ display: "flex", gap: 20, alignItems: "center", marginBottom: 18 }}>
              <ScoreRing score={pg.score} size={76} />
              <div>
                <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 2 }}>SEO Score: {pg.score}/100</div>
                <div className="muted" style={{ fontSize: 12.5 }}>{pg.words} woorden · {keys.filter(k => pg.checks[k]).length}/{keys.length} checks geslaagd · respons {pg.ms} ms</div>
              </div>
            </div>

            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 20 }}>
              {keys.map(k => (
                <div key={k} style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 12.5 }}>
                  <span style={{ width: 18, height: 18, borderRadius: 5, display: "grid", placeContent: "center", background: pg.checks[k] ? "var(--ok-soft)" : "var(--danger-soft)", color: pg.checks[k] ? "var(--ok)" : "var(--danger)", flex: "none" }}>
                    <Icon name={pg.checks[k] ? "check" : "x"} size={12} sw={2.6} />
                  </span>
                  <span style={{ color: pg.checks[k] ? "var(--text-2)" : "var(--text)" }}>{AUDIT_LABELS[k]}</span>
                </div>
              ))}
            </div>

            {(pg.advice || []).length > 0 && <React.Fragment>
              <div className="ai-tag" style={{ marginBottom: 12 }}><Icon name="sparkles" size={13} />Verbeterpunten · uit de live scan van deze pagina</div>
              <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                {pg.advice.map((a, i) => (
                  <div key={i} style={{ display: "flex", gap: 10, alignItems: "flex-start", background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 9, padding: "10px 12px" }}>
                    <span style={{ width: 20, height: 20, borderRadius: 6, background: "var(--accent-soft)", color: "var(--accent)", display: "grid", placeContent: "center", fontSize: 11, fontWeight: 700, flex: "none" }}>{i + 1}</span>
                    <span style={{ fontSize: 13, lineHeight: 1.5 }}>{a}</span>
                  </div>
                ))}
              </div>
            </React.Fragment>}
            {(pg.advice || []).length === 0 && <div className="muted" style={{ fontSize: 13 }}>Alle checks geslaagd — deze pagina staat er goed voor. 🎉</div>}
          </div>
        </Card>
      </div>
    </React.Fragment>
  );
}

/* ============================ RETOUREN ============================ */
function Retouren({ db, onNav }) {
  const [busy, setBusy] = React.useState(null);
  const [choice, setChoice] = React.useState({});
  const data = (db.bolReturns && db.bolReturns()) || {};
  const open = data.open || [];
  const handled = (data.handled || []).slice(0, 25);
  const period = db.period();
  const perLabel = (db.PERIODS.find(x => x.id === period) || {}).label || "";
  const impact = db.returnsImpact ? db.returnsImpact(period) : { cost: 0, count: 0, qty: 0 };
  const prodOf = (r) => db.products.find(p => (p.sku || "").toUpperCase() === (r.sku || "").toUpperCase());
  const nameOf = (r) => { const p = prodOf(r); return p ? p.name : (r.sku || "EAN " + r.ean); };
  const fmtD = (s) => s ? String(s).slice(0, 10) : "";
  const RESULT_LABEL = { RETURN_RECEIVED: ["Terugbetaald", "ok"], EXPIRED: ["Verlopen", "neutral"], FAILED_TO_COLLECT_BY_TRANSPORTER: ["Niet opgehaald", "neutral"], CUSTOMER_KEEPS_PRODUCT_PAID: ["Klant houdt (betaald)", "neutral"] };
  const HANDLE_OPTS = [
    { id: "RETURN_RECEIVED", label: "Goed ontvangen (terugbetalen)" },
    { id: "RETURN_DOES_NOT_MEET_CONDITIONS", label: "Voldoet niet aan voorwaarden" },
    { id: "CUSTOMER_KEEPS_PRODUCT_PAID", label: "Klant houdt product (betaald)" },
  ];
  async function verwerk(r) {
    const hr = choice[r.rmaId] || "RETURN_RECEIVED";
    const lbl = (HANDLE_OPTS.find(o => o.id === hr) || {}).label;
    if (!window.confirm("Retour van " + nameOf(r) + " (" + (r.qty || 1) + "×) verwerken als \"" + lbl + "\"?")) return;
    setBusy(r.rmaId);
    const res = await db.handleReturn(r.rmaId, hr, r.qty || 1, r.market);
    setBusy(null);
    if (!res.ok) window.alert("Verwerken mislukt: " + (res.status || res.error || "onbekende fout"));
  }
  const promos = (db.bolPromos && db.bolPromos()) || null;
  const promoList = (promos && promos.promotions) || [];
  const commKeys = promos && promos.commissions ? Object.keys(promos.commissions).filter(k => promos.commissions[k].reduction) : [];
  const nowIso = new Date().toISOString();
  return (
    <div className="view">
      <div className="page-head">
        <div className="ph-row">
          <div>
            <h1>Retouren</h1>
            <div className="ph-sub">Live van bol.com{data.at ? " · bijgewerkt " + new Date(data.at).toLocaleTimeString("nl-NL", { hour: "2-digit", minute: "2-digit" }) : ""} · terugbetaalde retouren worden verrekend in de winst.</div>
          </div>
          <button className="btn btn-sm btn-ghost" onClick={() => { db.refreshReturns(); db.refreshPromos(); }}><Icon name="refresh" size={14} />Nu ophalen</button>
        </div>
      </div>

      <div className="grid cols-4" style={{ marginBottom: "var(--space)" }}>
        <KPI icon={open.length ? "alert" : "check"} iconBg={open.length ? "var(--danger-soft)" : "var(--ok-soft)"} iconColor={open.length ? "var(--danger)" : "var(--ok)"} label="Open retouren" value={open.length} foot={open.length ? "actie nodig" : "niets te doen ✓"} />
        <KPI icon="truck" iconBg="var(--surface-3)" iconColor="var(--text-2)" label={"Terugbetaald · " + perLabel.toLowerCase()} value={impact.count} foot={impact.qty + " stuks"} />
        <KPI icon="euro" iconBg="var(--warn-soft)" iconColor="var(--warn)" label="Winst-impact" value={impact.cost > 0 ? "−" + fmtEur(Math.round(impact.cost)) : "—"} foot="verrekend in winst vóór belasting" />
        <KPI icon="truck" iconBg="var(--surface-3)" iconColor="var(--text-2)" label="Afgehandeld (totaal)" value={(data.handled || []).length} foot="alle retouren" />
      </div>

      <div style={{ marginBottom: "var(--space)" }}>
        <Card>
          <CardHead title={"Openstaande retouren (" + open.length + ")"} icon="alert" />
          <div className="card-pad" style={{ display: "flex", flexDirection: "column", gap: 12 }}>
            {!open.length && <div className="muted" style={{ fontSize: 13 }}>Geen openstaande retouren. 🎉</div>}
            {open.map(r => (
              <div key={r.rmaId} style={{ border: "1px solid var(--border)", borderRadius: 10, padding: "12px 14px" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
                  {prodOf(r) && <ProductThumb p={prodOf(r)} size={34} />}
                  <div style={{ flex: 1, minWidth: 180 }}>
                    <div style={{ fontWeight: 600, fontSize: 13.5 }}>{nameOf(r)} · {r.qty || 1}× {r.market ? <span className="pill neutral" style={{ fontSize: 10 }}>{r.market.toUpperCase()}</span> : null}</div>
                    <div className="muted" style={{ fontSize: 12 }}>Reden: {r.reason || "onbekend"} · aangemeld {fmtD(r.registered)} · order <span className="mono">{r.orderId}</span></div>
                    {r.comments ? <div className="muted" style={{ fontSize: 12, fontStyle: "italic", marginTop: 2 }}>“{r.comments}”</div> : null}
                  </div>
                  <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
                    <select value={choice[r.rmaId] || "RETURN_RECEIVED"} onChange={e => setChoice(Object.assign({}, choice, { [r.rmaId]: e.target.value }))}
                      style={{ fontSize: 12.5, padding: "7px 8px", border: "1px solid var(--border)", borderRadius: 8, background: "#fff", color: "var(--text)", fontFamily: "inherit" }}>
                      {HANDLE_OPTS.map(o => <option key={o.id} value={o.id}>{o.label}</option>)}
                    </select>
                    <button className="btn btn-brand btn-sm" disabled={busy === r.rmaId} onClick={() => verwerk(r)}>{busy === r.rmaId ? "Bezig…" : "Verwerken"}</button>
                  </div>
                </div>
              </div>
            ))}
          </div>
        </Card>
      </div>

      <Card>
        <CardHead title="Afgehandelde retouren" icon="truck" />
        <div style={{ overflowX: "auto" }}>
          <table className="tbl">
            <thead><tr><th>Afgehandeld</th><th>Product</th><th className="num">Aantal</th><th>Reden</th><th>Status</th><th>Order</th></tr></thead>
            <tbody>
              {handled.map(r => { const rl = RESULT_LABEL[r.handlingResult] || [r.handlingResult || "—", "neutral"]; return (
                <tr key={r.rmaId}>
                  <td className="tnum">{fmtD(r.processed || r.registered)}</td>
                  <td style={{ fontWeight: 600, fontSize: 13 }}>{nameOf(r)} {r.market ? <span className="pill neutral" style={{ fontSize: 9.5 }}>{r.market.toUpperCase()}</span> : null}</td>
                  <td className="num tnum">{r.qty || 1}</td>
                  <td className="muted" style={{ fontSize: 12.5 }}>{r.reason || "—"}</td>
                  <td><span className={"pill " + rl[1]}>{rl[0]}</span></td>
                  <td className="mono" style={{ fontSize: 11.5 }}>{r.orderId}</td>
                </tr>
              ); })}
            </tbody>
          </table>
        </div>
      </Card>
    </div>
  );
}

/* ============================ MELDINGEN ============================ */
function Meldingen({ db, onNav }) {
  const [filter, setFilter] = React.useState("alle");
  const types = [
    { id: "alle", label: "Alle" }, { id: "voorraad", label: "Voorraad" },
    { id: "verkoop", label: "Verkoop" }, { id: "retour", label: "Retouren" }, { id: "review", label: "Reviews" }, { id: "ranking", label: "Rankings" },
    { id: "seo", label: "SEO" },
  ];
  const open = db.openAlerts();
  const list = filter === "alle" ? open : open.filter(a => a.type === filter);
  const doneCount = db.dismissedCount();

  return (
    <div className="view">
      <div className="page-head">
        <div className="ph-row">
          <div>
            <h1>Meldingen</h1>
            <div className="ph-sub">Open signalen — voorraad, verkoop, reviews en SEO.</div>
          </div>
          {doneCount > 0 && <button className="btn btn-sm btn-ghost" onClick={() => db.restoreAlerts()}><Icon name="refresh" size={14} />{doneCount} afgevinkt terughalen</button>}
        </div>
      </div>

      <div style={{ display: "flex", gap: 8, marginBottom: 18, flexWrap: "wrap" }}>
        {types.map(t => {
          const n = t.id === "alle" ? open.length : open.filter(a => a.type === t.id).length;
          return <button key={t.id} className={"chip" + (filter === t.id ? " on" : "")} onClick={() => setFilter(t.id)}>{t.label}<span className="mono" style={{ opacity: .6 }}>{n}</span></button>;
        })}
      </div>

      <Card>
        <div className="card-pad" style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {list.length === 0 && <div className="muted" style={{ fontSize: 13, padding: "8px 2px" }}>Geen open meldingen in deze categorie. 🎉</div>}
          {list.map(a => <AttentionItem key={a.id} a={a} onNav={onNav} onDismiss={db.dismissAlert} />)}
        </div>
      </Card>
    </div>
  );
}

/* ============================ ADVERTENTIES ============================ */
function Advertenties({ db, onNav }) {
  const period = db.period();
  const perLabel = (db.PERIODS.find(x => x.id === period) || {}).label || "";
  const ads = (db.bolAds && db.bolAds()) || null;
  const roas = (c, sa) => c > 0 ? (sa / c) : null;
  const acos = (c, sa) => sa > 0 ? (c / sa * 100) : null;
  // "schone winst": winst op de toegerekende ad-omzet, ná advertentiekosten én winstbelasting
  const schoon = (p, a) => {
    if (!a) return null;
    const price = (db.bestPrice && db.bestPrice(p, /bol/i)) || ((p.prices && p.prices.web) || 0);
    const wp = db.winstPer ? db.winstPer(p, price, "Bol.com NL") : null;
    if (wp == null || !(price > 0)) return null;
    const voor = a.sales * (wp / price) - a.cost;
    return db.naBelasting ? db.naBelasting(voor) : voor;
  };
  const adStatus = (p, a) => {
    if (!a || !(a.cost > 0)) return null;
    const price = (db.bestPrice && db.bestPrice(p, /bol/i)) || ((p.prices && p.prices.web) || 0);
    const wp = db.winstPer ? db.winstPer(p, price, "Bol.com NL") : null;
    const r = a.sales > 0 ? a.sales / a.cost : 0;
    let be = null;
    if (wp != null && wp > 0 && price > 0) { const mf = wp / price; if (mf > 0) be = 1 / mf; }
    if (be) { if (r >= be * 1.25) return ["ok", "Winstgevend"]; if (r >= be) return ["warn", "Kan beter"]; return ["danger", "Verliesgevend"]; }
    if (r >= 5) return ["ok", "Winstgevend"]; if (r >= 2.5) return ["warn", "Kan beter"]; return ["danger", "Verliesgevend"];
  };
  const rows = db.products.map(p => ({ p, a: db.adsFor(p.sku, period) })).filter(x => x.a && (x.a.cost > 0 || x.a.impressions > 0)).sort((x, y) => y.a.cost - x.a.cost);
  const schoonTot = rows.reduce((s, r) => { const v = schoon(r.p, r.a); return v != null ? s + v : s; }, 0);
  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 });
  let nl = 0, be = 0; if (ads && ads.bySku) for (const sku in ads.bySku) { nl += ads.bySku[sku].nl || 0; be += ads.bySku[sku].be || 0; }
  const syncedAt = db.adsSyncedAt && db.adsSyncedAt();
  const g = (db.gadsData && db.gadsData()) || null;
  const gTot = (db.gadsTotal && db.gadsTotal(period)) || 0;
  const gRows = (db.gadsCampaigns && db.gadsCampaigns(period)) || [];
  const prevB = (db.adsAggAll && db.adsAggAll(period, 1)) || null;
  const prevG = (db.gadsCost && db.gadsCost(period, 1)) || 0;
  const totCostAll = tot.cost + gTot, prevCostAll = (prevB ? prevB.cost : 0) + prevG;
  const Delta = ({ now, before, invert }) => {
    if (before == null || !(before > 0)) return <span className="muted" style={{ fontSize: 11 }}>geen vergelijk</span>;
    const pct = Math.round((now - before) / before * 100);
    const good = invert ? pct <= 0 : pct >= 0;
    return <span style={{ fontSize: 12, fontWeight: 700, color: good ? "var(--ok)" : "var(--danger)" }}>{pct >= 0 ? "↑ +" + pct : "↓ " + pct}% <span className="muted" style={{ fontWeight: 400 }}>vs vorige periode</span></span>;
  };
  // STOCERS AdPilot — regelgebaseerde aanbevelingen (ROAS, marge, voorraad)
  const advies = [];
  rows.forEach(({ p, a }) => {
    const st = adStatus(p, a);
    const r = a.cost > 0 && a.sales > 0 ? a.sales / a.cost : null;
    if (st && st[0] === "danger" && a.cost >= 5) advies.push({ sev: "danger", txt: p.name + ": " + fmtEur(a.cost) + " advertentiekosten met te weinig ad-omzet (" + perLabel.toLowerCase() + "). Overweeg het bod te verlagen of de advertentie te pauzeren." });
    else if ((p.stock || 0) > 0 && (p.stock || 0) < 15 && a.cost > 0) advies.push({ sev: "warn", txt: p.name + ": nog maar " + p.stock + " stuks voorraad terwijl de advertentie doorloopt. Overweeg het bod te verlagen tot de voorraad is aangevuld." });
    else if (st && st[0] === "ok" && r != null && r >= 5 && (p.stock || 0) > 50) advies.push({ sev: "ok", txt: p.name + ": ROAS " + r.toFixed(1) + "× en " + p.stock + " stuks voorraad. Ruimte om het budget of bod te verhogen." });
  });
  gRows.forEach(c => {
    const r = c.cost > 0 && c.value > 0 ? c.value / c.cost : null;
    if (c.cost >= 10 && (c.conversions || 0) === 0) advies.push({ sev: "danger", txt: "Google · " + c.name + ": " + fmtEur(c.cost) + " uitgegeven zonder conversies (" + perLabel.toLowerCase() + "). Overweeg pauzeren of de zoektermen aan te scherpen." });
    else if (r != null && r < 2 && c.cost >= 10) advies.push({ sev: "warn", txt: "Google · " + c.name + ": ROAS " + r.toFixed(1) + "× — rond of onder break-even. Verlaag biedingen of controleer de zoektermen." });
    else if (r != null && r >= 5 && c.cost >= 5) advies.push({ sev: "ok", txt: "Google · " + c.name + ": ROAS " + r.toFixed(1) + "×. Sterk — overweeg het budget met ~20% te verhogen." });
  });
  const sevRank = { danger: 0, warn: 1, ok: 2 };
  advies.sort((x, y) => sevRank[x.sev] - sevRank[y.sev]);
  // bron-switch: bol.com of Google Ads
  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 adviesSrc = advies.filter(a => src === "google" ? a.txt.indexOf("Google · ") === 0 : a.txt.indexOf("Google · ") !== 0);
  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">bol.com Sponsored Products (NL + BE) én Google Ads (doosjehout.nl){syncedAt ? " · bijgewerkt " + new Date(syncedAt).toLocaleDateString("nl-NL", { day: "numeric", month: "short" }) : ""}.</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>

      <AdPilotChat db={db} advies={advies} g={g} rows={rows} tot={tot} gRows={gRows} gTot={gTot} 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" ? (
      <div className="grid cols-4" style={{ marginBottom: "var(--space)" }}>
        <KPI icon="euro" iconBg="var(--accent-soft)" iconColor="var(--accent)" label={"Adkosten bol · " + perLabel.toLowerCase()} value={fmtEur(Math.round(tot.cost))} foot={<Delta now={tot.cost} before={prevB ? prevB.cost : null} invert={true} />} />
        <KPI icon="chart" iconBg="var(--ok-soft)" iconColor="var(--ok)" label="Ad-omzet (bol)" value={fmtEur(Math.round(tot.sales))} foot={<Delta now={tot.sales} before={prevB ? prevB.sales : null} />} />
        <KPI icon="trending" iconBg="var(--brand-soft)" iconColor="var(--brand)" label="ROAS" value={roas(tot.cost, tot.sales) != null ? roas(tot.cost, tot.sales).toFixed(2) + "×" : "—"} foot={<Delta now={roas(tot.cost, tot.sales) || 0} before={prevB ? roas(prevB.cost, prevB.sales) : null} />} />
        <KPI icon="star" iconBg="var(--warn-soft)" iconColor="var(--warn)" label="ACOS" value={acos(tot.cost, tot.sales) != null ? Math.round(acos(tot.cost, tot.sales)) + "%" : "—"} foot={<Delta now={acos(tot.cost, tot.sales) || 0} before={prevB ? acos(prevB.cost, prevB.sales) : null} invert={true} />} />
      </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={<Delta now={gTot} before={prevG} invert={true} />} />
        <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>
      )}

      <Card style={{ marginBottom: "var(--space)" }}>
        <CardHead title="STOCERS AdPilot" icon="info" right={<span className="muted" style={{ fontSize: 12 }}>automatische aanbevelingen · {perLabel.toLowerCase()}</span>} />
        <div className="card-pad" style={{ paddingTop: 4 }}>
          {!adviesSrc.length && <div className="muted" style={{ fontSize: 13, padding: "6px 0" }}>Geen acties nodig — je advertenties draaien gezond.</div>}
          {adviesSrc.slice(0, 8).map((adv, i) => (
            <div key={i} style={{ display: "flex", alignItems: "flex-start", gap: 9, padding: "8px 0", borderTop: i ? "1px solid var(--border)" : "none", fontSize: 13, lineHeight: 1.45 }}>
              <span style={{ width: 8, height: 8, borderRadius: 99, marginTop: 5, flex: "none", background: adv.sev === "ok" ? "var(--ok)" : (adv.sev === "warn" ? "var(--warn)" : "var(--danger)") }}></span>
              <span>{adv.txt}</span>
            </div>
          ))}
        </div>
      </Card>

      {src === "bol" && <React.Fragment>
      <Card style={{ marginBottom: "var(--space)" }}>
        <CardHead title="bol.com Sponsored Products · per product" icon="tag" right={<button className="btn btn-sm btn-ghost" onClick={() => db.refreshAds && db.refreshAds()}><Icon name="refresh" size={14} />Nu ophalen</button>} />
        <div style={{ overflowX: "auto" }}>
          <table className="tbl">
            <thead><tr><th>Product</th><th>Markt</th><th className="num">Kosten</th><th className="num">Ad-omzet</th><th className="num" title="winst op de ad-omzet, na advertentiekosten én winstbelasting">Schone winst</th><th className="num">ROAS</th><th className="num">ACOS</th><th className="num">Clicks</th><th className="num">CPC</th><th className="num">CTR</th><th className="num">Impressies</th><th>Status</th></tr></thead>
            <tbody>
              {!rows.length && <tr><td colSpan={12} className="muted" style={{ padding: "14px 2px" }}>Geen advertentiedata in deze periode.</td></tr>}
              {rows.map(({ p, a }) => { const r = roas(a.cost, a.sales), ac = acos(a.cost, a.sales); return (
                <tr key={p.id} className="row-click" onClick={() => onNav("producten", p.id)}>
                  <td><div className="prod"><ProductThumb p={p} size={32} /><span style={{ fontWeight: 600, fontSize: 13 }}>{p.name}</span></div></td>
                  <td>{(() => { const rec = ads && ads.bySku ? ads.bySku[(p.sku || "").toUpperCase()] : null; if (!rec) return <span className="muted">—</span>; const mk = []; if (rec.nl > 0) mk.push(<span key="nl" className="pill" title={"bol NL · " + fmtEur(rec.nl) + " (30 dgn)"}>bol NL</span>); if (rec.be > 0) mk.push(<span key="be" className="pill" title={"bol BE · " + fmtEur(rec.be) + " (30 dgn)"}>bol BE</span>); return mk.length ? <span style={{ display: "inline-flex", gap: 4, flexWrap: "wrap" }}>{mk}</span> : <span className="muted">—</span>; })()}</td>
                  <td className="num tnum">{fmtEur(a.cost)}</td>
                  <td className="num tnum">{a.sales > 0 ? fmtEur(a.sales) : "—"}</td>
                  <td className="num tnum" style={(() => { const v = schoon(p, a); return { fontWeight: 700, color: v == null ? undefined : (v >= 0 ? "var(--ok)" : "var(--danger)") }; })()}>{(() => { const v = schoon(p, a); return v == null ? <span className="muted" title="vul de inkoopprijs in voor schone winst">—</span> : (v >= 0 ? "+" : "−") + fmtEur(Math.abs(v)).replace("€", "€"); })()}</td>
                  <td className="num tnum" style={{ color: r != null ? (r >= 3 ? "var(--ok)" : (r < 1.5 ? "var(--danger)" : undefined)) : undefined, fontWeight: 600 }}>{r != null ? r.toFixed(2) + "×" : "—"}</td>
                  <td className="num tnum">{ac != null ? Math.round(ac) + "%" : "—"}</td>
                  <td className="num tnum muted">{a.clicks}</td>
                  <td className="num tnum muted">{a.clicks > 0 ? fmtEur(a.cost / a.clicks) : "—"}</td>
                  <td className="num tnum muted">{a.impressions > 0 ? (a.clicks / a.impressions * 100).toFixed(1) + "%" : "—"}</td>
                  <td className="num tnum muted">{a.impressions}</td>
                  <td>{(() => { const st = adStatus(p, a); return st ? <span className={"pill " + st[0]}>{st[1]}</span> : <span className="muted">—</span>; })()}</td>
                </tr>
              ); })}
              {rows.length > 0 && <tr style={{ fontWeight: 700, borderTop: "2px solid var(--border)" }}><td>Totaal</td><td></td><td className="num tnum">{fmtEur(Math.round(tot.cost))}</td><td className="num tnum">{fmtEur(Math.round(tot.sales))}</td><td className="num tnum" style={{ color: schoonTot >= 0 ? "var(--ok)" : "var(--danger)" }}>{(schoonTot >= 0 ? "+" : "−") + fmtEur(Math.abs(Math.round(schoonTot)))}</td><td className="num tnum">{roas(tot.cost, tot.sales) != null ? roas(tot.cost, tot.sales).toFixed(2) + "×" : "—"}</td><td className="num tnum">{acos(tot.cost, tot.sales) != null ? Math.round(acos(tot.cost, tot.sales)) + "%" : "—"}</td><td className="num tnum">{tot.clicks}</td><td></td><td></td><td className="num tnum">{tot.impressions}</td><td></td></tr>}
            </tbody>
          </table>
        </div>
      </Card>
      </React.Fragment>}

      {src === "google" && <React.Fragment>
      <Card>
        <CardHead title="Google Ads · doosjehout.nl" icon="search2" right={g ? <span className="muted" style={{ fontSize: 12 }}>kosten · {perLabel.toLowerCase()}: <b className="tnum" style={{ color: "var(--text)" }}>{fmtEur(gTot)}</b></span> : null} />
        {!g ? (
          <div className="card-pad"><Placeholder label="Nog geen data" note="De Google Ads-koppeling staat klaar — data verschijnt na de eerste sync." height={90} /></div>
        ) : (
          <div>
            {!gRows.length && <div className="card-pad muted" style={{ fontSize: 13 }}>Geen Google Ads-kosten in deze periode.</div>}
            {gRows.map((c, ci) => { const r = c.cost > 0 && c.value > 0 ? c.value / c.cost : null; const st = c.cost > 0 && r != null ? (r >= 4 ? ["ok", "Winstgevend"] : (r >= 2 ? ["warn", "Kan beter"] : ["danger", "Verliesgevend"])) : null; return (
              <div key={c.name} className="card-pad" style={{ paddingTop: 12, paddingBottom: 14, borderTop: ci ? "1px solid var(--border)" : "none" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap", marginBottom: 10 }}>
                  <span style={{ fontWeight: 700, fontSize: 14 }}>{c.name}</span>
                  {st && <span className={"pill " + st[0]}>{st[1]}</span>}
                </div>
                <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(92px, 1fr))", gap: 10 }}>
                  {[["Kosten", fmtEur(c.cost)], ["Clicks", String(c.clicks)], ["Conversies", String(c.conversions)], ["Conv.-waarde", c.value > 0 ? fmtEur(c.value) : "—"], ["ROAS", r != null ? r.toFixed(2) + "×" : "—"]].map(([l, v2]) => (
                    <div key={l} style={{ background: "var(--bg)", border: "1px solid var(--border)", borderRadius: 10, padding: "8px 10px" }}>
                      <div className="muted" style={{ fontSize: 10.5, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em" }}>{l}</div>
                      <div className="tnum" style={{ fontSize: 16, fontWeight: 700, marginTop: 2 }}>{v2}</div>
                    </div>
                  ))}
                </div>
              </div>
            ); })}
            {(g.adGroups || []).length > 1 && <div className="card-pad" style={{ paddingTop: 0 }}>
              <div className="muted" style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em", margin: "8px 0 2px" }}>Advertentiegroepen · laatste 30 dgn</div>
              <table className="tbl">
                <thead><tr><th>Adgroep</th><th>Campagne</th><th className="num">Kosten</th><th className="num">Clicks</th></tr></thead>
                <tbody>
                  {(g.adGroups || []).slice(0, 8).map((a, i) => (
                    <tr key={i}><td style={{ fontWeight: 600, fontSize: 13 }}>{a.name}</td><td className="muted" style={{ fontSize: 13 }}>{a.campaign}</td><td className="num tnum">{fmtEur(a.cost)}</td><td className="num tnum muted">{a.clicks}</td></tr>
                  ))}
                </tbody>
              </table>
            </div>}
            {(g.products || []).length > 0 && <div className="card-pad" style={{ paddingTop: 0, paddingBottom: 14 }}>
              <div className="muted" style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em", margin: "8px 0 2px" }}>Producten in de campagne · laatste 30 dgn</div>
              <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">Opbrengst</th></tr></thead>
                  <tbody>
                    {(g.products || []).slice(0, 10).map((p2, i) => (
                      <tr key={i}><td style={{ fontWeight: 600, fontSize: 13 }}>{p2.title}</td><td className="num tnum">{fmtEur(p2.cost)}</td><td className="num tnum muted">{p2.clicks}</td><td className="num tnum">{p2.value > 0 ? fmtEur(p2.value) : "—"}</td></tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>}
          </div>
        )}
      </Card>

      <ZoektermenCard g={g} db={db} />
      <ActiesCard db={db} g={g} />
      </React.Fragment>}
    </div>
  );
}

/* ---- AdPilot Chat — AI-assistent op je eigen live data (ads, rankings, SEO, retouren, voorraad) ---- */
function AdPilotChat({ db, advies, g, rows, tot, gRows, gTot, perLabel }) {
  const [msgs, setMsgs] = React.useState([]);
  const [inp, setInp] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  React.useEffect(() => {
    const h = (e) => { if (e.detail) ask(String(e.detail)); };
    window.addEventListener("adpilot-ask", h);
    return () => window.removeEventListener("adpilot-ask", h);
  });
  const endRef = React.useRef(null);
  const gsc = (db.gscData && db.gscData()) || null;
  const audit = (db.seoAudit && db.seoAudit()) || null;
  const terms = (g && g.searchTerms) || [];
  const eur = (v) => fmtEur(Math.round(v));
  function answer(q) {
    const t = q.toLowerCase();
    const out = [];
    const wants = (re) => re.test(t);
    let matched = false;
    if (wants(/verlies|kwijt|slecht|stop|verliesgevend/)) {
      matched = true;
      const bad = advies.filter(a => a.sev === "danger");
      out.push(bad.length ? "Hier lekt geld weg:\n" + bad.map(a => "• " + a.txt).join("\n") : "Goed nieuws: ik zie momenteel geen duidelijke verliezers in je advertenties.");
      const negTerms = terms.filter(x => x.cost >= 5 && !x.conversions).slice(0, 3);
      if (negTerms.length) out.push("Zoektermen om uit te sluiten: " + negTerms.map(x => "“" + x.term + "” (" + eur(x.cost) + " zonder conversie)").join(", ") + ".");
    }
    if (wants(/opschalen|verhogen|kans|groei|meer budget/)) {
      matched = true;
      const good = advies.filter(a => a.sev === "ok");
      out.push(good.length ? "Dit kan omhoog:\n" + good.map(a => "• " + a.txt).join("\n") : "Geen duidelijke opschaal-kandidaten in deze periode — je ROAS-toppers hebben weinig extra voorraad of volume.");
    }
    if (wants(/ranking|positie|vindbaar/)) {
      matched = true;
      if (gsc && gsc.queries) {
        const prev = {}; (gsc.prevQueries || []).forEach(x => { prev[x.query] = x; });
        const movers = gsc.queries.map(x => ({ kw: x.query, cur: x.position, d: prev[x.kw = x.query] ? +(prev[x.query].position - x.position).toFixed(1) : null, imp: x.impressions })).filter(x => x.d != null && Math.abs(x.d) >= 1 && x.imp >= 100).sort((a, b) => Math.abs(b.d) - Math.abs(a.d)).slice(0, 4);
        const top = gsc.queries.filter(x => x.clicks > 0).slice(0, 3);
        out.push("Gem. positie: " + gsc.total.position.toFixed(1) + (gsc.prevTotal ? " (was " + gsc.prevTotal.position.toFixed(1) + ")" : "") + ". Topzoekwoorden: " + top.map(x => "“" + x.query + "” #" + x.position.toFixed(1)).join(", ") + ".");
        if (movers.length) out.push("Opvallende bewegingen:\n" + movers.map(x => "• “" + x.kw + "” " + (x.d > 0 ? "↑ gestegen" : "↓ gedaald") + " naar #" + x.cur.toFixed(1)).join("\n"));
      } else out.push("Ranking-data komt uit Search Console — die is nog niet binnen.");
    }
    if (wants(/zoekterm|zoekwoord(?!.*positie)|gezocht/) && terms.length) {
      matched = true;
      out.push("Duurste zoektermen (30 dgn):\n" + terms.slice(0, 5).map(x => { const r = x.cost > 0 && x.value > 0 ? (x.value / x.cost).toFixed(1) + "×" : "—"; return "• “" + x.term + "” · " + eur(x.cost) + " · ROAS " + r; }).join("\n"));
    }
    if (wants(/seo|audit|pagina.?score|meta|titel/)) {
      matched = true;
      if (audit && (audit.pages || []).length) {
        const ps = audit.pages.slice().sort((a, b) => a.score - b.score);
        const worst = ps[0];
        const avg = Math.round(audit.pages.reduce((s, x) => s + x.score, 0) / audit.pages.length);
        out.push("Gem. SEO-score: " + avg + "/100 over " + audit.pages.length + " pagina's. Zwakste pagina: " + worst.url + " (" + worst.score + "/100)." + ((worst.advice || []).length ? " Belangrijkste verbeterpunten:\n" + worst.advice.slice(0, 2).map(a => "• " + a).join("\n") : ""));
      } else out.push("De SEO-scan is nog niet gedraaid — open de SEO-pagina en klik “Opnieuw scannen”.");
    }
    if (wants(/budget/)) {
      matched = true;
      const camps = Object.entries((g && g.campaigns) || {}).filter(([n, c]) => c.id);
      if (camps.length) out.push("Google-campagnes: " + camps.map(([n, c]) => n + " (" + eur(c.cost) + "/30d" + (c.status === "PAUSED" ? ", gepauzeerd" : "") + ")").join(", ") + ". Budget direct aanpassen kan hieronder bij “Acties vanuit het dashboard”.");
      else out.push("Nog geen campagne-info binnen — ververs de Google Ads-data.");
    }
    if (wants(/acos|roas|rendement/)) {
      matched = true;
      const r = tot.cost > 0 && tot.sales > 0 ? (tot.sales / tot.cost).toFixed(2) : null;
      const gv = gRows.reduce((s, c) => s + (c.value || 0), 0);
      out.push("bol (" + perLabel.toLowerCase() + "): " + eur(tot.cost) + " kosten, " + eur(tot.sales) + " ad-omzet" + (r ? ", ROAS " + r + "×" : "") + ". Google: " + eur(gTot) + " kosten" + (gv > 0 ? ", " + eur(gv) + " conversiewaarde (" + (gTot > 0 ? (gv / gTot).toFixed(2) : "—") + "×)" : "") + ".");
    }
    if (wants(/voorraad/)) {
      matched = true;
      const low = rows.filter(x => (x.p.stock || 0) > 0 && (x.p.stock || 0) < 15);
      out.push(low.length ? "Adverterende producten met weinig voorraad: " + low.map(x => x.p.name + " (" + x.p.stock + " stuks)").join(", ") + " — overweeg het bod te verlagen tot de voorraad is aangevuld." : "Geen adverterende producten met kritiek lage voorraad. 👍");
    }
    if (wants(/rapport|overzicht|samenvatting|hoe (gaat|staat|draait)/) || !matched) {
      const r = tot.cost > 0 && tot.sales > 0 ? (tot.sales / tot.cost).toFixed(1) : null;
      const best = rows.filter(x => x.a.cost > 0 && x.a.sales > 0).sort((a, b) => (b.a.sales / b.a.cost) - (a.a.sales / a.a.cost))[0];
      const head = "📊 " + perLabel + ": bol " + eur(tot.cost) + " adkosten → " + eur(tot.sales) + " ad-omzet" + (r ? " (ROAS " + r + "×)" : "") + " · Google " + eur(gTot) + " kosten.";
      const bits = [head];
      if (best) bits.push("Beste presteerder: " + best.p.name + " met ROAS " + (best.a.sales / best.a.cost).toFixed(1) + "×.");
      const urgent = advies.find(a => a.sev === "danger");
      if (urgent) bits.push("⚠️ Belangrijkste actie: " + urgent.txt);
      if (gsc && gsc.total) bits.push("Vindbaarheid: " + gsc.total.clicks.toLocaleString("nl-NL") + " Google-clicks (30 dgn), gem. positie " + gsc.total.position.toFixed(1) + ".");
      out.push(bits.join("\n"));
    }
    return out.join("\n\n");
  }
  // compacte snapshot van álle live data — als kennis voor het AI-brein
  function buildContext() {
    const L = [];
    const E = (v) => "€" + (+v).toFixed(2);
    L.push("Datum: " + new Date().toLocaleDateString("nl-NL") + " · gekozen periode: " + perLabel);
    L.push("\n== bol Sponsored Products (" + perLabel + ") ==");
    L.push("Totaal: kosten " + E(tot.cost) + ", ad-omzet " + E(tot.sales) + ", clicks " + tot.clicks + ", impressies " + tot.impressions);
    rows.slice(0, 12).forEach(({ p, a }) => L.push("- " + p.name + " [" + p.sku + "]: kosten " + E(a.cost) + ", ad-omzet " + E(a.sales) + ", clicks " + a.clicks + ", voorraad " + (p.stock || 0)));
    L.push("\n== Google Ads (doosjehout.nl) ==");
    L.push("Kosten " + perLabel.toLowerCase() + ": " + E(gTot));
    Object.entries((g && g.campaigns) || {}).forEach(([nm, c]) => L.push("- Campagne " + nm + ": " + E(c.cost) + " (30d), " + c.clicks + " clicks, conversiewaarde " + E(c.value) + (c.status ? ", status " + c.status : "")));
    const terms2 = (g && g.searchTerms) || [];
    if (terms2.length) { L.push("Top zoektermen (30d):"); terms2.slice(0, 10).forEach(x => L.push("- \"" + x.term + "\": " + E(x.cost) + ", " + x.clicks + " clicks, " + x.conversions + " conv, waarde " + E(x.value))); }
    const gsc2 = (db.gscData && db.gscData()) || null;
    if (gsc2 && gsc2.total) {
      L.push("\n== Google-vindbaarheid (Search Console, 30d) ==");
      L.push("Clicks " + gsc2.total.clicks + " (vorige periode " + (gsc2.prevTotal ? gsc2.prevTotal.clicks : "?") + "), vertoningen " + gsc2.total.impressions + ", gem. positie " + gsc2.total.position.toFixed(1));
      const prevQ = {}; (gsc2.prevQueries || []).forEach(x => { prevQ[x.query] = x; });
      (gsc2.queries || []).slice(0, 12).forEach(x => L.push("- \"" + x.query + "\": positie " + x.position.toFixed(1) + (prevQ[x.query] ? " (was " + prevQ[x.query].position.toFixed(1) + ")" : "") + ", " + x.clicks + " clicks"));
    }
    const audit2 = (db.seoAudit && db.seoAudit()) || null;
    if (audit2 && (audit2.pages || []).length) {
      L.push("\n== SEO-audit (live scan doosjehout.nl) ==");
      audit2.pages.forEach(pg => L.push("- " + pg.url + ": score " + pg.score + "/100" + ((pg.advice || []).length ? " · verbeterpunten: " + pg.advice.slice(0, 2).join(" / ") : "")));
    }
    try {
      const revs = db.products.map(p2 => ({ p2, r: db.reviewFor && db.reviewFor(p2.sku) })).filter(x => x.r && x.r.rating != null);
      if (revs.length) L.push("\n== Reviews (bol) ==\n" + revs.map(x => "- " + x.p2.name + ": " + (+x.r.rating).toFixed(1) + "★ (" + (x.r.count || 0) + " reviews)").join("\n"));
      const pr = db.bolPromos && db.bolPromos();
      const ck = pr && pr.commissions ? Object.keys(pr.commissions).filter(k => pr.commissions[k].reduction) : [];
      if ((pr && (pr.promotions || []).length) || ck.length) L.push("\n== bol-promoties ==" + ((pr.promotions || []).length ? "\nActieve promoties: " + pr.promotions.length : "") + (ck.length ? "\nCommissiekorting actief voor: " + ck.join(", ") : ""));
      L.push("\n== Dagdoel ==\nTeamdoel: €200 winst na belasting per dag (voortgangsbalk op de Winst-pagina).");
      const ret = (db.bolReturns && db.bolReturns()) || {};
      if ((ret.open || []).length) L.push("\n== Open retouren ==\n" + ret.open.map(r => "- " + (r.sku || r.ean) + " " + (r.qty || 1) + "×, reden: " + (r.reason || "?")).join("\n"));
      const ords = db.ordersIn && db.ordersIn("today");
      let omzetToday = 0; db.products.forEach(p => { const d = db.periodOf(p, "today"); if (d) omzetToday += d.rev || 0; });
      L.push("\n== Verkoop vandaag ==\nOmzet " + E(omzetToday) + (ords ? ", " + ords.o + " bestellingen" : ""));
    } catch (e) {}
    return L.join("\n");
  }
  const ask = async (q) => {
    if (!q.trim() || busy) return;
    const history = msgs.map(m => ({ role: m.who === "me" ? "user" : "assistant", content: m.txt }));
    setMsgs(m => [...m, { who: "me", txt: q }]);
    setInp("");
    setBusy(true);
    const scroll = () => setTimeout(() => { try { if (endRef.current && endRef.current.parentNode) endRef.current.parentNode.scrollTop = endRef.current.parentNode.scrollHeight; } catch (e) {} }, 60);
    scroll();
    let txt = null;
    if (db.adpilotAsk) {
      const res = await db.adpilotAsk(q, history, buildContext());
      if (res.ok) txt = res.answer;
    }
    if (txt == null) txt = answer(q); // terugval: regelgebaseerd op de live cijfers
    setBusy(false);
    setMsgs(m => [...m, { who: "ai", txt: txt }]);
    scroll();
  };
  const chips = ["Geef me een dagrapport", "Waar verlies ik geld?", "Wat kan ik opschalen?", "Hoe staan mijn rankings?", "Wat kan beter aan mijn SEO?"];
  return (
    <div style={{ background: "linear-gradient(135deg, var(--brand-soft), var(--accent-soft))", border: "1px solid var(--border)", borderRadius: 14, padding: "14px 16px", marginBottom: "var(--space)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: msgs.length ? 12 : 10 }}>
        <span className="adp-bot" style={{ width: 34, height: 34, borderRadius: 99, background: "var(--brand)", color: "#fff", display: "grid", placeContent: "center", flex: "none" }}><Icon name="sparkles" size={17} /></span>
        <div style={{ minWidth: 0 }}>
          <div style={{ fontWeight: 700, fontSize: 14 }}>AdPilot <span className="muted" style={{ fontWeight: 400 }}>· Hé! Waar kan ik je mee helpen?</span></div>
          <div className="muted" style={{ fontSize: 12 }}>Ik kijk live mee in je advertenties (bol + Google), zoektermen, rankings, SEO en voorraad.</div>
        </div>
      </div>
      {(msgs.length > 0 || busy) && (
        <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 12, maxHeight: 320, overflowY: "auto" }}>
          {msgs.map((m, i) => (
            <div key={i} style={{ alignSelf: m.who === "me" ? "flex-end" : "flex-start", maxWidth: "88%", background: m.who === "me" ? "var(--brand)" : "#fff", color: m.who === "me" ? "#fff" : "var(--text)", border: m.who === "me" ? "none" : "1px solid var(--border)", borderRadius: 12, padding: "9px 13px", fontSize: 13, whiteSpace: "pre-line", lineHeight: 1.5 }}>{m.txt}</div>
          ))}
          {busy && <div style={{ alignSelf: "flex-start", background: "#fff", border: "1px solid var(--border)", borderRadius: 12, padding: "9px 13px", fontSize: 13, color: "var(--text-3)" }}>AdPilot denkt na…</div>}
          <div ref={endRef}></div>
        </div>
      )}
      <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 10 }}>
        {chips.map(c => <button key={c} className="btn btn-sm btn-ghost" style={{ background: "rgba(255,255,255,.7)" }} onClick={() => ask(c)}>{c}</button>)}
      </div>
      <div style={{ display: "flex", gap: 8 }}>
        <input value={inp} onChange={e => setInp(e.target.value)} onKeyDown={e => { if (e.key === "Enter") ask(inp); }} placeholder={busy ? "AdPilot denkt na…" : "Vraag iets over je advertenties, rankings of SEO…"} disabled={busy} style={{ flex: 1, border: "1px solid var(--border)", borderRadius: 10, padding: "10px 13px", fontSize: 13, background: "#fff" }} />
        <button className="btn btn-sm" disabled={busy} onClick={() => ask(inp)}>{busy ? "…" : "Vraag"}</button>
      </div>
    </div>
  );
}

/* ---- Zoektermen-analyse — live uit Google Ads (search_term_view) ---- */
function ZoektermenCard({ g, db }) {
  const terms = (g && g.searchTerms) || [];
  const rec = (t) => {
    const r = t.cost > 0 && t.value > 0 ? t.value / t.cost : null;
    if (t.cost >= 5 && (t.conversions || 0) === 0) return ["danger", "Uitsluiten (negatief)"];
    if (r != null && r >= 4) return ["ok", "Opschalen"];
    if (r != null && r < 2) return ["warn", "Bod verlagen"];
    return ["neutral", "Monitoren"];
  };
  return (
    <Card style={{ marginTop: "var(--space)" }}>
      <CardHead title="Zoektermen-analyse · Google Ads" icon="search2" sub="waar mensen écht op zochten · laatste 30 dagen" right={<span className="pill ok"><span className="pdot" />Live</span>} />
      {!terms.length ? (
        <div className="card-pad muted" style={{ fontSize: 13 }}>Nog geen zoektermen binnen — klik op “Nu ophalen” bovenaan of wacht op de volgende sync. (Performance Max-campagnes geven geen zoektermen prijs; zoek- en Shopping-campagnes wel.)</div>
      ) : (
        <div style={{ overflowX: "auto" }}>
          <table className="tbl">
            <thead><tr><th>Zoekterm</th><th>Campagne</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>Aanbeveling</th></tr></thead>
            <tbody>
              {terms.slice(0, 15).map(t => { const r = t.cost > 0 && t.value > 0 ? t.value / t.cost : null; const rc = rec(t); return (
                <tr key={t.term}>
                  <td style={{ fontWeight: 600, fontSize: 13 }}>“{t.term}”</td>
                  <td className="muted" style={{ fontSize: 12 }}>{t.campaign}</td>
                  <td className="num tnum">{fmtEur(t.cost)}</td>
                  <td className="num tnum muted">{t.clicks}</td>
                  <td className="num tnum muted">{t.conversions}</td>
                  <td className="num tnum">{t.value > 0 ? fmtEur(t.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><span className={"pill " + rc[0]}>{rc[1]}</span></td>
                </tr>
              ); })}
            </tbody>
          </table>
        </div>
      )}
    </Card>
  );
}

/* ---- Acties vanuit het dashboard — écht pauzeren/activeren/budget wijzigen (Google Ads) ---- */
function ActiesCard({ db, g }) {
  const camps = Object.entries((g && g.campaigns) || {}).filter(([n, c]) => c.id).map(([name, c]) => Object.assign({ name }, c));
  const [busy, setBusy] = React.useState(null);
  const [msg, setMsg] = React.useState({});
  async function doAct(c, 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 {
      const lbl = action === "pause" ? "pauzeren" : "weer activeren";
      if (!window.confirm("Campagne “" + c.name + "” " + lbl + "? Dit wordt direct doorgevoerd in Google Ads.")) return;
    }
    setBusy(c.id + action);
    const res = await db.adsAction(action, payload);
    setBusy(null);
    if (res.ok) setMsg(o => Object.assign({}, o, { [c.id]: action === "budget" ? "✓ Budget aangepast" : (action === "pause" ? "✓ Gepauzeerd" : "✓ Geactiveerd") }));
    else window.alert("Actie mislukt: " + (res.error || res.status || "onbekende fout"));
  }
  return (
    <Card style={{ marginTop: "var(--space)" }}>
      <CardHead title="Acties vanuit het dashboard" icon="check" sub="wijzigingen gaan direct naar Google Ads" right={<span className="pill ok"><span className="pdot" />Live</span>} />
      <div className="card-pad" style={{ paddingTop: 4 }}>
        {!camps.length && <div className="muted" style={{ fontSize: 13, padding: "6px 0" }}>Nog geen campagnes binnen — ververs de Google Ads-data (de campagne-info komt mee bij de volgende sync).</div>}
        {camps.map((c, i) => (
          <div key={c.id} style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap", padding: "10px 0", borderTop: i ? "1px solid var(--border)" : "none" }}>
            <span style={{ flex: "1 1 200px", minWidth: 0 }}>
              <span style={{ fontWeight: 600, fontSize: 13 }}>{c.name}</span>
              <span className="muted" style={{ fontSize: 12 }}> · Google · {fmtEur(c.cost)} (30 dgn)</span>
              {c.status === "PAUSED" && <span className="pill neutral" style={{ marginLeft: 8 }}>Gepauzeerd</span>}
              {c.status === "ENABLED" && <span className="pill ok" style={{ marginLeft: 8 }}>Actief</span>}
            </span>
            {msg[c.id] ? <span style={{ fontSize: 12.5, color: "var(--ok)", fontWeight: 600 }}>{msg[c.id]}</span> : (
              <span style={{ display: "inline-flex", gap: 6, flexWrap: "wrap" }}>
                {c.status === "ENABLED" && <button className="btn btn-sm btn-ghost" disabled={busy === c.id + "pause"} onClick={() => doAct(c, "pause")}>{busy === c.id + "pause" ? "Bezig…" : "Pauzeer"}</button>}
                {c.status === "PAUSED" && <button className="btn btn-sm btn-ghost" disabled={busy === c.id + "enable"} onClick={() => doAct(c, "enable")}>{busy === c.id + "enable" ? "Bezig…" : "Activeer"}</button>}
                <button className="btn btn-sm btn-ghost" disabled={busy === c.id + "budget"} onClick={() => doAct(c, "budget")}>{busy === c.id + "budget" ? "Bezig…" : "Budget…"}</button>
              </span>
            )}
          </div>
        ))}
        <div className="muted" style={{ fontSize: 12, paddingTop: 10 }}>bol-advertenties kunnen via de API alleen worden uitgelezen (rapportage-rechten) — biedingen en budgetten daarvoor beheer je in het bol-adverteerdersdashboard.</div>
      </div>
    </Card>
  );
}

/* ---- Demo-blokken Advertenties (zoektermen / acties / AI-chat) ---- */
function DemoPill() { return <span className="pill warn" style={{ marginLeft: 8 }}>Demo</span>; }
function DemoZoektermen() {
  const terms = [
    { term: "pizzahout", cost: 18.4, sales: 96.5, conv: 6, adv: ["ok", "Opschalen"] },
    { term: "aanmaakhout 20 kg", cost: 12.1, sales: 58.2, conv: 4, adv: ["ok", "Toevoegen als exact"] },
    { term: "goedkoop brandhout", cost: 9.8, sales: 0, conv: 0, adv: ["danger", "Negatief maken"] },
    { term: "houten doosje cadeau", cost: 6.2, sales: 7.1, conv: 1, adv: ["warn", "Monitoren"] },
    { term: "aanmaakkrullen", cost: 4.9, sales: 31.0, conv: 3, adv: ["ok", "Opschalen"] },
  ];
  return (
    <Card style={{ marginTop: "var(--space)" }}>
      <CardHead title={<span>Zoektermen-analyse<DemoPill /></span>} icon="search2" right={<span className="muted" style={{ fontSize: 12 }}>voorbeelddata</span>} />
      <div style={{ overflowX: "auto" }}>
        <table className="tbl">
          <thead><tr><th>Zoekterm</th><th className="num">Kosten</th><th className="num">Omzet</th><th className="num">ROAS</th><th className="num">Conversies</th><th>Aanbeveling</th></tr></thead>
          <tbody>
            {terms.map(t => (
              <tr key={t.term}><td style={{ fontWeight: 600, fontSize: 13 }}>“{t.term}”</td><td className="num tnum">{fmtEur(t.cost)}</td><td className="num tnum">{t.sales > 0 ? fmtEur(t.sales) : "—"}</td><td className="num tnum">{t.sales > 0 ? (t.sales / t.cost).toFixed(1) + "×" : "—"}</td><td className="num tnum muted">{t.conv}</td><td><span className={"pill " + t.adv[0]}>{t.adv[1]}</span></td></tr>
            ))}
          </tbody>
        </table>
      </div>
      <div className="card-pad muted" style={{ fontSize: 12, paddingTop: 8 }}>Demo met voorbeelddata — de echte zoektermen halen we straks live uit de Google Ads API, met aanbevelingen van AdPilot.</div>
    </Card>
  );
}
function DemoActies({ items }) {
  const [fb, setFb] = React.useState({});
  const doAct = (k, act) => setFb(o => Object.assign({}, o, { [k]: act + " klaargezet ✓ (demo — wordt nog niet uitgevoerd)" }));
  return (
    <Card style={{ marginTop: "var(--space)" }}>
      <CardHead title={<span>Acties vanuit het dashboard<DemoPill /></span>} icon="check" right={<span className="muted" style={{ fontSize: 12 }}>bod · budget · pauzeren</span>} />
      <div className="card-pad" style={{ paddingTop: 4 }}>
        {(items || []).map((it, i) => (
          <div key={i} style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap", padding: "9px 0", borderTop: i ? "1px solid var(--border)" : "none" }}>
            <span style={{ fontWeight: 600, fontSize: 13, flex: "1 1 180px" }}>{it.name} <span className="muted" style={{ fontWeight: 400 }}>· {it.type}</span></span>
            {fb[i] ? <span style={{ fontSize: 12.5, color: "var(--ok)", fontWeight: 600 }}>{fb[i]}</span> : (
              <span style={{ display: "inline-flex", gap: 6, flexWrap: "wrap" }}>
                <button className="btn btn-sm btn-ghost" onClick={() => doAct(i, "Bod −10%")}>Bod −10%</button>
                <button className="btn btn-sm btn-ghost" onClick={() => doAct(i, "Bod +10%")}>Bod +10%</button>
                <button className="btn btn-sm btn-ghost" onClick={() => doAct(i, "Budgetwijziging")}>Budget…</button>
                <button className="btn btn-sm btn-ghost" onClick={() => doAct(i, "Pauzeren")}>Pauzeer</button>
              </span>
            )}
          </div>
        ))}
        <div className="muted" style={{ fontSize: 12, paddingTop: 10 }}>Demo — de knoppen voeren nog niets uit. In de echte versie gaan deze acties met één bevestiging rechtstreeks naar bol en Google Ads.</div>
      </div>
    </Card>
  );
}
function DemoChat({ advies }) {
  const [msgs, setMsgs] = React.useState([{ who: "ai", txt: "Hoi! Ik ben AdPilot Chat (demo). Kies een voorbeeldvraag hieronder of typ zelf iets." }]);
  const [inp, setInp] = React.useState("");
  const chips = ["Waar verlies ik geld?", "Welke producten kan ik opschalen?", "Waarom daalde mijn omzet gisteren?"];
  const ask = (q) => {
    if (!q.trim()) return;
    let ans;
    if (/verlies/i.test(q)) ans = (advies || []).filter(a => a.sev === "danger").map(a => "• " + a.txt).join("\n") || "Ik zie op dit moment geen duidelijke verliezers — je advertenties draaien gezond.";
    else if (/opschalen|verhogen/i.test(q)) ans = (advies || []).filter(a => a.sev === "ok").map(a => "• " + a.txt).join("\n") || "Geen duidelijke opschaal-kandidaten in deze periode.";
    else ans = "Dit is een demo — in de echte versie beantwoord ik deze vraag op basis van je live cijfers (omzet, winst, ads, voorraad) via een AI-koppeling.";
    setMsgs(m => [...m, { who: "me", txt: q }, { who: "ai", txt: ans }]);
    setInp("");
  };
  return (
    <Card style={{ marginTop: "var(--space)" }}>
      <CardHead title={<span>AdPilot Chat<DemoPill /></span>} icon="info" right={<span className="muted" style={{ fontSize: 12 }}>vraag het je data</span>} />
      <div className="card-pad" style={{ paddingTop: 4 }}>
        <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 10 }}>
          {msgs.map((m, i) => (
            <div key={i} style={{ alignSelf: m.who === "me" ? "flex-end" : "flex-start", maxWidth: "85%", background: m.who === "me" ? "var(--brand-soft)" : "var(--bg)", border: "1px solid var(--border)", borderRadius: 12, padding: "8px 12px", fontSize: 13, whiteSpace: "pre-line", lineHeight: 1.45 }}>{m.txt}</div>
          ))}
        </div>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 10 }}>
          {chips.map(c => <button key={c} className="btn btn-sm btn-ghost" onClick={() => ask(c)}>{c}</button>)}
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <input value={inp} onChange={e => setInp(e.target.value)} onKeyDown={e => { if (e.key === "Enter") ask(inp); }} placeholder="Stel een vraag over je advertenties…" style={{ flex: 1, border: "1px solid var(--border)", borderRadius: 10, padding: "9px 12px", fontSize: 13, background: "var(--bg)" }} />
          <button className="btn btn-sm" onClick={() => ask(inp)}>Verstuur</button>
        </div>
        <div className="muted" style={{ fontSize: 12, paddingTop: 10 }}>Demo — antwoorden komen nu uit de AdPilot-regels. De volledige AI-chat koppelen we later via een AI-sleutel in de datakraan.</div>
      </div>
    </Card>
  );
}

Object.assign(window, { Reviews, Rankings, SEO, Meldingen, Retouren, Advertenties, AdPilotChat, ZoektermenCard, ActiesCard });
