// -----------------------------------------------------------------------------
// Food-Ka — Agrégateur de produits d'épicerie (province de Québec)
// Auteur : Simon-Pierre Boucher — contact@spboucher.ai
// pages/Stats.tsx : observatoire du marché — consomme /api/stats/detailed
//   · Tuiles héro (produits, soldes, bannières, marques, prix médian, activité 7 j)
//   · 🧺 Panier comparatif : articles courants × bannières (prix médians)
//   · Bannières en chiffres (tableau triable, mini-barres de prix médian)
//   · Matrice catégorie × bannière (teinte chaleur, moins cher en vert)
//   · Distribution des prix, baisses de prix (7 j)
//   · Meilleures aubaines + journal des synchronisations (/api/stats)
// -----------------------------------------------------------------------------
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import {
  BasketTotal, DetailedStats, SourceMarketStats, Stats,
  fetchSources, fetchStats, fmtTs, registerSourceNames,
  sourceName, sourceShort, statsDetailed,
} from "../api";
import ProductCard from "../components/ProductCard";
import SourceLogo from "../components/SourceLogo";

const fmt = (n: number | null | undefined) =>
  n == null ? "—" : n.toLocaleString("fr-CA");
const fmt$ = (n: number | null | undefined) =>
  n == null
    ? "—"
    : `${n.toLocaleString("fr-CA", { minimumFractionDigits: 2, maximumFractionDigits: 2 })} $`;
const fmtPct = (n: number | null | undefined, digits = 0) =>
  n == null
    ? "—"
    : `${n.toLocaleString("fr-CA", { maximumFractionDigits: digits })} %`;

function Tile({ v, k, hero }: { v: string; k: string; hero?: boolean }) {
  return (
    <div className={`tile ${hero ? "hero-tile" : ""}`}>
      <div className="tile-v">{v}</div>
      <div className="tile-k">{k}</div>
    </div>
  );
}

// clés numériques triables du tableau « bannières en chiffres »
type BannerSortKey = "n" | "median_price" | "sale_share" | "avg_discount_pct" | "max_discount_pct";

