/* ============================================================
   BountyBoard — total revamp of the "Most Wanted" leaderboard.

   A real-time intel surface, not a data table.
   - BOLO live ticker: new wanted notices scroll across the top.
   - Aggregate heat dial (conic gradient) + pool totals.
   - Per-row: rank delta arrow, mug-shot, alias, bounty bar (animated),
     holdings sparkline (canvas), heat stars, last-seen.
   - Click row → expanding dossier with bigger poster + bigger sparkline.
   - Scroll-driven reveal via view-timeline (compositor thread).
   - #1 row has a registered @property conic-gradient aura.
   ============================================================ */

const {
  useState: useS_bb,
  useEffect: useE_bb,
  useMemo: useM_bb,
  useRef: useR_bb,
  useLayoutEffect: useL_bb,
} = React;

/* ---------- deterministic PRNG so mock data is stable across renders ---------- */
function rngFor(seed) {
  let s = 0;
  for (let i = 0; i < seed.length; i++) s = (s * 31 + seed.charCodeAt(i)) | 0;
  return () => {
    s = (s * 1664525 + 1013904223) | 0;
    return ((s >>> 0) % 100000) / 100000;
  };
}

/* ---------- sparkline canvas ---------- */
function Sparkline({ seed, w = 96, h = 28, accent = "var(--vc-cyan)", trend = 0 }) {
  const ref = useR_bb(null);
  const data = useM_bb(() => {
    const r = rngFor(seed);
    let v = 0.5;
    const arr = [];
    for (let i = 0; i < 24; i++) {
      // trend nudges the random walk
      v = Math.max(0.05, Math.min(0.98, v + (r() - 0.5) * 0.22 + trend * 0.012));
      arr.push(v);
    }
    return arr;
  }, [seed, trend]);

  useE_bb(() => {
    const c = ref.current;
    if (!c) return;
    const dpr = Math.min(2, window.devicePixelRatio || 1);
    c.width = w * dpr;
    c.height = h * dpr;
    const ctx = c.getContext("2d");
    ctx.scale(dpr, dpr);
    ctx.clearRect(0, 0, w, h);

    // grid baseline
    ctx.strokeStyle = "rgba(255,245,251,0.06)";
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(0, h - 0.5); ctx.lineTo(w, h - 0.5);
    ctx.stroke();

    // gradient fill below
    const grad = ctx.createLinearGradient(0, 0, 0, h);
    const accentRGB = accent.includes("pink") ? "255,58,163" : "70,229,229";
    grad.addColorStop(0, `rgba(${accentRGB}, 0.42)`);
    grad.addColorStop(1, `rgba(${accentRGB}, 0)`);

    const pts = data.map((v, i) => [(i / (data.length - 1)) * w, h - 4 - v * (h - 8)]);

    // smooth quadratic path
    ctx.beginPath();
    ctx.moveTo(pts[0][0], h);
    ctx.lineTo(pts[0][0], pts[0][1]);
    for (let i = 1; i < pts.length - 1; i++) {
      const xc = (pts[i][0] + pts[i + 1][0]) / 2;
      const yc = (pts[i][1] + pts[i + 1][1]) / 2;
      ctx.quadraticCurveTo(pts[i][0], pts[i][1], xc, yc);
    }
    ctx.lineTo(pts[pts.length - 1][0], pts[pts.length - 1][1]);
    ctx.lineTo(w, h);
    ctx.closePath();
    ctx.fillStyle = grad;
    ctx.fill();

    // line on top
    ctx.beginPath();
    ctx.moveTo(pts[0][0], pts[0][1]);
    for (let i = 1; i < pts.length - 1; i++) {
      const xc = (pts[i][0] + pts[i + 1][0]) / 2;
      const yc = (pts[i][1] + pts[i + 1][1]) / 2;
      ctx.quadraticCurveTo(pts[i][0], pts[i][1], xc, yc);
    }
    ctx.lineTo(pts[pts.length - 1][0], pts[pts.length - 1][1]);
    ctx.strokeStyle = `rgba(${accentRGB}, 0.95)`;
    ctx.lineWidth = 1.4;
    ctx.shadowColor = `rgba(${accentRGB}, 0.7)`;
    ctx.shadowBlur = 6;
    ctx.stroke();
    ctx.shadowBlur = 0;

    // last point dot
    const last = pts[pts.length - 1];
    ctx.beginPath();
    ctx.arc(last[0], last[1], 2.2, 0, Math.PI * 2);
    ctx.fillStyle = "#fff";
    ctx.fill();
    ctx.strokeStyle = `rgba(${accentRGB}, 1)`;
    ctx.lineWidth = 1.2;
    ctx.stroke();
  }, [data, w, h, accent]);

  return <canvas ref={ref} className="bb-spark" style={{ width: w, height: h }} />;
}

