// view-admin-stats.jsx — Page « Chiffres » consolidée (Admin KODAMA).
// Récap transversal de TOUS les jeux en même temps, empilés par année de sortie FR.
// Bandeau de KPIs globaux (CA, bénéfice, marge, exemplaires, à encaisser) + une section par année.
// 3 dispositions au choix via Tweaks → « Page Chiffres » :
//   A · Tableau par année    — chaque année : un tableau propre, une ligne par jeu
//   B · Cartes par jeu       — chaque année : des cartes visuelles par jeu
//   C · Tableau dense + barres — comparaison annuelle (barres) + un grand tableau groupé

function sEuro(n, dec) {
  if (n == null || n === "" || isNaN(n)) return "—";
  return Number(n).toLocaleString("fr-FR", { minimumFractionDigits: dec || 0, maximumFractionDigits: dec || 0 }) + " €";
}
function sPct(v) {
  if (v == null || isNaN(v)) return "—";
  return Math.round(v * 100) + " %";
}
function sNum(n) { return (n || 0).toLocaleString("fr-FR"); }

// ——— Agrégation : un objet par jeu (volumes + finances), groupé par année de sortie FR ———
function statsAggregate(gs) {
  const t = { gameCount: gs.length, printCount: 0, totalQty: 0, activeQty: 0, doneQty: 0, ca: 0, benef: 0, toEncash: 0, unpaidCount: 0, partnerSet: new Set() };
  gs.forEach((g) => {
    t.printCount += g.prints.length; t.totalQty += g.totalQty; t.activeQty += g.activeQty; t.doneQty += g.doneQty;
    t.ca += g.ca; t.benef += g.benef; t.toEncash += g.toEncash; t.unpaidCount += g.unpaidCount;
    Object.keys(g.partnerIds).forEach((id) => t.partnerSet.add(id));
  });
  t.marge = t.ca > 0 ? t.benef / t.ca : null;
  t.partnerCount = t.partnerSet.size;
  return t;
}

function buildStatsData(db) {
  const gameById = {};
  (db.games || []).forEach((g) => { gameById[g.id] = g; });
  const prodsByPrint = {};
  db.productions.forEach((p) => { (prodsByPrint[p.printId] = prodsByPrint[p.printId] || []).push(p); });

  // Année d'un print = année de la date de fin de prod la plus tardive de ses productions.
  // Sans date de fin → le print n'est pas encore terminé → bucket « en cours ».
  function printYearKey(pr) {
    const prods = prodsByPrint[pr.id] || [];
    let end = null;
    prods.forEach((p) => { if (p.prodEnd && (!end || p.prodEnd > end)) end = p.prodEnd; });
    return end ? end.slice(0, 4) : "__active";
  }

  // Accumulation par (année → jeu) : un jeu peut donc figurer dans plusieurs années.
  const years = {};
  db.prints.forEach((pr) => {
    const prods = prodsByPrint[pr.id] || [];
    if (prods.length === 0) return;
    const y = printYearKey(pr);
    const bucket = years[y] || (years[y] = {});
    const gRef = gameById[pr.gameId] || {};
    const g = bucket[pr.gameId] || (bucket[pr.gameId] = { id: pr.gameId, name: pr.game,
      ppht: gRef.ppht != null ? gRef.ppht : null, prints: [],
      totalQty: 0, activeQty: 0, doneQty: 0, partnerIds: {}, ca: 0, benef: 0, caCount: 0, toEncash: 0, unpaidCount: 0 });
    g.prints.push(pr);
    prods.forEach((p) => {
      g.totalQty += p.qty || 0;
      g.partnerIds[p.partnerId] = true;
      if (p.statut === "Terminé") g.doneQty += p.qty || 0; else g.activeQty += p.qty || 0;
      if (p.caPost != null) { g.ca += p.caPost; g.caCount++; }
      if (p.benefPost != null) g.benef += p.benefPost;
      if (p.factStatut && p.factStatut !== "paid") { g.unpaidCount++; g.toEncash += p.caPost || 0; }
    });
  });

  // Années terminées en premier (décroissant), puis le bucket « en cours » en dernier.
  const yearKeys = Object.keys(years).sort((a, b) => (a === "__active" ? 1 : b === "__active" ? -1 : b.localeCompare(a)));
  const yearGroups = yearKeys.map((y) => {
    const list = Object.values(years[y]).map((g) => ({
      ...g,
      partnerCount: Object.keys(g.partnerIds).length,
      marge: g.ca > 0 ? g.benef / g.ca : null,
      valeurHT: g.ppht != null ? g.totalQty * g.ppht : null,
      printsLabel: g.prints.map((p) => p.label).join(" · "),
    })).sort((a, b) => b.totalQty - a.totalQty);
    return Object.assign({ year: y, isActive: y === "__active", label: y === "__active" ? "En cours — sans date de fin" : y, games: list }, statsAggregate(list));
  });
  const allRows = yearGroups.reduce((acc, grp) => acc.concat(grp.games), []);
  return { yearGroups, totals: statsAggregate(allRows) };
}