export default function StatsPage() {
  const [d, setD] = useState<Stats | null>(null);           // /api/stats (aubaines + journal)
  const [m, setM] = useState<DetailedStats | null>(null);   // /api/stats/detailed
  const [error, setError] = useState<string | null>(null);
  const [sortKey, setSortKey] = useState<BannerSortKey>("n");
  const [sortDir, setSortDir] = useState<-1 | 1>(-1);

  useEffect(() => {
    fetchSources().then((r) => registerSourceNames(r.sources)).catch(() => {});
    fetchStats().then(setD).catch((e) => setError(String(e)));
    statsDetailed().then(setM).catch((e) => setError(String(e)));
  }, []);

  if (error)
    return (
      <div className="notice container">
        <div className="big">⚠️</div>
        <h2>Statistiques indisponibles</h2>
        <p>{error}</p>
      </div>
    );

  if (!m || !d)
    return (
      <div className="container stats-page" aria-busy="true">
        <div className="skel" style={{ height: 110, marginTop: 40 }} />
        <div className="tiles" style={{ marginTop: 20 }}>
          {Array.from({ length: 6 }).map((_, i) => (
            <div className="skel" key={i} style={{ height: 92 }} />
          ))}
        </div>
        <div className="skel" style={{ height: 320, marginTop: 8 }} />
        <div className="skel" style={{ height: 260, marginTop: 22 }} />
      </div>
    );

  const g = m.global;

  // ---- panier comparatif -----------------------------------------------------
  // colonnes = bannières couvrant assez d'articles, déjà triées du moins cher
  const basketCols = m.basket_totals.map((t) => t.source);
  const bestBasket: BasketTotal | null = m.basket_totals[0] ?? null;
  const totalBySrc: Record<string, BasketTotal> = {};
  for (const t of m.basket_totals) totalBySrc[t.source] = t;

  // ---- tableau bannières (triable) --------------------------------------------
  const numOf = (r: SourceMarketStats, k: BannerSortKey): number =>
    (r[k] ?? -Infinity) as number;
  const bannerRows = [...m.by_source].sort(
    (a, b) => (numOf(a, sortKey) - numOf(b, sortKey)) * sortDir || b.n - a.n
  );
  const maxMedian = Math.max(...m.by_source.map((r) => r.median_price ?? 0), 0.01);
  const sortBy = (k: BannerSortKey) => {
    if (sortKey === k) setSortDir((dir) => (dir === -1 ? 1 : -1));
    else { setSortKey(k); setSortDir(-1); }
  };
  const Th = ({ k, label }: { k: BannerSortKey; label: string }) => (
    <th
      className={`sortable ${sortKey === k ? "sorted" : ""}`}
      onClick={() => sortBy(k)}
      title="Trier"
    >
      {label}{sortKey === k ? (sortDir === -1 ? " ▾" : " ▴") : ""}
    </th>
  );

  // ---- matrice catégorie × bannière --------------------------------------------
  const matrixSources = m.by_source.slice(0, 9).map((s) => s.source);
  const matrixRows = Object.entries(m.category_matrix)
    .map(([cat, per]) => ({
      cat, per,
      total: Object.values(per).reduce((s, c) => s + c.n, 0),
    }))
    .sort((a, b) => b.total - a.total);

  // ---- distribution des prix ---------------------------------------------------
  const distMax = Math.max(...m.price_distribution.map((b) => b.n), 1);

  return (
    <div className="container stats-page">
      <span className="kicker">Observatoire — prix d'épicerie au Québec</span>
      <div className="stats-head">
        <h1 className="stats-title">L'épicerie, en chiffres</h1>
        <a className="btn btn-primary btn-pdf" href="/api/stats/rapport.pdf" download>
          ↓ Télécharger le rapport PDF
        </a>
      </div>
      <p className="sub">
        Calculé en direct sur les {fmt(g.total)} produits actifs de {fmt(g.sources)} bannières,
        répartis dans {fmt(g.categories)} catégories et {fmt(g.brands)} marques.
      </p>

      {/* ---- 1 · tuiles héro ---- */}
      <div className="tiles">
        <Tile hero v={fmt(g.total)} k="produits suivis" />
        <Tile v={fmtPct(g.sale_share * 100)} k={`en solde (${fmt(g.on_sale)} produits)`} />
        <Tile v={fmt(g.sources)} k="bannières connectées" />
        <Tile v={fmt(g.brands)} k="marques" />
        <Tile v={fmt$(g.median_price)} k="prix médian global" />
        <Tile v={fmt(g.price_changes_7d)} k="changements de prix (7 j)" />
      </div>

      {/* ---- 2 · panier comparatif ---- */}
      <section className="viz-card">
        <h2>🧺 Panier comparatif</h2>
        <p className="viz-sub">
          articles courants × bannières — prix médian des produits correspondants
        </p>
        {basketCols.length > 0 ? (
          <>
            <div className="basket-wrap">
              <table className="basket-table">
                <thead>
                  <tr>
                    <th>Article</th>
                    {basketCols.map((src) => (
                      <th key={src}
                          className={src === bestBasket?.source ? "best-col" : ""}>
                        <span className="basket-th">
                          <SourceLogo source={src} size={28} fallback="hide" />
                          {sourceShort(src)}
                        </span>
                      </th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {m.basket.map((row) => {
                    const prices = basketCols
                      .map((src) => row.by_source[src]?.median_price)
                      .filter((v): v is number => v != null);
                    const min = prices.length ? Math.min(...prices) : null;
                    return (
                      <tr key={row.item}>
                        <th>{row.item}</th>
                        {basketCols.map((src) => {
                          const cell = row.by_source[src];
                          const v = cell?.median_price ?? null;
                          const cls = [
                            v != null && v === min ? "cell-best" : "",
                            src === bestBasket?.source ? "best-col" : "",
                          ].join(" ").trim();
                          return (
                            <td key={src} className={cls}
                                title={cell ? `${fmt(cell.n)} produits correspondants` : undefined}>
                              {fmt$(v)}
                            </td>
                          );
                        })}
                      </tr>
                    );
                  })}
                </tbody>
                <tfoot>
                  <tr>
                    <th>Total du panier</th>
                    {basketCols.map((src) => {
                      const t = totalBySrc[src];
                      return (
                        <td key={src}
                            className={src === bestBasket?.source ? "best-col cell-best" : ""}>
                          {fmt$(t?.total)}
                          <small>{t ? `${t.items}/${m.basket.length} articles` : ""}</small>
                        </td>
                      );
                    })}
                  </tr>
                </tfoot>
              </table>
            </div>
            {bestBasket && (
              <div className="basket-callout">
                🏆 Panier le moins cher : <b>{sourceName(bestBasket.source)}</b> —{" "}
                {fmt$(bestBasket.total)} pour {bestBasket.items} articles
              </div>
            )}
            <p className="stats-foot">
              Prix médian des produits correspondant à chaque article chez la bannière ;
              seules les bannières couvrant la majorité du panier sont comparées.
            </p>
          </>
        ) : (
          <p className="fine">
            Pas encore assez de données pour composer le panier — il se remplit à
            mesure que les bannières sont synchronisées.
          </p>
        )}
      </section>

      {/* ---- 3 · bannières en chiffres ---- */}
      <section className="viz-card">
        <h2>Bannières en chiffres</h2>
        <p className="viz-sub">cliquez un en-tête pour trier · cliquez une bannière pour filtrer</p>
        <div className="stat-table-wrap">
          <table className="stat-table">
            <thead>
              <tr>
                <th>Bannière</th>
                <Th k="n" label="Produits" />
                <Th k="median_price" label="Prix médian" />
                <Th k="sale_share" label="En solde" />
                <Th k="avg_discount_pct" label="Rabais moyen" />
                <Th k="max_discount_pct" label="Rabais max" />
              </tr>
            </thead>
            <tbody>
              {bannerRows.map((r) => (
                <tr key={r.source}>
                  <td>
                    <Link to={`/?source=${encodeURIComponent(r.source)}`}>
                      <SourceLogo source={r.source} size={22} name="short" />
                    </Link>
                  </td>
                  <td>{fmt(r.n)}</td>
                  <td>
                    {fmt$(r.median_price)}
                    <span className="mini-track" aria-hidden="true">
                      <span className="mini-fill"
                            style={{ width: `${((r.median_price ?? 0) / maxMedian) * 100}%` }} />
                    </span>
                  </td>
                  <td className={r.sale_share > 0 ? "pct-sale" : ""}>
                    {fmtPct(r.sale_share * 100)}
                  </td>
                  <td>{fmtPct(r.avg_discount_pct, 1)}</td>
                  <td>{fmtPct(r.max_discount_pct, 1)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </section>

      {/* ---- 4 · matrice catégorie × bannière ---- */}
      <section className="viz-card">
        <h2>Prix médian par catégorie et bannière</h2>
        <p className="viz-sub">
          {matrixSources.length} plus grandes bannières — le moins cher de chaque rangée en vert
        </p>
        <div className="stat-table-wrap">
          <table className="stat-table matrix-table">
            <thead>
              <tr>
                <th>Catégorie</th>
                {matrixSources.map((src) => (
                  <th key={src} title={sourceName(src)}>
                    <span className="basket-th">
                      <SourceLogo source={src} size={24} fallback="hide" />
                      {sourceShort(src)}
                    </span>
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {matrixRows.map(({ cat, per }) => {
                const vals = matrixSources
                  .map((src) => per[src]?.median_price)
                  .filter((v): v is number => v != null);
                const min = vals.length ? Math.min(...vals) : null;
                const max = vals.length ? Math.max(...vals) : null;
                return (
                  <tr key={cat}>
                    <td>
                      <Link to={`/?category=${encodeURIComponent(cat)}`}>{cat}</Link>
                    </td>
                    {matrixSources.map((src) => {
                      const cell = per[src];
                      const v = cell?.median_price ?? null;
                      let style: React.CSSProperties | undefined;
                      if (v != null && min != null && max != null) {
                        if (v === min) style = { background: "rgba(46, 158, 99, 0.16)" };
                        else if (max > min) {
                          const t = (v - min) / (max - min);
                          style = { background: `rgba(232, 84, 47, ${(0.05 + 0.2 * t).toFixed(3)})` };
                        }
                      }
                      return (
                        <td key={src} style={style}
                            className={v != null && v === min ? "cell-best" : ""}
                            title={cell ? `${fmt(cell.n)} produits` : undefined}>
                          {fmt$(v)}
                        </td>
                      );
                    })}
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
        <div className="matrix-legend">
          <span><span className="sw" style={{ background: "rgba(46, 158, 99, 0.3)" }} />moins cher</span>
          <span><span className="sw" style={{ background: "rgba(232, 84, 47, 0.25)" }} />plus cher</span>
        </div>
      </section>

      {/* ---- 5 · distribution des prix ---- */}
      <section className="viz-card">
        <h2>Distribution des prix</h2>
        <p className="viz-sub">produits actifs par palier de prix</p>
        <div className="hbars">
          {m.price_distribution.map((b) => (
            <div className="hbar-row" key={b.range}>
              <span className="hbar-label">{b.range}</span>
              <span className="hbar-track">
                <span className="hbar-fill" style={{ width: `${(b.n / distMax) * 100}%` }} />
              </span>
              <span className="hbar-value">{fmt(b.n)}</span>
            </div>
          ))}
        </div>
      </section>

      {/* ---- 6 · baisses de prix (7 j) ---- */}
      <section className="viz-card">
        <h2>📉 Baisses de prix (7 jours)</h2>
        <p className="viz-sub">produits dont le prix relevé a diminué depuis la dernière synchronisation</p>
        {m.price_drops.length > 0 ? (
          <ul className="drops-list">
            {m.price_drops.slice(0, 20).map((dr, i) => (
              <li key={`${dr.uid}-${i}`}>
                <Link to={`/produit/${encodeURIComponent(dr.uid)}`}>
                  <SourceLogo source={dr.source} size={22} fallback="hide" />
                  <span className="drop-name">{dr.name}</span>
                  <span className="drop-prices">
                    <s>{fmt$(dr.old_price)}</s> → <b>{fmt$(dr.new_price)}</b>
                  </span>
                  <span className="drop-pct">−{dr.drop_pct.toLocaleString("fr-CA")} %</span>
                </Link>
              </li>
            ))}
          </ul>
        ) : (
          <p className="fine">
            Aucune baisse détectée encore — l'historique se construit à chaque synchronisation.
          </p>
        )}
      </section>

      {/* ---- aubaines & journal (depuis /api/stats) ---- */}
      {d.deals.length > 0 && (
        <section className="viz-card">
          <h2>Meilleures aubaines du moment 🔥</h2>
          <p className="viz-sub">rabais relatif le plus fort, toutes bannières confondues</p>
          <div className="grid deals-grid">
            {d.deals.slice(0, 12).map((p) => (
              <ProductCard key={p.uid} p={p} />
            ))}
          </div>
          <p className="stats-foot">
            <Link to="/aubaines">Voir toutes les aubaines →</Link>
          </p>
        </section>
      )}

      {d.recent_syncs.length > 0 && (
        <section className="viz-card">
          <h2>Dernières synchronisations</h2>
          <ul className="alertes">
            {d.recent_syncs.map((s) => (
              <li key={s.id}>
                {s.ok ? "✅" : "⚠️"} <b>{sourceName(s.source)}</b> — {fmtTs(s.ts)} ·{" "}
                {fmt(s.found)} produits trouvés, {fmt(s.added)} ajoutés,{" "}
                {fmt(s.updated)} mis à jour, {fmt(s.removed)} retirés
                {s.message ? ` — ${s.message}` : ""}
              </li>
            ))}
          </ul>
        </section>
      )}

      <p className="stats-foot">
        Données recalculées à chaque synchronisation. Les catégories et bannières
        renvoient vers les produits filtrés correspondants.{" "}
        <Link to="/sources">Voir le registre complet des sources →</Link>
      </p>
    </div>
  );
}
