// bingo.jsx — WWDC 2026 Keynote Bingo. Two presentational screens that read
// state + callbacks from App (like the other screens) and the prediction data
// from window.WWDC_BINGO:
//   • BingoScreen      — the 4×4 card; tap a square as Apple announces it.
//   • BingoLeaderboard — live "who called it" standings, ranking the outlets by
//                        how many of their predictions you've marked confirmed.
// The feature is only routed to when window.bingoLive() is true (keynote window
// or a localhost debug toggle), so nothing here ships to normal visitors off-day.

const BIcon = window.Icon;

// The 8 winning lines of a 4×4 grid, as index sets (rows, cols, two diagonals).
function bingoLines() {
  const lines = [];
  for (let r = 0; r < 4; r++) lines.push([0, 1, 2, 3].map((c) => r * 4 + c));
  for (let c = 0; c < 4; c++) lines.push([0, 1, 2, 3].map((r) => r * 4 + c));
  lines.push([0, 5, 10, 15]);
  lines.push([3, 6, 9, 12]);
  return lines;
}

// ============================================================ BINGO CARD
function BingoScreen({ marked, onToggle, onReset, onBoard, onBack }) {
  const squares = window.WWDC_BINGO.squares;
  const markedSet = new Set(marked);

  // Which cells sit on a completed line — those get highlighted, and any
  // completed line means BINGO.
  const winning = new Set();
  let hasBingo = false;
  bingoLines().forEach((line) => {
    if (line.every((i) => markedSet.has(squares[i].id))) {
      hasBingo = true;
      line.forEach((i) => winning.add(i));
    }
  });

  return (
    <div className="screen bingo">
      <div className="bloom" style={{ width: 340, height: 180, top: -50, left: 130, opacity: 0.45 }} />
      <div className="statusbar">
        <span className="label">WWDC 2026 Bingo</span>
        <span className="label">{markedSet.size}/{squares.length} called</span>
      </div>
      <div style={{ marginTop: 14 }}>
        <div className="kicker glow-text">{hasBingo ? "BINGO!" : "Keynote bingo"}</div>
        <div className="bingo-lede">Tap each prediction as Apple announces it. Line one up for a win.</div>
      </div>

      {hasBingo && <div className="bingo-win">★ BINGO — you called the line ★</div>}

      <div className="bingo-grid">
        {squares.map((sq, i) => {
          const on = markedSet.has(sq.id);
          return (
            <div key={sq.id}
              className={"bcard focusable" + (on ? " marked" : "") + (winning.has(i) ? " in-line" : "")}
              data-focus onClick={() => onToggle(sq.id)}>
              {on && <div className="bcard-check"><BIcon name="check" size={13} /></div>}
              <div className="bcard-text">{sq.text}</div>
              <div className="bcard-src">{sq.src}</div>
            </div>
          );
        })}
      </div>

      <div className="home-foot" style={{ marginTop: 4 }}>
        <button className="btn focusable" data-focus onClick={onBoard}>
          <BIcon name="star" /> Leaderboard
        </button>
        <button className="btn focusable" data-focus onClick={onReset}>Reset card</button>
        <button className="btn focusable" data-focus data-autofocus data-back onClick={onBack}>
          <BIcon name="back" /> Trail
        </button>
      </div>
    </div>
  );
}

// ============================================================ LEADERBOARD
// Ranks the outlets by how many of their predictions you've marked confirmed —
// a live "who called it" scoreboard. Recomputes from `marked` on every render.
function BingoLeaderboard({ marked, onBack }) {
  const squares = window.WWDC_BINGO.squares;
  const markedSet = new Set(marked);

  // Tally per source: total predictions + how many are confirmed (marked).
  const bySrc = {};
  squares.forEach((sq) => {
    const t = bySrc[sq.src] || (bySrc[sq.src] = { src: sq.src, total: 0, hit: 0 });
    t.total += 1;
    if (markedSet.has(sq.id)) t.hit += 1;
  });
  const rows = Object.values(bySrc).sort((a, b) =>
    b.hit - a.hit || (b.hit / b.total) - (a.hit / a.total) || a.src.localeCompare(b.src));

  const anyCalled = rows.some((r) => r.hit > 0);
  const leader = rows[0] ? rows[0].hit : 0;

  return (
    <div className="screen leaderboard" data-back-on-left>
      <div className="bloom" style={{ width: 340, height: 180, top: -50, left: 130, opacity: 0.45 }} />
      <div className="statusbar">
        <span className="label">Who called it?</span>
        <span className="label">{markedSet.size}/{squares.length} called</span>
      </div>
      <div style={{ marginTop: 14 }}>
        <div className="kicker glow-text">Source leaderboard</div>
        <div className="bingo-lede">
          {anyCalled
            ? "Outlets ranked by predictions Apple confirmed in the keynote."
            : "No predictions confirmed yet — tap squares on the card to score the sources."}
        </div>
      </div>

      <div className="lb-list focusable" data-focus data-autofocus data-scroll>
        {rows.map((r, i) => {
          const top = anyCalled && r.hit === leader;
          const pct = Math.round((r.hit / r.total) * 100);
          return (
            <div key={r.src} className={"lb-row" + (top ? " top" : "")}>
              <div className="lb-rank">{top ? "🏆" : i + 1}</div>
              <div className="lb-main">
                <div className="lb-head">
                  <span className="lb-src">{r.src}</span>
                  <span className="lb-score">{r.hit}/{r.total} called</span>
                </div>
                <div className="lb-bar"><div className="lb-fill" style={{ width: pct + "%" }} /></div>
              </div>
            </div>
          );
        })}
      </div>

      <div className="bingo-note">{window.WWDC_BINGO.note}</div>

      <div className="home-foot" style={{ marginTop: 4 }}>
        <button className="btn focusable" data-focus data-back onClick={onBack}>
          <BIcon name="back" /> Back to card
        </button>
      </div>
    </div>
  );
}

window.BingoScreen = BingoScreen;
window.BingoLeaderboard = BingoLeaderboard;