// ——— Bandeau de KPIs globaux ———
function KpiTile({ label, value, sub, fg, first }) {
  return (
    <div style={{ flex: "1 1 168px", minWidth: 150, padding: "6px 22px", borderLeft: first ? "none" : `1px solid ${K.line}` }}>
      <div style={{ fontSize: 11, fontWeight: 800, letterSpacing: ".05em", textTransform: "uppercase", color: K.sub }}>{label}</div>
      <div className="k-round" style={{ fontSize: 33, fontWeight: 700, lineHeight: 1.08, marginTop: 4, color: fg || K.ink, whiteSpace: "nowrap" }}>{value}</div>
      {sub ? <div style={{ fontSize: 11.5, color: K.sub, marginTop: 2 }}>{sub}</div> : null}
    </div>
  );
}
function StatKpiBanner({ totals }) {
  const tiles = [
    { label: "CA Post Prod'", value: sEuro(totals.ca) },
    { label: "Bénéfice", value: sEuro(totals.benef), fg: K.green },
    { label: "Marge moyenne", value: sPct(totals.marge) },
    { label: "Exemplaires produits", value: sNum(totals.totalQty), sub: sNum(totals.activeQty) + " en production" },
    { label: "Reste à encaisser", value: sEuro(totals.toEncash), fg: totals.unpaidCount ? K.amber : K.green,
      sub: totals.unpaidCount ? totals.unpaidCount + " facture" + (totals.unpaidCount > 1 ? "s" : "") + " à suivre" : "tout est encaissé" },
  ];
  return (
    <div className="k-card" style={{ overflow: "hidden", marginTop: 14 }}>
      <div style={{ height: 4, background: K.grad }}></div>
      <div style={{ display: "flex", flexWrap: "wrap", padding: "16px 4px", alignItems: "stretch" }}>
        {tiles.map((tl, i) => <KpiTile key={tl.label} {...tl} first={i === 0} />)}
      </div>
    </div>
  );
}

// ——— En-tête d'une année (bandeau récap) ———
function MiniStat({ label, value, fg }) {
  return (
    <div style={{ textAlign: "right" }}>
      <div style={{ fontSize: 10, fontWeight: 800, letterSpacing: ".05em", textTransform: "uppercase", color: K.sub }}>{label}</div>
      <div className="k-mono" style={{ fontSize: 14, fontWeight: 700, color: fg || K.ink, whiteSpace: "nowrap" }}>{value}</div>
    </div>
  );
}
function YearBand({ grp, style }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap", ...style }}>
      <div style={{ display: "flex", alignItems: "baseline", gap: 12, flexWrap: "wrap" }}>
        <div className="k-round" style={{ fontSize: grp.isActive ? 24 : 30, fontWeight: 700, lineHeight: 1, color: grp.isActive ? K.sub : K.ink }}>{grp.label}</div>
        <span style={{ fontSize: 13, color: K.sub }}>{grp.gameCount} jeu{grp.gameCount > 1 ? "x" : ""} · {grp.printCount} print{grp.printCount > 1 ? "s" : ""} · {sNum(grp.totalQty)} ex.</span>
      </div>
      <div style={{ marginLeft: "auto", display: "flex", gap: 22, flexWrap: "wrap" }}>
        <MiniStat label="CA" value={sEuro(grp.ca)} />
        <MiniStat label="Bénéfice" value={sEuro(grp.benef)} fg={grp.benef > 0 ? K.green : K.ink} />
        <MiniStat label="Marge" value={sPct(grp.marge)} />
        {grp.toEncash > 0 ? <MiniStat label="À encaisser" value={sEuro(grp.toEncash)} fg={K.amber} /> : null}
      </div>
    </div>
  );
}

