/* organizer-monitor-techday.jsx — Tech-Day variant of OrgMonitorPage
 * Renders agenda, speakers/decks, leaderboard, engagement metrics
 * Branched from OrgMonitorPage when event_type === 'tech-day'
 */

// Inline phase badge (PhaseBadge in organizer-pages.jsx is not on window; modules are isolated)
function TDPhaseBadge(props) {
  var phase = props.phase || 'registration';
  var label = phase.charAt(0).toUpperCase() + phase.slice(1);
  var color = phase === 'playing' ? 'var(--ok)' : (phase === 'draft' ? 'var(--wn)' : 'var(--brand)');
  var bg = phase === 'playing' ? 'var(--ok-soft)' : (phase === 'draft' ? 'var(--wn-soft)' : 'var(--brand-soft)');
  return React.createElement('span', {
    style: {
      fontFamily: 'var(--f-m)', fontSize: '10px', letterSpacing: '.1em',
      textTransform: 'uppercase', fontWeight: 600,
      padding: '3px 9px', borderRadius: 'var(--r-p)',
      background: bg, color: color, border: '1px solid ' + color,
    }
  }, label);
}

window.OrgMonitorTechDay = function OrgMonitorTechDay(props) {
  var gameId = props.gameId;
  var detail = props.detail || {};
  var onSelectGame = props.onSelectGame || function() {};
  var showToast = props.showToast || function() {};
  var onRefresh = props.onRefresh || function() {};

  var game = detail.game || {};
  var leaderboard = detail.leaderboard || [];
  var players = detail.players || [];
  var phase = detail.phase || game.current_phase || 'registration';
  var eventId = game.event_id || '';
  var displayCode = game.join_code || gameId;

  var _ev = React.useState(null);          var eventData = _ev[0]; var setEventData = _ev[1];
  var _sp = React.useState([]);            var speakers = _sp[0]; var setSpeakers = _sp[1];
  var _ag = React.useState([]);            var agenda = _ag[0]; var setAgenda = _ag[1];
  var _qs = React.useState([]);            var questions = _qs[0]; var setQuestions = _qs[1];
  var _ld = React.useState(true);          var loading = _ld[0]; var setLoading = _ld[1];
  var _td = React.useState(null);          var tdState = _td[0]; var setTdState = _td[1];
  var _nw = React.useState(Date.now()/1000); var nowTs = _nw[0]; var setNowTs = _nw[1];
  var _bz = React.useState(false);         var busy = _bz[0]; var setBusy = _bz[1];
  var _tp1 = React.useState(10);           var testPlayerCount = _tp1[0]; var setTestPlayerCount = _tp1[1];
  var _tp2 = React.useState(false);        var generatingPlayers = _tp2[0]; var setGeneratingPlayers = _tp2[1];
  // Per-agenda counts for "Open questions" — {agenda_id: {n_tech, n_theme}}
  var _qc = React.useState({});            var qCounts = _qc[0]; var setQCounts = _qc[1];
  function getQCount(agendaId, key, dflt) {
    var rec = qCounts[agendaId] || {};
    var v = rec[key];
    return (v == null || v === '') ? dflt : v;
  }
  function setQCount(agendaId, key, val) {
    setQCounts(function(prev) {
      var next = Object.assign({}, prev);
      var rec = Object.assign({}, next[agendaId] || {});
      rec[key] = val;
      next[agendaId] = rec;
      return next;
    });
  }

  /* ── Test player helpers (admin/dev tool) ── */
  function handleGenerateTestPlayers() {
    setGeneratingPlayers(true);
    AdminApi.generateTestPlayers(gameId, testPlayerCount)
      .then(function(res) {
        var cnt = (res && res.count) || testPlayerCount;
        showToast(cnt + ' test players created', 'ok');
        setGeneratingPlayers(false);
        onRefresh();
      })
      .catch(function(err) {
        showToast('Failed: ' + ((err && err.message) || err), 'err');
        setGeneratingPlayers(false);
      });
  }
  function handleResetPlayers() {
    if (!window.confirm('Delete ALL players from this game? This cannot be undone.')) return;
    AdminApi.resetPlayers(gameId)
      .then(function() { showToast('All players deleted', 'ok'); onRefresh(); })
      .catch(function(err) { showToast('Failed: ' + ((err && err.message) || err), 'err'); });
  }
  function handleResetGame() {
    if (!window.confirm('FULL RESET of game ' + gameId + '?\n\nThis deletes:\n  • All players & scores\n  • All tech-day quiz answers\n  • Active talk / questions-open state\n  • Draft state, modules, custom codes\n\nGame phase resets to "registration". Cannot be undone.')) return;
    AdminApi.resetGame(gameId)
      .then(function() { showToast('Game fully reset', 'ok'); onRefresh(); })
      .catch(function(err) { showToast('Reset failed: ' + ((err && err.message) || err), 'err'); });
  }

  /* ── Fetch tech-day specific data ── */
  React.useEffect(function() {
    if (!eventId) { setLoading(false); return; }
    function refresh() {
      Promise.all([
        AdminApi.getEvent(eventId).catch(function() { return null; }),
        AdminApi.listEventSpeakers(eventId).catch(function() { return []; }),
        AdminApi.listEventAgenda(eventId).catch(function() { return []; }),
        AdminApi.listEventQuestions(eventId).catch(function() { return []; }),
      ]).then(function(r) {
        if (r[0]) setEventData(r[0]);
        setSpeakers(Array.isArray(r[1]) ? r[1] : []);
        setAgenda(Array.isArray(r[2]) ? r[2] : []);
        setQuestions(Array.isArray(r[3]) ? r[3] : []);
        setLoading(false);
      });
    }
    refresh();
    var t = setInterval(refresh, 15000);
    return function() { clearInterval(t); };
  }, [eventId]);

  /* ── Poll tech-day flow state every 3s ── */
  React.useEffect(function() {
    if (!gameId) return;
    function pollState() {
      AdminApi.techDayGetState(gameId).then(setTdState).catch(function() {});
    }
    pollState();
    var t = setInterval(pollState, 3000);
    var clk = setInterval(function() { setNowTs(Date.now() / 1000); }, 1000);
    return function() { clearInterval(t); clearInterval(clk); };
  }, [gameId]);

  /* ── Action handlers ── */
  function withBusy(promise, successMsg) {
    setBusy(true);
    return promise
      .then(function(res) {
        if (res && res.game_phase !== undefined) setTdState(res);
        if (successMsg) showToast(successMsg, 'ok');
        return res;
      })
      .catch(function(err) {
        var msg = (err && err.message) || 'Action failed';
        showToast(msg, 'err');
        throw err;
      })
      .finally(function() { setBusy(false); });
  }

  function handleSetActive(agendaId) {
    return withBusy(AdminApi.techDaySetActiveTalk(gameId, agendaId), 'Active talk updated');
  }
  function handleOpenQuestions(agendaId, opts) {
    return withBusy(AdminApi.techDayOpenQuestions(gameId, agendaId, opts || {}), 'Questions opened');
  }
  function handleCloseQuestions() {
    return withBusy(AdminApi.techDayCloseQuestions(gameId), 'Questions closed');
  }
  function handleStartDraft() {
    if (!confirm('Start draft? Requires at least 2 captains pre-assigned.')) return;
    setBusy(true);
    AdminApi.startDraft(gameId)
      .then(function() { showToast('Draft started', 'ok'); })
      .catch(function(err) { showToast((err && err.message) || 'Could not start draft', 'err'); })
      .finally(function() { setBusy(false); });
  }
  function handleResetDraft() {
    if (!confirm('Restart draft? This clears all team assignments (keeps captains) and re-runs the snake draft from round 1.')) return;
    setBusy(true);
    AdminApi.resetDraft(gameId)
      .then(function() { showToast('Draft reset — ready to restart', 'ok'); onRefresh(); })
      .catch(function(err) { showToast((err && err.message) || 'Could not reset draft', 'err'); })
      .finally(function() { setBusy(false); });
  }
  function handleBeginEvent() {
    if (!confirm('Begin event? This flips the game to playing phase and auto-assigns any remaining players.')) return;
    setBusy(true);
    AdminApi.setGamePhase(gameId, 'playing')
      .then(function() { showToast('Event started', 'ok'); })
      .catch(function(err) { showToast((err && err.message) || 'Could not begin event', 'err'); })
      .finally(function() { setBusy(false); });
  }

  /* ── Derived metrics ── */
  var speakerById = {};
  speakers.forEach(function(s) { speakerById[s.speaker_id] = s; });

  // Normalize agenda items: speaker_ids is the array; older entries may have speaker_id
  function agendaSpeakerIds(item) {
    if (Array.isArray(item.speaker_ids) && item.speaker_ids.length) return item.speaker_ids;
    if (item.speaker_id) return [item.speaker_id];
    return [];
  }

  var questionsByAgenda = {};
  questions.forEach(function(q) {
    var aid = q.agenda_id || '_unassigned';
    if (!questionsByAgenda[aid]) questionsByAgenda[aid] = [];
    questionsByAgenda[aid].push(q);
  });

  var totalQuestions = questions.length;
  var aiQuestions = questions.filter(function(q) { return q.source === 'ai'; }).length;
  var manualQuestions = totalQuestions - aiQuestions;
  var nonProctorPlayers = players.filter(function(p) { return !p.isProctor; });

  /* ── Sorted leaderboard ── */
  var sortedLb = leaderboard.slice().sort(function(a, b) {
    return (b.score || b.total_score || 0) - (a.score || a.total_score || 0);
  });

  /* ── Derived flow data ── */
  // NOTE: API returns isCaptain/isProctor (camelCase). p.is_captain would always be undefined.
  var captains = players.filter(function(p) { return p.isCaptain && !p.isProctor; });
  var nonCaptainPlayers = players.filter(function(p) { return !p.isCaptain && !p.isProctor; });
  var captainByTeam = {};
  captains.forEach(function(p) { if (p.team) captainByTeam[p.team] = p; });

  // Resolve theme teams (mirrors organizer-pages.jsx: DB stores 'world-cup' etc., data.js uses 'cup')
  var THEME_REVERSE_MAP = { 'f1': 'gp', 'world-cup': 'cup', 'nfl': 'nfl', 'realm': 'realm' };
  var rawThemeId = (game.theme_id || game.theme || 'cisco');
  var gameThemeId = THEME_REVERSE_MAP[rawThemeId] || rawThemeId;
  var themeObj = (window.THEMES || []).find(function(t) { return t.id === gameThemeId; }) || (window.THEMES || [])[0] || { teams: [] };
  var themeTeams = themeObj.teams || [];

  function handleSetCaptain(email, teamId) {
    setBusy(true);
    AdminApi.setCaptain(gameId, email, teamId)
      .then(function() { showToast('Captain set for ' + teamId, 'ok'); onRefresh(); })
      .catch(function(err) { showToast('Failed: ' + ((err && err.message) || err), 'err'); })
      .finally(function() { setBusy(false); });
  }
  function handleRemoveCaptain(email, teamId) {
    setBusy(true);
    AdminApi.removeCaptain(gameId, email, teamId)
      .then(function() { showToast('Captain removed', 'ok'); onRefresh(); })
      .catch(function(err) { showToast('Failed: ' + ((err && err.message) || err), 'err'); })
      .finally(function() { setBusy(false); });
  }

  var teamlessCount = nonProctorPlayers.filter(function(p) { return !p.team; }).length;
  var draftComplete = phase === 'draft' && teamlessCount === 0;
  var currentPhase = (tdState && tdState.game_phase) || phase || 'registration';
  var activeAgendaId = tdState && tdState.active_agenda_id;
  var questionsOpen = !!(tdState && tdState.questions_open);
  var closesAt = tdState && tdState.questions_closes_at;
  var secondsLeft = (questionsOpen && closesAt) ? Math.max(0, Math.floor(closesAt - nowTs)) : 0;

  function fmtClock(s) {
    if (!s || s <= 0) return '0:00';
    var m = Math.floor(s / 60); var ss = s % 60;
    return m + ':' + (ss < 10 ? '0' + ss : ss);
  }

  function nextAgendaId(currentId) {
    var sorted = agenda.slice().sort(function(a, b) { return (a.sort_order || 0) - (b.sort_order || 0); });
    var idx = sorted.findIndex(function(a) { return a.agenda_id === currentId; });
    if (idx < 0 || idx >= sorted.length - 1) return null;
    return sorted[idx + 1].agenda_id;
  }

  return (
    <div className="page-monitor tdmon">
      {/* ── Header ── */}
      <div className="pghd">
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: '10px', flexWrap: 'wrap' }}>
            <div className="title">{(eventData && eventData.name) || game.name || gameId}</div>
            <span className="tdmon-type-pill">Tech Day</span>
            <code style={{
              fontFamily: 'var(--f-m)',
              fontSize: '12px',
              background: 'var(--s2)',
              padding: '2px 8px',
              borderRadius: '4px',
              color: 'var(--brand)',
            }}>{displayCode}</code>
            <TDPhaseBadge phase={phase} />
            <span style={{ fontSize: '13px', color: 'var(--i3)' }}>
              {nonProctorPlayers.length} player{nonProctorPlayers.length !== 1 ? 's' : ''} · {speakers.length} speaker{speakers.length !== 1 ? 's' : ''} · {agenda.length} talk{agenda.length !== 1 ? 's' : ''}
            </span>
          </div>
          {eventData && (eventData.start_date || eventData.location) ? (
            <div style={{ marginTop: '6px', fontSize: '12px', color: 'var(--i3)' }}>
              {eventData.start_date || '—'}{eventData.location ? ' · ' + eventData.location : ''}
            </div>
          ) : null}
        </div>
        <div className="right" style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
          <a className="btn ghost"
             href={"/v2/tech-day-speakers?event_id=" + encodeURIComponent(eventId)}
             title="Manage speakers, agenda, decks">
            ⚙ Manage Tech Day
          </a>
          <button
            className="btn"
            onClick={function() {
              var url = '/v2/projector.html?game=' + encodeURIComponent(gameId);
              window.open(url, 'arena-projector-' + gameId,
                'width=1920,height=1080,menubar=no,toolbar=no,location=no,status=no');
            }}
            title="Big-screen view for projector / TV"
            style={{
              background: 'linear-gradient(135deg, #00BCEB 0%, #1E4D8C 100%)',
              borderColor: '#00BCEB',
              color: '#fff',
              fontWeight: 700,
              letterSpacing: '.02em',
            }}>
            📺 Projector ↗
          </button>
          <button className="btn ghost" onClick={function() { onSelectGame(null); }}>← Back</button>
        </div>
      </div>

      {loading ? (
        <div style={{ padding: '48px', textAlign: 'center', color: 'var(--i3)' }}>Loading tech-day data…</div>
      ) : (
        <div className="tdmon-grid">
          {/* ── Event Flow controls ── */}
          <div className="tdmon-block tdmon-flow">
            <div className="tdmon-block-hd">
              <h3>Event Flow</h3>
              <small>Phase: {currentPhase.toUpperCase()}</small>
            </div>
            {currentPhase === 'registration' ? (
              <div className="tdmon-flow-body">
                <div className="tdmon-flow-step">
                  <span className="tdmon-flow-num">1</span>
                  <div className="tdmon-flow-step-body">
                    <div className="tdmon-flow-step-title">Assign captains ({captains.length} / {themeTeams.length || 5})</div>
                    <div className="tdmon-flow-step-hint">Pick a captain for each team in the panel below.</div>
                  </div>
                </div>
                <div className="tdmon-flow-step">
                  <span className="tdmon-flow-num">2</span>
                  <div className="tdmon-flow-step-body">
                    <div className="tdmon-flow-step-title">Start draft</div>
                    <button className="btn primary"
                      disabled={busy || captains.length < 2}
                      title={captains.length < 2 ? 'Need at least 2 captains' : ('Begin snake draft with ' + captains.length + ' captain' + (captains.length === 1 ? '' : 's'))}
                      onClick={handleStartDraft}>
                      ▶ Start draft ({captains.length}/{themeTeams.length || 5})
                    </button>
                  </div>
                </div>
                <div className="tdmon-flow-step muted">
                  <span className="tdmon-flow-num">3</span>
                  <div className="tdmon-flow-step-body">
                    <div className="tdmon-flow-step-title">Skip draft (random teams)</div>
                    <button className="btn ghost sm"
                      disabled={busy}
                      title="Auto-assign all players to balanced teams and start playing"
                      onClick={handleBeginEvent}>
                      ⏭ Skip to playing
                    </button>
                  </div>
                </div>
              </div>
            ) : currentPhase === 'draft' ? (
              <div className="tdmon-flow-body">
                <div style={{ padding: '8px 0', fontSize: '13px', color: 'var(--i3)' }}>
                  Draft in progress — {nonProctorPlayers.length - teamlessCount} of {nonProctorPlayers.length} players assigned.
                </div>
                <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap', alignItems: 'center' }}>
                  {draftComplete ? (
                    <button className="btn primary" disabled={busy} onClick={handleBeginEvent}>
                      ▶ Begin event
                    </button>
                  ) : null}
                  <button className="btn ghost sm" disabled={busy} onClick={handleResetDraft}
                    title="Clears team assignments (keeps captains) and lets you restart the draft from round 1">
                    ↺ Restart draft
                  </button>
                </div>
              </div>
            ) : (
              <div className="tdmon-flow-body">
                <div style={{ padding: '8px 0', fontSize: '13px' }}>
                  {activeAgendaId ? (
                    <span>
                      Active talk: <strong>{tdState.active_title || activeAgendaId}</strong>
                      {questionsOpen ? (
                        <span style={{ color: 'var(--ok)', marginLeft: '8px' }}>
                          🟢 questions open · closes in {fmtClock(secondsLeft)}
                        </span>
                      ) : (
                        <span style={{ color: 'var(--wn)', marginLeft: '8px' }}>🔵 questions closed</span>
                      )}
                    </span>
                  ) : (
                    <span style={{ color: 'var(--i3)' }}>No active talk. Pick one from the agenda below.</span>
                  )}
                </div>
                {questionsOpen ? (
                  <button className="btn warn sm" disabled={busy} onClick={handleCloseQuestions}>🔒 Close questions now</button>
                ) : null}
              </div>
            )}
          </div>

          {/* ── Test Players (registration phase only — dev/admin tool) ── */}
          {currentPhase === 'registration' && (
            <div className="tdmon-block">
              <div className="tdmon-block-hd">
                <h3>Test Players <span style={{ fontSize: '11px', textTransform: 'uppercase', letterSpacing: '.05em', color: 'var(--i3)', marginLeft: '8px' }}>Dev tool</span></h3>
                <small>Simulate registered players for testing</small>
              </div>
              <div style={{ padding: '14px 16px' }}>
                <div style={{ display: 'flex', gap: '8px', alignItems: 'center', flexWrap: 'wrap' }}>
                  <label style={{ fontSize: '13px', color: 'var(--i2)' }}>Generate</label>
                  <input type="number" min="1" max="100" value={testPlayerCount}
                    onChange={function(e) { setTestPlayerCount(Math.max(1, Math.min(100, parseInt(e.target.value, 10) || 1))); }}
                    style={{ width: '64px', padding: '8px 10px', borderRadius: '8px', border: '1px solid var(--line-soft)', background: 'var(--s2)', color: 'var(--i1)', fontFamily: 'var(--f-m)', fontSize: '13px', textAlign: 'center' }}
                  />
                  <label style={{ fontSize: '13px', color: 'var(--i2)' }}>fake players</label>
                  <button className="btn primary sm" disabled={generatingPlayers} onClick={handleGenerateTestPlayers}>
                    {generatingPlayers ? 'Creating…' : '＋ Generate'}
                  </button>
                </div>
                <div style={{ display: 'flex', gap: '8px', alignItems: 'center', marginTop: '12px', paddingTop: '12px', borderTop: '1px solid var(--line-soft)' }}>
                  <span style={{ fontSize: '11px', color: 'var(--i3)' }}>For reset operations, see Danger Zone below ↓</span>
                </div>
              </div>
            </div>
          )}

          {/* ── Danger Zone (always visible, all phases) ── */}
          <div className="tdmon-block" style={{ borderColor: 'var(--dn)' }}>
            <div className="tdmon-block-hd">
              <h3 style={{ color: 'var(--dn)' }}>⚠ Danger Zone</h3>
              <small>Destructive operations — confirm before clicking</small>
            </div>
            <div style={{ padding: '14px 16px', display: 'flex', flexDirection: 'column', gap: '12px' }}>
              <div style={{ display: 'flex', gap: '10px', alignItems: 'center', flexWrap: 'wrap' }}>
                <button className="btn ghost sm" style={{ color: 'var(--dn)', borderColor: 'var(--dn)', fontSize: '12px' }} onClick={handleResetPlayers}>
                  ✕ Delete all players
                </button>
                <span style={{ fontSize: '11px', color: 'var(--i3)' }}>Keeps game config &amp; modules</span>
              </div>
              <div style={{ display: 'flex', gap: '10px', alignItems: 'center', flexWrap: 'wrap', paddingTop: '12px', borderTop: '1px solid var(--line-soft)' }}>
                <button className="btn ghost sm" style={{ color: 'var(--dn)', borderColor: 'var(--dn)', fontSize: '12px', fontWeight: 700 }} onClick={handleResetGame}>
                  ⟲ Reset game (full)
                </button>
                <span style={{ fontSize: '11px', color: 'var(--i3)' }}>Clears players, scores, tech-day answers &amp; active talk · phase → registration</span>
              </div>
            </div>
          </div>

          {/* ── Captain Assignment (registration phase only) ── */}
          {currentPhase === 'registration' && (
            <div className="tdmon-block">
              <div className="tdmon-block-hd">
                <h3>Captain Assignment</h3>
                <small>{captains.length}/{themeTeams.length || 5} assigned · {nonProctorPlayers.length} player{nonProctorPlayers.length !== 1 ? 's' : ''} registered</small>
              </div>
              {themeTeams.length === 0 ? (
                <div className="tdmon-empty">No teams found for theme "{gameThemeId}". Check the event theme.</div>
              ) : nonProctorPlayers.length === 0 ? (
                <div className="tdmon-empty">No players registered yet. Share the join code <strong>{displayCode}</strong> or QR from the projector.</div>
              ) : (
                <div>
                  {themeTeams.map(function(team) {
                    var captain = captainByTeam[team.id];
                    return (
                      <div key={team.id} style={{
                        display: 'flex', alignItems: 'center', gap: '10px',
                        padding: '10px 16px', borderBottom: '1px solid var(--line-soft)',
                      }}>
                        <div style={{ width: '10px', height: '10px', borderRadius: '50%', background: team.color || 'var(--i3)', flexShrink: 0 }} />
                        <div style={{ width: '120px', fontWeight: 600, fontSize: '13px' }}>{team.name}</div>
                        {captain ? (
                          <div style={{ flex: 1, display: 'flex', alignItems: 'center', gap: '8px' }}>
                            <span style={{ fontSize: '13px' }}>★ {captain.name || captain.email}</span>
                            <button className="btn ghost" style={{ fontSize: '11px', padding: '2px 6px', color: 'var(--dn)' }}
                              disabled={busy}
                              onClick={function() { handleRemoveCaptain(captain.email, team.id); }}>
                              ✕ remove
                            </button>
                          </div>
                        ) : (
                          <select
                            disabled={busy}
                            style={{
                              flex: 1, padding: '6px 8px', borderRadius: '6px',
                              border: '1px solid var(--line-soft)', background: 'var(--s2)',
                              color: 'var(--i1)', fontSize: '12px', fontFamily: 'var(--f-m)',
                            }}
                            value=""
                            onChange={function(e) { if (e.target.value) handleSetCaptain(e.target.value, team.id); }}>
                            <option value="">Select captain…</option>
                            {nonCaptainPlayers.map(function(p) {
                              return <option key={p.email} value={p.email}>{p.name || p.email}</option>;
                            })}
                          </select>
                        )}
                      </div>
                    );
                  })}
                </div>
              )}
            </div>
          )}

          {/* ── Agenda timeline ── */}
          <div className="tdmon-block tdmon-agenda">
            <div className="tdmon-block-hd">
              <h3>Agenda</h3>
              <small>{agenda.length} talk{agenda.length !== 1 ? 's' : ''}</small>
            </div>
            {agenda.length === 0 ? (
              <div className="tdmon-empty">No agenda items yet. <a href={"/v2/tech-day-speakers?event_id=" + encodeURIComponent(eventId)}>Add some</a>.</div>
            ) : (
              <ol className="tdmon-agenda-list">
                {agenda.slice().sort(function(a, b) {
                  return (a.sort_order || 0) - (b.sort_order || 0);
                }).map(function(item, idx) {
                  var sids = agendaSpeakerIds(item);
                  var resolvedSpeakers = sids.map(function(sid) { return speakerById[sid]; }).filter(Boolean);
                  var qs = questionsByAgenda[item.agenda_id] || [];
                  var hasAnySpeaker = resolvedSpeakers.length > 0 || sids.length > 0;
                  var isActive = activeAgendaId === item.agenda_id;
                  var nextId = nextAgendaId(item.agenda_id);
                  return (
                    <li key={item.agenda_id} className={"tdmon-agenda-item" + (isActive ? " active" : "")}>
                      <div className="tdmon-agenda-num">{String(idx + 1).padStart(2, '0')}</div>
                      <div className="tdmon-agenda-body">
                        <div className="tdmon-agenda-title">{item.title || 'Untitled talk'}</div>
                        <div className="tdmon-agenda-meta">
                          {hasAnySpeaker ? (
                            <span className="tdmon-spk">
                              {resolvedSpeakers.length
                                ? resolvedSpeakers.map(function(s) { return s.name; }).join(', ')
                                : (item.speaker_info || 'Speaker assigned')}
                            </span>
                          ) : (
                            <span className="tdmon-spk-empty">No speaker</span>
                          )}
                          {item.time ? <span> · {item.time}</span> : null}
                          {item.type ? <span> · {item.type}</span> : null}
                        </div>
                        <div className="tdmon-agenda-stats">
                          <span className="tag">{qs.length} question{qs.length !== 1 ? 's' : ''}</span>
                          {isActive ? (
                            <span className={"tag " + (questionsOpen ? 'ok' : 'warn')}>
                              {questionsOpen ? '🟢 Q&A open · ' + fmtClock(secondsLeft) : '🔵 Active · Q&A closed'}
                            </span>
                          ) : null}
                        </div>
                        {currentPhase === 'playing' ? (
                          <div className="tdmon-talk-actions">
                            {!isActive ? (
                              <button className="btn sm" disabled={busy || qs.length === 0}
                                title={qs.length === 0 ? 'No questions to gate' : 'Set as the active talk'}
                                onClick={function() { handleSetActive(item.agenda_id); }}>
                                ▶ Set as active
                              </button>
                            ) : !questionsOpen ? (
                              <React.Fragment>
                                <div className="tdmon-qcounts" style={{display:'flex', gap:8, alignItems:'center', flexWrap:'wrap', marginBottom:6}}>
                                  <label style={{fontSize:12, opacity:0.85}}>
                                    Tech&nbsp;
                                    <input type="number" min="0" max={qs.length}
                                      value={getQCount(item.agenda_id, 'n_tech', qs.length)}
                                      onChange={function(e){ setQCount(item.agenda_id, 'n_tech', e.target.value === '' ? '' : Math.max(0, Math.min(qs.length, parseInt(e.target.value, 10) || 0))); }}
                                      style={{width:60, marginLeft:4, padding:'2px 4px'}}
                                      disabled={busy}
                                      title={'Available: ' + qs.length}
                                    />
                                    <span style={{opacity:0.5, marginLeft:2}}>/ {qs.length}</span>
                                  </label>
                                  <label style={{fontSize:12, opacity:0.85}}>
                                    🌎 World Cup&nbsp;
                                    <input type="number" min="0" max="20"
                                      value={getQCount(item.agenda_id, 'n_theme', 0)}
                                      onChange={function(e){ setQCount(item.agenda_id, 'n_theme', e.target.value === '' ? '' : Math.max(0, Math.min(20, parseInt(e.target.value, 10) || 0))); }}
                                      style={{width:60, marginLeft:4, padding:'2px 4px'}}
                                      disabled={busy}
                                      title="0–20 themed trivia questions"
                                    />
                                  </label>
                                </div>
                                <button className="btn primary sm" disabled={busy}
                                  onClick={function() {
                                    handleOpenQuestions(item.agenda_id, {
                                      n_tech: parseInt(getQCount(item.agenda_id, 'n_tech', qs.length), 10) || 0,
                                      n_theme: parseInt(getQCount(item.agenda_id, 'n_theme', 0), 10) || 0,
                                    });
                                  }}>
                                  🔓 Open questions
                                </button>
                                {nextId ? (
                                  <button className="btn ghost sm" disabled={busy}
                                    onClick={function() { handleSetActive(nextId); }}>
                                    ⏭ Next talk
                                  </button>
                                ) : null}
                              </React.Fragment>
                            ) : (
                              <React.Fragment>
                                <button className="btn warn sm" disabled={busy}
                                  onClick={handleCloseQuestions}>
                                  🔒 Close questions
                                </button>
                                {nextId ? (
                                  <button className="btn ghost sm" disabled={busy}
                                    onClick={function() { handleSetActive(nextId); }}>
                                    ⏭ Next talk
                                  </button>
                                ) : null}
                              </React.Fragment>
                            )}
                          </div>
                        ) : null}
                      </div>
                    </li>
                  );
                })}
              </ol>
            )}
          </div>

          {/* ── Speakers ── */}
          <div className="tdmon-block tdmon-speakers">
            <div className="tdmon-block-hd">
              <h3>Speakers</h3>
              <small>{speakers.length} total</small>
            </div>
            {speakers.length === 0 ? (
              <div className="tdmon-empty">No speakers yet.</div>
            ) : (
              <div className="tdmon-speakers-grid">
                {speakers.map(function(s) {
                  var assignedAgenda = agenda.filter(function(a) {
                    return agendaSpeakerIds(a).indexOf(s.speaker_id) >= 0;
                  });
                  var qCount = assignedAgenda.reduce(function(sum, a) {
                    return sum + ((questionsByAgenda[a.agenda_id] || []).length);
                  }, 0);
                  return (
                    <div key={s.speaker_id} className="tdmon-speaker">
                      <div className="tdmon-speaker-name">{s.name}</div>
                      <div className="tdmon-speaker-email">{s.email}</div>
                      <div className="tdmon-speaker-stats">
                        <span>{assignedAgenda.length} talk{assignedAgenda.length !== 1 ? 's' : ''}</span>
                        <span>{qCount} Q{qCount !== 1 ? 's' : ''}</span>
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </div>

          {/* ── Question bank summary ── */}
          <div className="tdmon-block tdmon-qbank">
            <div className="tdmon-block-hd">
              <h3>Question Bank</h3>
              <small>For post-talk play</small>
            </div>
            <div className="tdmon-qbank-stats">
              <div className="tdmon-qbank-stat">
                <div className="tdmon-qbank-num">{totalQuestions}</div>
                <div className="tdmon-qbank-lbl">Total</div>
              </div>
              <div className="tdmon-qbank-stat">
                <div className="tdmon-qbank-num">{aiQuestions}</div>
                <div className="tdmon-qbank-lbl">AI-drafted</div>
              </div>
              <div className="tdmon-qbank-stat">
                <div className="tdmon-qbank-num">{manualQuestions}</div>
                <div className="tdmon-qbank-lbl">Manual</div>
              </div>
            </div>
          </div>

          {/* ── Leaderboard ── */}
          <div className="tdmon-block tdmon-leaderboard">
            <div className="tdmon-block-hd">
              <h3>Live Leaderboard</h3>
              <small>{sortedLb.length} ranked</small>
            </div>
            {sortedLb.length === 0 ? (
              <div className="tdmon-empty">No scores yet. Players appear here as they answer questions.</div>
            ) : (
              <ol className="tdmon-lb-list">
                {sortedLb.slice(0, 10).map(function(row, i) {
                  var name = row.name || row.display_name || row.email || '—';
                  var score = row.score || row.total_score || 0;
                  return (
                    <li key={(row.email || row.name) + i} className="tdmon-lb-row">
                      <span className="tdmon-lb-rank">{i + 1}</span>
                      <span className="tdmon-lb-name">{name}</span>
                      <span className="tdmon-lb-score">{score}</span>
                    </li>
                  );
                })}
              </ol>
            )}
          </div>
        </div>
      )}
    </div>
  );
};