/* ---------- pixel mug shot (halftone) ---------- */
function MugShot({ seed, size = 56 }) {
  const grid = useM_bb(() => {
    const r = rngFor("mug-" + seed);
    const cells = [];
    const n = 9;
    for (let y = 0; y < n; y++) {
      for (let x = 0; x < n; x++) {
        // symmetric on x to make a "face"
        const xx = x < n / 2 ? x : (n - 1 - x);
        const k = `${xx},${y}`;
        if (!cells[k]) {
          // face cluster bias
          const center = Math.hypot(xx - n / 2, y - n / 2);
          const p = r();
          cells[k] = p > 0.4 + center * 0.05 ? 1 : 0;
        }
        cells[`${x},${y}`] = cells[`${xx},${y}`];
      }
    }
    return cells;
  }, [seed]);
  const n = 9;
  const cell = size / n;
  return (
    <div className="bb-mug" style={{ width: size, height: size }}>
      {Array.from({ length: n * n }, (_, i) => {
        const x = i % n, y = (i / n) | 0;
        const on = grid[`${x},${y}`];
        return (
          <span
            key={i}
            style={{
              left: x * cell, top: y * cell, width: cell, height: cell,
              background: on ? "currentColor" : "transparent",
            }}
          />
        );
      })}
    </div>
  );
}

/* ---------- rank delta ---------- */
function RankDelta({ delta }) {
  if (delta === 0) return <span className="bb-delta same">—</span>;
  if (delta > 0) return <span className="bb-delta up">▲<i>{delta}</i></span>;
  return <span className="bb-delta dn">▼<i>{-delta}</i></span>;
}

/* ---------- BOLO ticker — live stream of new wanted notices ---------- */
function BoloTicker({ liveBolos, fallbackRows, crimePool, aliases }) {
  const stream = useM_bb(() => {
    if (liveBolos && liveBolos.length >= 6) {
      // newest first → reverse + cap so the scroll reads left-to-right with newest on left
      return liveBolos.slice(0, 24).map(b => ({
        alias: b.alias,
        crime: b.crime,
        sec: Math.max(1, Math.round((Date.now() - b.ts) / 1000)),
        kind: b.kind,
      }));
    }
    const r = rngFor("bolo");
    const out = [];
    for (let i = 0; i < 24; i++) {
      const alias = aliases[Math.floor(r() * aliases.length)];
      const crime = crimePool[Math.floor(r() * crimePool.length)]
        .replace("%X%", (Math.floor(r() * 9 + 1) + "." + Math.floor(r() * 9) + "M"));
      const sec = Math.floor(r() * 59 + 1);
      out.push({ alias, crime, sec });
    }
    return out;
  }, [liveBolos, fallbackRows, crimePool, aliases]);

  return (
    <div className="bb-bolo">
      <div className="bb-bolo-label">
        <span className="lt">▸ BOLO · LIVE FEED</span>
        <span className="dot" />
      </div>
      <div className="bb-bolo-track">
        {[0, 1].map(rep => (
          <React.Fragment key={rep}>
            {stream.map((s, i) => (
              <span key={rep + ":" + i} className={`bb-bolo-pip ${s.kind === "claim" ? "claim" : ""}`}>
                <b>{s.alias}</b>
                <span className="bb-bolo-sep">·</span>
                <span className="bb-bolo-crime">{s.crime}</span>
                <span className="bb-bolo-sep">·</span>
                <span className="bb-bolo-time">{s.sec}s ago</span>
              </span>
            ))}
          </React.Fragment>
        ))}
      </div>
    </div>
  );
}