// Petite étiquette de facturation (à encaisser / soldé / —)
function FactChip({ g }) {
  if (g.unpaidCount > 0) return <Pill fg={K.amber} bg={K.amberBg}>À encaisser {sEuro(g.toEncash)}</Pill>;
  if (g.ca > 0) return <Pill fg={K.green} bg={K.greenBg}>Soldé</Pill>;
  return <span style={{ fontSize: 12, color: K.sub }}>—</span>;
}

function GameDot({ name }) {
  return <span style={{ width: 10, height: 10, borderRadius: 99, background: gameColor(name).mid, flexShrink: 0, display: "inline-block" }}></span>;
}

// ——— A · Tableau par année ———
function StatYearTable({ grp, setNav }) {
  const head = { textAlign: "left", padding: "9px 10px", fontSize: 10.5, fontWeight: 800, letterSpacing: ".04em", textTransform: "uppercase", color: K.sub, whiteSpace: "nowrap" };
  const cell = { padding: "11px 10px", borderTop: `1px solid ${K.line}`, fontSize: 13, verticalAlign: "middle" };
  const num = { ...cell, textAlign: "right", fontFamily: K.mono };
  return (
    <div style={{ marginTop: 22 }}>
      <YearBand grp={grp} />
      <div className="k-card" style={{ marginTop: 10, overflow: "hidden" }}>
        <div style={{ overflowX: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 760 }}>
            <thead><tr>
              <th style={head}>Jeu</th>
              <th style={{ ...head, textAlign: "right" }}>Exemplaires</th>
              <th style={{ ...head, textAlign: "right" }}>En prod'</th>
              <th style={{ ...head, textAlign: "right" }}>Part.</th>
              <th style={{ ...head, textAlign: "right" }}>CA Post Prod'</th>
              <th style={{ ...head, textAlign: "right" }}>Bénéfice</th>
              <th style={{ ...head, textAlign: "right" }}>Marge</th>
              <th style={head}>Facturation</th>
            </tr></thead>
            <tbody>
              {grp.games.map((g) => (
                <tr key={g.id} onClick={() => setNav({ page: "game", gameId: g.id })} style={{ cursor: "pointer" }}
                  onMouseEnter={(e) => e.currentTarget.style.background = "#FAF9F7"} onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
                  <td style={{ ...cell, fontWeight: 700 }}>
                    <span style={{ display: "flex", alignItems: "center", gap: 9 }}><GameDot name={g.name} /> <span>{g.name}<span style={{ display: "block", fontSize: 11, fontWeight: 500, color: K.sub }}>{g.printsLabel}</span></span></span>
                  </td>
                  <td style={num}>{sNum(g.totalQty)}</td>
                  <td style={{ ...num, color: g.activeQty > 0 ? K.ink : K.sub }}>{g.activeQty > 0 ? sNum(g.activeQty) : "—"}</td>
                  <td style={num}>{g.partnerCount}</td>
                  <td style={{ ...num, fontWeight: 600 }}>{sEuro(g.ca)}</td>
                  <td style={{ ...num, fontWeight: 600, color: g.ca > 0 ? (g.benef < 0 ? K.red : K.green) : K.sub }}>{g.ca > 0 ? sEuro(g.benef) : "—"}</td>
                  <td style={num}>{sPct(g.marge)}</td>
                  <td style={cell}><FactChip g={g} /></td>
                </tr>
              ))}
            </tbody>
            <tfoot>
              <tr>
                <td style={{ ...cell, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>Total {grp.isActive ? "en cours" : grp.year}</td>
                <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{sNum(grp.totalQty)}</td>
                <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{sNum(grp.activeQty)}</td>
                <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{grp.partnerCount}</td>
                <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{sEuro(grp.ca)}</td>
                <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800, color: K.green }}>{sEuro(grp.benef)}</td>
                <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{sPct(grp.marge)}</td>
                <td style={{ ...cell, borderTop: `2px solid ${K.ink}` }}>{grp.toEncash > 0 ? <Pill fg={K.amber} bg={K.amberBg}>{sEuro(grp.toEncash)}</Pill> : null}</td>
              </tr>
            </tfoot>
          </table>
        </div>
      </div>
    </div>
  );
}

// ——— B · Cartes par jeu ———
function StatTile({ label, value, sub, fg }) {
  return (
    <div style={{ background: "#FAF9F7", borderRadius: 10, padding: "9px 13px" }}>
      <div style={{ fontSize: 10, fontWeight: 800, letterSpacing: ".04em", textTransform: "uppercase", color: K.sub }}>{label}</div>
      <div className="k-round" style={{ fontSize: 21, fontWeight: 700, lineHeight: 1.1, marginTop: 1, color: fg || K.ink }}>{value}</div>
      {sub ? <div style={{ fontSize: 11, color: K.sub, marginTop: 1 }}>{sub}</div> : null}
    </div>
  );
}
function StatGameCard({ g, setNav }) {
  const gc = gameColor(g.name);
  return (
    <div className="k-card" style={{ overflow: "hidden", cursor: "pointer" }} onClick={() => setNav({ page: "game", gameId: g.id })}>
      <div style={{ height: 4, background: `linear-gradient(90deg, ${gc.mid}, ${gc.soft})` }}></div>
      <div style={{ padding: "13px 16px 15px" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 11 }}>
          <GameDot name={g.name} />
          <span className="k-round" style={{ fontSize: 18, fontWeight: 700 }}>{g.name}</span>
          <span style={{ marginLeft: "auto", fontSize: 12, fontWeight: 700, color: gc.fg }}>ouvrir →</span>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
          <StatTile label="Exemplaires" value={sNum(g.totalQty)} sub={g.printsLabel} />
          <StatTile label="En production" value={g.activeQty > 0 ? sNum(g.activeQty) : "—"} fg={g.activeQty > 0 ? K.ink : K.sub} />
          <StatTile label="CA Post Prod'" value={sEuro(g.ca)} />
          <StatTile label="Bénéfice" value={g.ca > 0 ? sEuro(g.benef) : "—"} fg={g.ca > 0 ? K.green : K.sub} sub={g.ca > 0 ? "marge " + sPct(g.marge) : null} />
        </div>
        <div style={{ marginTop: 11, display: "flex", alignItems: "center", gap: 9, flexWrap: "wrap" }}>
          <FactChip g={g} />
          {g.valeurHT != null ? <span style={{ fontSize: 11.5, color: K.sub }}>Valeur PP HT ≈ {sEuro(Math.round(g.valeurHT))}</span> : null}
        </div>
      </div>
    </div>
  );
}
function StatYearCards({ grp, setNav }) {
  return (
    <div style={{ marginTop: 22 }}>
      <YearBand grp={grp} />
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", gap: 14, marginTop: 12 }}>
        {grp.games.map((g) => <StatGameCard key={g.id} g={g} setNav={setNav} />)}
      </div>
    </div>
  );
}