/* ---------- heat dial — aggregate ---------- */
function HeatDial({ rows }) {
  const totalHeat = rows.reduce((a, r) => a + r.stars, 0);
  const max = rows.length * 5;
  const pct = totalHeat / max;
  return (
    <div className="bb-dial" style={{ "--p": pct }}>
      <div className="bb-dial-ring" />
      <div className="bb-dial-mask" />
      <div className="bb-dial-text">
        <div className="bb-dial-num">{Math.round(pct * 100)}<i>%</i></div>
        <div className="bb-dial-lbl">heat index</div>
      </div>
    </div>
  );
}

/* ---------- main BountyBoard ---------- */
function BountyBoard({ rows: rawRows }) {
  const data = window.GCA_DATA;
  const [sort, setSort] = useS_bb("bounty");        // bounty | holdings | heat | recent
  const [crewFilter, setCrew] = useS_bb("ALL");     // ALL | 🇧🇷 | ...
  const [expanded, setExpanded] = useS_bb(null);    // rank

  /* Live engine drives rank deltas + bolo stream + spark seeds */
  const live = window.useLive
    ? window.useLive(s => ({
        tick: s.tick,
        rankDeltas: s.rankDeltas,
        rowDrift: s.rowDrift,
        sparkSeed: s.sparkSeed,
        bolos: s.bolos,
      }))
    : { tick: 0, rankDeltas: {}, rowDrift: {}, sparkSeed: {}, bolos: [] };

  /* augment rows with derived data: delta, numeric bounty, numeric holdings */
  const augmented = useM_bb(() => {
    return rawRows.map((r, i) => {
      const rr = rngFor("aug-" + r.rank);
      const bountyN = parseFloat(r.bounty) || 0;
      const holdingsN = parseFloat(r.holdings) * (r.holdings.includes("M") ? 1e6 : 1e3);
      const fallbackDelta = Math.round((rr() - 0.5) * 6);
      const delta = (r.rank in live.rankDeltas) ? live.rankDeltas[r.rank] : fallbackDelta;
      const drift = live.rowDrift[r.rank] || 0;
      const liveBounty = Math.max(1, bountyN + drift);
      return {
        ...r,
        bountyN,
        liveBounty,
        holdingsN,
        delta,
        trend: delta,
        sparkSeedBump: live.sparkSeed[r.rank] || 0,
      };
    });
  }, [rawRows, live.rankDeltas, live.rowDrift, live.sparkSeed]);

  const filtered = useM_bb(() => {
    let a = augmented;
    if (crewFilter !== "ALL") a = a.filter(r => r.crew === crewFilter);
    a = [...a].sort((x, y) => {
      if (sort === "bounty")   return y.liveBounty - x.liveBounty;
      if (sort === "holdings") return y.holdingsN - x.holdingsN;
      if (sort === "heat")     return y.stars - x.stars;
      if (sort === "recent")   return x.rank - y.rank; // proxy
      return 0;
    });
    return a;
  }, [augmented, sort, crewFilter]);

  const maxBounty = Math.max(...filtered.map(r => r.liveBounty), 1);
  const totalBountyPool = augmented.reduce((a, r) => a + r.liveBounty, 0);
  const totalHoldings = augmented.reduce((a, r) => a + r.holdingsN, 0);

  const crews = useM_bb(() => {
    const seen = new Set();
    rawRows.forEach(r => seen.add(r.crew));
    return Array.from(seen);
  }, [rawRows]);

  return (
    <div className="bb-wrap" data-reveal>
      {/* ───────── HEAD STRIP ───────── */}
      <div className="bb-head">
        <BoloTicker
          liveBolos={live.bolos}
          fallbackRows={rawRows}
          crimePool={data.crimePool}
          aliases={data.aliases}
        />

        <div className="bb-meta">
          <div className="bb-meta-cell">
            <div className="k">★ BOUNTY POOL</div>
            <div className="v gold">◎ <NumberTicker value={Math.round(totalBountyPool)} /></div>
          </div>
          <div className="bb-meta-cell">
            <div className="k">▸ TOTAL HOLDINGS</div>
            <div className="v cyan">
              <NumberTicker value={Math.round(totalHoldings / 1e6 * 10) / 10} decimals={1} />M
            </div>
          </div>
          <div className="bb-meta-cell">
            <div className="k">● ACTIVE SUSPECTS</div>
            <div className="v pink">{rawRows.length}<i> / ∞</i></div>
          </div>
          <HeatDial rows={rawRows} />
        </div>
      </div>

      {/* ───────── CONTROLS ───────── */}
      <div className="bb-controls">
        <div className="bb-sort">
          <span className="bb-cap">SORT</span>
          {[
            ["bounty", "bounty ◎"],
            ["holdings", "holdings"],
            ["heat", "heat ★"],
            ["recent", "rank #"],
          ].map(([k, v]) => (
            <button
              key={k}
              className={`bb-chip ${sort === k ? "on" : ""}`}
              onClick={() => {
                if (window.withViewTransition) window.withViewTransition(() => setSort(k), "bb-sort");
                else setSort(k);
              }}
            >
              {v}
            </button>
          ))}
        </div>
        <div className="bb-filter">
          <span className="bb-cap">CREW</span>
          <button
            className={`bb-chip ${crewFilter === "ALL" ? "on" : ""}`}
            onClick={() => setCrew("ALL")}
          >all</button>
          {crews.map(c => (
            <button
              key={c}
              className={`bb-chip bb-chip-crew ${crewFilter === c ? "on" : ""}`}
              onClick={() => setCrew(c === crewFilter ? "ALL" : c)}
            >
              {c}
            </button>
          ))}
        </div>
      </div>

      {/* ───────── COLUMN HEADER ───────── */}
      <div className="bb-colhead">
        <div>RANK · Δ24H</div>
        <div>SUSPECT</div>
        <div className="bb-th-hold">HOLDINGS · 24H ACTIVITY</div>
        <div>BOUNTY ★ ESTIMATE</div>
        <div className="hide-mob">HEAT</div>
        <div className="hide-mob">LAST SEEN</div>
      </div>

      {/* ───────── ROWS ───────── */}
      <div className="bb-rows">
        {filtered.map((r, i) => {
          const widthPct = (r.liveBounty / maxBounty) * 100;
          const isOpen = expanded === r.rank;
          return (
            <div
              key={r.rank}
              className={`bb-row ${r.rank === 1 ? "fugitive" : ""} ${isOpen ? "open" : ""}`}
              style={{
                "--i": i,
                "--bar": `${widthPct}%`,
                "--accent": r.rank === 1 ? "var(--vc-cyan)" : "var(--vc-pink)",
                viewTransitionName: isOpen ? `bb-row-${r.rank}` : undefined,
              }}
              onClick={() => {
                const next = isOpen ? null : r.rank;
                if (window.withViewTransition) window.withViewTransition(() => setExpanded(next), "bb-dossier");
                else setExpanded(next);
              }}
            >
              {/* rank + delta */}
              <div className="bb-cell bb-rank-cell">
                <div className={`bb-rank ${r.rank === 1 ? "gold" : ""}`}>
                  #{String(r.rank).padStart(2, "0")}
                </div>
                <RankDelta delta={r.delta} />
                {r.rank === 1 && <div className="bb-fugitive-tag">★ FUGITIVE</div>}
              </div>

              {/* suspect */}
              <div className="bb-cell bb-suspect">
                <div className="bb-mug-wrap" style={{ color: r.rank === 1 ? "var(--vc-cyan)" : "var(--vc-pink)" }}>
                  <MugShot seed={r.alias} size={52} />
                  <div className="bb-mug-stamp">{r.crew}</div>
                </div>
                <div className="bb-id">
                  <div className="bb-alias">{r.alias.toLowerCase().replace(/_/g, " ")}</div>
                  <div className="bb-aka mono">aka {r.aka}</div>
                </div>
              </div>

              {/* holdings + sparkline */}
              <div className="bb-cell bb-holdings">
                <div className="bb-h-val mono">
                  {r.holdings}
                  <span className="bb-h-unit">$GCA</span>
                </div>
                <Sparkline
                  seed={"hold-" + r.rank}
                  trend={r.delta}
                  w={130} h={28}
                  accent={r.rank === 1 ? "cyan" : "pink"}
                />
              </div>

              {/* bounty bar */}
              <div className="bb-cell bb-bounty">
                <div className="bb-bar-track">
                  <div className="bb-bar-fill" />
                  <div className="bb-bar-glint" />
                </div>
                <div className="bb-bounty-num mono">
                  ◎ <NumberTicker value={Math.round(r.liveBounty)} /> SOL
                </div>
              </div>

              {/* heat */}
              <div className="bb-cell bb-heat hide-mob">
                {Array.from({ length: 5 }, (_, j) => (
                  <span key={j} className={`bb-star ${j < r.stars ? "on" : ""}`}>★</span>
                ))}
              </div>

              {/* last seen */}
              <div className="bb-cell bb-last hide-mob mono">
                <span className="bb-pin" />
                {r.last}
              </div>

              {/* expanded dossier */}
              {isOpen && (
                <div className="bb-dossier" onClick={(e) => e.stopPropagation()}>
                  <div className="bb-dossier-left">
                    <div className="bb-dossier-poster">
                      <div className="bb-poster-stamp">▸ wanted · {r.crew}</div>
                      <MugShot seed={r.alias} size={148} />
                      <div className="bb-poster-name">
                        {r.alias.toLowerCase().replace(/_/g, " ")}
                      </div>
                      <div className="bb-poster-bounty">
                        ◎ {Math.round(r.liveBounty)} sol
                      </div>
                    </div>
                  </div>

                  <div className="bb-dossier-main">
                    <div className="bb-dossier-eyebrow">
                      ▸ FILE #{String(r.rank).padStart(4, "0")} · DOSSIER
                    </div>
                    <div className="bb-dossier-title">
                      operation · {r.alias.toLowerCase().split("_")[0]}
                    </div>
                    <div className="bb-dossier-aka mono">aka {r.aka} · last seen {r.last}</div>

                    <div className="bb-dossier-stats">
                      <div className="dd-stat">
                        <div className="dd-k">HOLDINGS</div>
                        <div className="dd-v">{r.holdings}</div>
                      </div>
                      <div className="dd-stat">
                        <div className="dd-k">BOUNTY</div>
                        <div className="dd-v gold">◎ {Math.round(r.liveBounty)}</div>
                      </div>
                      <div className="dd-stat">
                        <div className="dd-k">HEAT</div>
                        <div className="dd-v pink">
                          {Array.from({ length: 5 }, (_, j) =>
                            <span key={j} style={{ opacity: j < r.stars ? 1 : 0.18 }}>★</span>)}
                        </div>
                      </div>
                      <div className="dd-stat">
                        <div className="dd-k">Δ 24H</div>
                        <div className={`dd-v ${r.delta > 0 ? "go" : r.delta < 0 ? "alert" : ""}`}>
                          {r.delta > 0 ? "▲ +" : r.delta < 0 ? "▼ -" : "— "}{Math.abs(r.delta)} ranks
                        </div>
                      </div>
                      <div className="dd-stat">
                        <div className="dd-k">CREW</div>
                        <div className="dd-v">{r.crew}</div>
                      </div>
                      <div className="dd-stat">
                        <div className="dd-k">STATUS</div>
                        <div className="dd-v alert">○ AT LARGE</div>
                      </div>
                    </div>

                    <div className="bb-dossier-spark">
                      <div className="dd-spark-lbl">▸ 24-HOUR ACTIVITY</div>
                      <Sparkline
                        seed={"big-" + r.rank}
                        trend={r.delta}
                        w={420} h={70}
                        accent={r.rank === 1 ? "cyan" : "pink"}
                      />
                    </div>

                    <div className="bb-dossier-cta">
                      <button className="btn-sunset">▸ issue bounty (◎ 1 sol)</button>
                      <button className="btn-ghost">view on solscan</button>
                      <button
                        className="btn-ghost bb-close"
                        onClick={(e) => { e.stopPropagation(); setExpanded(null); }}
                      >× close file</button>
                    </div>

                    {/* Claude-powered alias forge */}
                    {typeof window.AliasForge === "function" && (
                      <div className="bb-dossier-forge">
                        <div className="dd-spark-lbl">▸ FORGE NEW ALIAS · ai dispatcher</div>
                        <window.AliasForge defaultInput={r.aka} />
                      </div>
                    )}
                  </div>
                </div>
              )}
            </div>
          );
        })}
      </div>

      {/* footer note */}
      <div className="bb-foot">
        <div className="bb-foot-l mono">
          <span className="bb-foot-dot" /> stream &middot; sync &middot; gca/01 · last updated 04s ago
        </div>
        <div className="bb-foot-r mono">
          showing {filtered.length} of {rawRows.length} · pool ◎ {Math.round(totalBountyPool)} sol
        </div>
      </div>
    </div>
  );
}