// ——— C · Tableau dense + barres ———
function YearBars({ yearGroups }) {
  const maxQty = Math.max(1, ...yearGroups.map((y) => y.totalQty));
  const maxCa = Math.max(1, ...yearGroups.map((y) => y.ca));
  const rows = yearGroups.slice().sort((a, b) => (a.isActive ? 1 : b.isActive ? -1 : a.year.localeCompare(b.year)));
  return (
    <div className="k-card" style={{ marginTop: 14, padding: "16px 20px" }}>
      <div className="k-label" style={{ marginBottom: 12 }}>Comparaison par année <span style={{ fontWeight: 500, textTransform: "none", letterSpacing: 0, color: K.sub }}>(d'après la date de fin de print)</span></div>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        {rows.map((y) => (
          <div key={y.year} style={{ display: "grid", gridTemplateColumns: "84px 1fr", gap: 14, alignItems: "center" }}>
            <div className="k-round" style={{ fontSize: y.isActive ? 14 : 18, fontWeight: 700, color: y.isActive ? K.sub : K.ink }}>{y.isActive ? "En cours" : y.year}</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                <div style={{ flex: 1, height: 16, borderRadius: 6, background: K.grayBg, overflow: "hidden" }}>
                  <div style={{ width: Math.max(2, (y.totalQty / maxQty) * 100) + "%", height: "100%", background: K.blue, borderRadius: 6 }}></div>
                </div>
                <span className="k-mono" style={{ fontSize: 12, fontWeight: 600, minWidth: 92, textAlign: "right" }}>{sNum(y.totalQty)} ex.</span>
              </div>
              <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                <div style={{ flex: 1, height: 16, borderRadius: 6, background: K.grayBg, overflow: "hidden" }}>
                  <div style={{ width: Math.max(2, (y.ca / maxCa) * 100) + "%", height: "100%", background: K.green, borderRadius: 6 }}></div>
                </div>
                <span className="k-mono" style={{ fontSize: 12, fontWeight: 600, minWidth: 92, textAlign: "right" }}>{sEuro(y.ca)}</span>
              </div>
            </div>
          </div>
        ))}
      </div>
      <div style={{ display: "flex", gap: 18, marginTop: 14, fontSize: 11.5, color: K.sub }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}><span style={{ width: 11, height: 11, borderRadius: 3, background: K.blue }}></span> Exemplaires produits</span>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}><span style={{ width: 11, height: 11, borderRadius: 3, background: K.green }}></span> CA Post Prod'</span>
      </div>
    </div>
  );
}
function StatDenseTable({ yearGroups, totals, setNav }) {
  const maxQty = Math.max(1, ...yearGroups.flatMap((y) => y.games.map((g) => g.totalQty)));
  const head = { textAlign: "left", padding: "9px 10px", fontSize: 10.5, fontWeight: 800, letterSpacing: ".04em", textTransform: "uppercase", color: K.sub, whiteSpace: "nowrap" };
  const cell = { padding: "10px 10px", borderTop: `1px solid ${K.line}`, fontSize: 12.5, verticalAlign: "middle" };
  const num = { ...cell, textAlign: "right", fontFamily: K.mono };
  return (
    <div className="k-card" style={{ marginTop: 16, overflow: "hidden" }}>
      <div style={{ overflowX: "auto" }}>
        <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 820 }}>
          <thead><tr>
            <th style={head}>Jeu</th>
            <th style={{ ...head, width: 200 }}>Exemplaires</th>
            <th style={{ ...head, textAlign: "right" }}>En prod'</th>
            <th style={{ ...head, textAlign: "right" }}>Part.</th>
            <th style={{ ...head, textAlign: "right" }}>CA</th>
            <th style={{ ...head, textAlign: "right" }}>Bénéfice</th>
            <th style={{ ...head, textAlign: "right" }}>Marge</th>
            <th style={head}>Factu.</th>
          </tr></thead>
          <tbody>
            {yearGroups.map((grp) => (
              <React.Fragment key={grp.year}>
                <tr>
                  <td colSpan={8} style={{ background: "#F2F0EC", padding: "8px 12px", borderTop: `1px solid ${K.line}` }}>
                    <span style={{ display: "inline-flex", alignItems: "baseline", gap: 10, flexWrap: "wrap" }}>
                      <span className="k-round" style={{ fontSize: 16, fontWeight: 700 }}>{grp.label}</span>
                      <span style={{ fontSize: 11.5, color: K.sub }}>{sNum(grp.totalQty)} ex. · CA {sEuro(grp.ca)} · bénéfice {sEuro(grp.benef)} · marge {sPct(grp.marge)}</span>
                    </span>
                  </td>
                </tr>
                {grp.games.map((g) => (
                  <tr key={g.id} onClick={() => setNav({ page: "game", gameId: g.id })} style={{ cursor: "pointer" }}
                    onMouseEnter={(e) => e.currentTarget.style.background = "#FAF9F7"} onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
                    <td style={{ ...cell, fontWeight: 700 }}><span style={{ display: "flex", alignItems: "center", gap: 9 }}><GameDot name={g.name} /> <span>{g.name}<span style={{ display: "block", fontSize: 10.5, fontWeight: 500, color: K.sub }}>{g.printsLabel}</span></span></span></td>
                    <td style={cell}>
                      <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
                        <div style={{ flex: 1, height: 9, borderRadius: 99, background: K.grayBg, overflow: "hidden", minWidth: 60 }}>
                          <div style={{ width: Math.max(3, (g.totalQty / maxQty) * 100) + "%", height: "100%", background: gameColor(g.name).mid, borderRadius: 99 }}></div>
                        </div>
                        <span className="k-mono" style={{ fontSize: 12, fontWeight: 600, minWidth: 54, textAlign: "right" }}>{sNum(g.totalQty)}</span>
                      </div>
                    </td>
                    <td style={{ ...num, color: g.activeQty > 0 ? K.ink : K.sub }}>{g.activeQty > 0 ? sNum(g.activeQty) : "—"}</td>
                    <td style={num}>{g.partnerCount}</td>
                    <td style={{ ...num, fontWeight: 600 }}>{sEuro(g.ca)}</td>
                    <td style={{ ...num, fontWeight: 600, color: g.ca > 0 ? (g.benef < 0 ? K.red : K.green) : K.sub }}>{g.ca > 0 ? sEuro(g.benef) : "—"}</td>
                    <td style={num}>{sPct(g.marge)}</td>
                    <td style={cell}><FactChip g={g} /></td>
                  </tr>
                ))}
              </React.Fragment>
            ))}
          </tbody>
          <tfoot>
            <tr>
              <td style={{ ...cell, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>Tous jeux</td>
              <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{sNum(totals.totalQty)}</td>
              <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{sNum(totals.activeQty)}</td>
              <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{totals.partnerCount}</td>
              <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{sEuro(totals.ca)}</td>
              <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800, color: K.green }}>{sEuro(totals.benef)}</td>
              <td style={{ ...num, borderTop: `2px solid ${K.ink}`, fontWeight: 800 }}>{sPct(totals.marge)}</td>
              <td style={{ ...cell, borderTop: `2px solid ${K.ink}` }}>{totals.toEncash > 0 ? <Pill fg={K.amber} bg={K.amberBg}>{sEuro(totals.toEncash)}</Pill> : null}</td>
            </tr>
          </tfoot>
        </table>
      </div>
    </div>
  );
}

// ——— Page complète ———
function AdminStatsPage({ db, setNav, t }) {
  const { yearGroups, totals } = React.useMemo(() => buildStatsData(db), [db]);
  const layout = ((t && t.statsLayout) || "A · Tableau par année")[0];
  const today = new Date();
  const dateStr = today.toLocaleDateString("fr-FR", { day: "numeric", month: "long", year: "numeric" });

  return (
    <div data-comment-anchor="admin-stats" data-screen-label="Chiffres consolidés">
      <div style={{ display: "flex", alignItems: "baseline", gap: 14, flexWrap: "wrap" }}>
        <div className="k-round" style={{ fontSize: 24, fontWeight: 700 }}>Chiffres — vue d'ensemble</div>
        <div style={{ fontSize: 13, color: K.sub }}>Tous les jeux · par date de fin de print</div>
        <div style={{ marginLeft: "auto", fontSize: 12.5, color: K.sub, textTransform: "capitalize" }}>{dateStr}</div>
      </div>

      <StatKpiBanner totals={totals} />

      {layout === "C" && <YearBars yearGroups={yearGroups} />}

      {yearGroups.length === 0 && (
        <div className="k-card" style={{ marginTop: 16, padding: 22, color: K.sub, textAlign: "center" }}>Aucun jeu à afficher.</div>
      )}

      {layout === "C"
        ? <StatDenseTable yearGroups={yearGroups} totals={totals} setNav={setNav} />
        : yearGroups.map((grp) => layout === "B"
            ? <StatYearCards key={grp.year} grp={grp} setNav={setNav} />
            : <StatYearTable key={grp.year} grp={grp} setNav={setNav} />)}

      <p style={{ fontSize: 11.5, color: K.sub, margin: "18px 2px 0", maxWidth: 760 }}>
        Chiffres calculés en direct depuis les productions export du portail. Les jeux sont regroupés par <strong>année de fin de print</strong> (date de fin de production la plus tardive du print) — un même jeu peut donc apparaître sur plusieurs années, et les prints pas encore datés figurent dans « En cours ». Le CA, le bénéfice et la marge proviennent des fiches de facturation (champs Airtable) ; un print sans facturation renseignée affiche « — ». Cliquez sur un jeu pour ouvrir sa fiche.
      </p>
    </div>
  );
}

Object.assign(window, { AdminStatsPage, buildStatsData });