const BOUNTY_CARTELS = [
  { name: "Vice Kings", token: "$VICE", color: "#ff3aa3", status: "Pump.fun GO contracts loading", logo: "assets/cartels/vice-kings.png" },
  { name: "Jade Triad", token: "$JADE", color: "#46e5e5", status: "Pump.fun GO contracts loading", logo: "assets/cartels/jade-triad.png" },
  { name: "Los Muertos", token: "$MUERTOS", color: "#ff735c", status: "Pump.fun GO contracts loading", logo: "assets/cartels/los-muertos.png" },
  { name: "Mamba Syndicate", token: "$MAMBA", color: "#5be684", status: "Pump.fun GO contracts loading", logo: "assets/cartels/mamba-syndicate.png" },
  { name: "Bratva", token: "$BRATVA", color: "#ffd23a", status: "Pump.fun GO contracts loading", logo: "assets/cartels/bratva.png" },
];

function BountyBoardLoading() {
  return (
    <div className="bb-load" data-reveal>
      <div className="bb-load-top">
        <div>
          <div className="bb-load-kicker">waiting for first live world cup match</div>
          <h3>Bounty Board</h3>
          <p>
            Five cartel bounty boards connect to Pump.fun GO when live missions open.
            Cartel fees load each family pot while $GCA stays the boss token fed by the full system.
          </p>
        </div>
        <div className="bb-load-status">
          <span className="bb-load-dot" />
          Mission loading
        </div>
      </div>

      <div className="bb-load-screen" aria-label="Bounty Board loading">
        <div className="bb-load-feature">
          <div className="bb-card-rank">$GCA</div>
          <div className="bb-card-heat">boss feed</div>
          <div className="bb-card-stamp">standby</div>
          <div className="bb-feature-media">
            <img className="bb-feature-logo" src="assets/main-logo.png" alt="Grand Cup Auto" loading="lazy" />
          </div>
          <div className="bb-feature-copy">
            <h4>$GCA boss desk</h4>
            <div className="bb-feature-grid">
              <span>main token</span><b>$GCA</b>
              <span>cartel feeds</span><b>5</b>
              <span>claim rule</span><b>hold gate</b>
              <span>live bounties</span><b>-</b>
            </div>
            <p>Every cartel board points back to the boss: burn pressure, holder-gated claims, and bounty-driven reach.</p>
          </div>
        </div>

        <div className="bb-load-cartels">
          {BOUNTY_CARTELS.map((cartel, i) => (
            <div
              key={cartel.name}
              className="bb-load-cartel"
              style={{ "--cartel-color": cartel.color, "--i": i }}
            >
              <div className="bb-card-rank">{String(i + 1).padStart(2, "0")}</div>
              <div className="bb-card-heat">cartel pot</div>
              <div className="bb-card-stamp">loading</div>
              <div className="bb-card-media">
                <img className="bb-card-logo" src={cartel.logo} alt="" loading="lazy" />
              </div>
              <div className="bb-cartel-head">
                <span>{cartel.name}</span>
                <b>{cartel.token}</b>
              </div>
              <div className="bb-cartel-bar">
                <span />
              </div>
              <div className="bb-cartel-foot">
                <span>bounty pot: -</span>
                <span>{cartel.status}</span>
              </div>
            </div>
          ))}
        </div>
      </div>

      <div className="bb-load-bottom">
        <div className="bb-load-metric">
          <span>Active bounties</span>
          <b>-</b>
        </div>
        <div className="bb-load-metric">
          <span>Cartel boards</span>
          <b>{BOUNTY_CARTELS.length}</b>
        </div>
        <div className="bb-load-metric">
          <span>Main token</span>
          <b>$GCA</b>
        </div>
        <div className="bb-load-metric">
          <span>Status</span>
          <b>Standby</b>
        </div>
      </div>
    </div>
  );
}

window.BountyBoard = BountyBoardLoading;
