/* global React, Btn, Eyebrow, Display, Rule, FigureNum, Wordmark, Monogram */
const { useState: useStateLobby, useEffect: useEffectLobby, useRef: useRefLobby } = React;

const TEAMS_LOBBY = ["De Slimmeriken", "Kennistycoons", "Brain Storm", "Q-Force"];
const TEAM_COLORS = { "De Slimmeriken": "#dc2626", "Kennistycoons": "#0a0a0a", "Brain Storm": "#0f766e", "Q-Force": "#f97316" };

// JOIN_HOST is what we display to players. The actual /join page is served on
// the same origin as the lobby, so localhost demos work as well.
const JOIN_HOST = "kwisthet.be";

function LobbyScreen({ theme, quiz, user, onClose }) {
  const code = quiz?.code || null;
  const sessionId = quiz?.sessionId || null;
  const [showHostGuide, setShowHostGuide] = useStateLobby(() => {
    try { return window.localStorage.getItem("kwist-hide-host-guide") !== "1"; }
    catch { return true; }
  });
  const [players, setPlayers] = useStateLobby([]);
  const [countdown, setCountdown] = useStateLobby(null);
  const [started, setStarted] = useStateLobby(false);
  const [error, setError] = useStateLobby(null);
  // Host-game-runner state
  const [question, setQuestion] = useStateLobby(null);
  const [answeredIds, setAnsweredIds] = useStateLobby([]);
  const [ended, setEnded] = useStateLobby(false);
  const [scoreboard, setScoreboard] = useStateLobby(null);
  const [onlineIds, setOnlineIds] = useStateLobby([]);
  const wsRef = useRefLobby(null);

  // Initial fetch of session state, then keep up via WebSocket.
  useEffectLobby(() => {
    if (!code) {
      setError("Geen sessiecode — start de wizard opnieuw.");
      return;
    }
    let cancelled = false;
    (async () => {
      try {
        const r = await window.kwistApi.get(`/api/sessions/code/${code}`);
        if (cancelled) return;
        setPlayers(r.players || []);
        setStarted(r.session.status === "running" || r.session.status === "finished");
        if (r.session.status === "finished") setEnded(true);
      } catch (e) {
        setError(e.message);
      }
    })();

    const proto = window.location.protocol === "https:" ? "wss:" : "ws:";
    const ws = new WebSocket(`${proto}//${window.location.host}/ws/sessions/${code}`);
    wsRef.current = ws;
    ws.onmessage = (ev) => {
      let msg = null;
      try { msg = JSON.parse(ev.data); } catch { return; }
      if (msg.type === "player:joined" && msg.player) {
        setPlayers((curr) => curr.some((p) => p.id === msg.player.id) ? curr : [...curr, msg.player]);
      } else if (msg.type === "session:started") {
        setStarted(true);
      } else if (msg.type === "answer:received" && msg.playerId) {
        setAnsweredIds((curr) => curr.includes(msg.playerId) ? curr : [...curr, msg.playerId]);
      } else if (msg.type === "presence:update" && Array.isArray(msg.onlinePlayerIds)) {
        setOnlineIds(msg.onlinePlayerIds);
      } else if (msg.type === "hello" && Array.isArray(msg.onlinePlayerIds)) {
        setOnlineIds(msg.onlinePlayerIds);
      } else if (msg.type === "session:finished") {
        setEnded(true);
      }
    };
    ws.onerror = () => { /* swallow — REST polling is the fallback */ };
    return () => { cancelled = true; ws.close(); };
  }, [code]);

  useEffectLobby(() => {
    if (countdown === null || countdown <= 0) return;
    const t = setTimeout(() => setCountdown(countdown - 1), 1000);
    return () => clearTimeout(t);
  }, [countdown]);

  const startSession = async () => {
    try {
      await window.kwistApi.post(`/api/sessions/${code}/start`, {});
      setCountdown(3);
    } catch (e) {
      setError(e.message);
    }
  };

  const projectorRef = useRefLobby(null);
  const openProjector = () => {
    if (!code) return;
    if (projectorRef.current && !projectorRef.current.closed) {
      projectorRef.current.focus();
      return;
    }
    projectorRef.current = window.open(
      `/projector?code=${encodeURIComponent(code)}`,
      "kwisthet-projector",
      "popup,width=1280,height=800"
    );
  };

  // Auto-open the projector window once we have a session code.
  useEffectLobby(() => {
    if (!code) return;
    const opened = window.sessionStorage.getItem(`projector-opened-${code}`);
    if (opened) return;
    const w = window.open(
      `/projector?code=${encodeURIComponent(code)}`,
      "kwisthet-projector",
      "popup,width=1280,height=800"
    );
    if (w) {
      projectorRef.current = w;
      window.sessionStorage.setItem(`projector-opened-${code}`, "1");
    }
  }, [code]);

  const broadcastStandings = async (show) => {
    try { await window.kwistApi.post(`/api/sessions/${code}/standings`, { show }); }
    catch { /* ignore */ }
  };

  const advanceQuestion = async () => {
    try {
      const r = await window.kwistApi.post(`/api/sessions/${code}/next`, {});
      if (r.done) {
        setEnded(true);
        const lobby = await window.kwistApi.get(`/api/sessions/code/${code}`);
        setScoreboard([...(lobby.players || [])].sort((a, b) => b.score - a.score));
      } else {
        setQuestion(r.question);
        setAnsweredIds([]);
      }
    } catch (e) {
      setError(e.message);
    }
  };

  // Wanneer ended-via-WS getriggerd wordt zonder dat we de scoreboard al hebben.
  useEffectLobby(() => {
    if (!ended || scoreboard) return;
    (async () => {
      try {
        const lobby = await window.kwistApi.get(`/api/sessions/code/${code}`);
        setScoreboard([...(lobby.players || [])].sort((a, b) => b.score - a.score));
      } catch { /* ignore */ }
    })();
  }, [ended, scoreboard, code]);

  const teamCounts = TEAMS_LOBBY.map((t) => ({ name: t, count: players.filter((p) => p.team === t).length }));
  const accentColor = quiz?.color || theme.accent;
  const hostName = user?.name || quiz?.author || "Host";
  const sessionLabel = sessionId ? sessionId.slice(0, 8).toUpperCase() : "—";

  return (
    <div style={{ minHeight: "100vh", background: theme.bg, display: "flex", flexDirection: "column" }}>
      {/* MASTHEAD */}
      <header style={{
        borderBottom: `3px double ${theme.rule}`,
        padding: "14px 40px",
        display: "grid",
        gridTemplateColumns: "1fr auto 1fr",
        alignItems: "center",
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
          <button onClick={onClose} style={{
            background: "transparent", border: "none",
            fontFamily: theme.fonts.display, fontSize: 16, color: theme.fg, cursor: "pointer",
          }}>← terug</button>
          <div style={{ width: 1, height: 16, background: theme.rule }} />
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <span style={{ width: 8, height: 8, background: theme.signal, borderRadius: "50%", animation: "blink 1s infinite" }}></span>
            <Eyebrow theme={theme} style={{ color: theme.signal }}>LIVE LOBBY</Eyebrow>
          </div>
        </div>
        <Wordmark size={140} />
        <div style={{ textAlign: "right" }}>
          <Eyebrow theme={theme}>SESSIE Nº {sessionLabel} · HOST: {hostName.toUpperCase()}</Eyebrow>
        </div>
      </header>

      {error && (
        <div style={{
          padding: "10px 40px", background: `${theme.accent}10`,
          color: theme.accent, fontFamily: theme.fonts.mono, fontSize: 12,
          borderBottom: `1px solid ${theme.accent}`,
        }}>{error}</div>
      )}

      {/* MAIN — pre-game lobby OR host-game-runner OR scoreboard */}
      {started && ended ? (
        <ScoreboardView theme={theme} quiz={quiz} scoreboard={scoreboard} onClose={onClose} />
      ) : started ? (
        <HostGameView
          theme={theme}
          quiz={quiz}
          question={question}
          players={players}
          answeredIds={answeredIds}
          answeredCount={answeredIds.length}
          onlineIds={onlineIds}
          onAdvance={advanceQuestion}
          onClose={onClose}
          onOpenProjector={openProjector}
          onBroadcastStandings={broadcastStandings}
        />
      ) : (
      <div style={{ flex: 1, display: "grid", gridTemplateColumns: "1.5fr 1fr" }}>
        {/* LEFT — the cover with code */}
        <section style={{
          background: accentColor, color: "#fff",
          padding: "44px 56px",
          position: "relative", overflow: "hidden",
          display: "flex", flexDirection: "column", justifyContent: "space-between",
          borderRight: `1px solid ${theme.rule}`,
        }}>
          <div style={{
            position: "absolute", inset: 0,
            backgroundImage: `radial-gradient(circle at 80% 10%, rgba(255,255,255,0.12) 0%, transparent 40%)`,
            pointerEvents: "none",
          }} />

          <div style={{ position: "relative" }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
              <div style={{ fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.15em", opacity: 0.85 }}>
                EDITIE · {(quiz?.category || "ALGEMEEN").toUpperCase()}
              </div>
              <div style={{ fontFamily: theme.fonts.display, fontSize: 14, opacity: 0.85 }}>vandaag</div>
            </div>
            <div style={{ height: 1, background: "rgba(255,255,255,0.4)", margin: "12px 0" }} />
            <div style={{
              fontFamily: theme.fonts.display, fontSize: "clamp(48px, 5.4vw, 84px)",
              lineHeight: 0.95, letterSpacing: "-0.025em",
              maxWidth: 760,
            }}>{quiz?.title || "Quiz"}</div>
            <div style={{ marginTop: 20, display: "flex", gap: 24, fontFamily: theme.fonts.mono, fontSize: 12, letterSpacing: "0.1em", opacity: 0.9 }}>
              <span><b>{quiz?.questions || 0}</b> VRAGEN</span>
              <span>·</span>
              <span>~<b>{Math.round((quiz?.questions || 20) * 22 / 60)}</b> MIN</span>
              <span>·</span>
              <span><b>{players.length}</b> SPELERS</span>
            </div>
          </div>

          {/* JOIN block */}
          <div style={{ position: "relative", display: "grid", gridTemplateColumns: "1fr 200px", gap: 36, alignItems: "end" }}>
            <div>
              <div style={{ fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.15em", opacity: 0.85, marginBottom: 12 }}>
                ── HOE MEE TE DOEN
              </div>
              <div style={{ fontFamily: theme.fonts.display, fontSize: 30, lineHeight: 1.2, marginBottom: 24 }}>
                Ga naar <span style={{ borderBottom: "2px solid #fff" }}>{JOIN_HOST}/join</span>
              </div>
              <div style={{ fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.15em", opacity: 0.85, marginBottom: 8 }}>
                ── EN VOER DE CODE IN
              </div>
              <div style={{
                fontFamily: theme.fonts.display, fontSize: 96, lineHeight: 1, letterSpacing: "0.01em",
                color: "#fff",
              }}>{code || "··-····"}</div>
            </div>
            <div>
              <div style={{ fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.15em", opacity: 0.85, marginBottom: 8, textAlign: "center" }}>
                ── OF SCAN
              </div>
              <QRCode theme={theme} size={184} value={code ? `${window.location.origin}/?code=${encodeURIComponent(code)}` : ""} />
            </div>
          </div>
        </section>

        {/* RIGHT — players column */}
        <section style={{ display: "flex", flexDirection: "column" }}>
          <div style={{ padding: "28px 36px 20px", borderBottom: `1px solid ${theme.rule}` }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
              <Display theme={theme} size={36}>De gasten</Display>
              <FigureNum theme={theme} size={48} accent>{players.length}</FigureNum>
            </div>
            <Eyebrow theme={theme} style={{ marginTop: 4 }}>── ZE DRUPPELEN BINNEN</Eyebrow>

            {quiz?.teamsEnabled && (
              <div style={{ marginTop: 20 }}>
                <Eyebrow theme={theme} style={{ marginBottom: 8 }}>── TEAMS</Eyebrow>
                <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
                  {teamCounts.map((t) => (
                    <div key={t.name} style={{
                      padding: "8px 10px",
                      border: `1px solid ${theme.rule}`,
                      display: "flex", justifyContent: "space-between", alignItems: "center", gap: 8,
                    }}>
                      <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
                        <div style={{ width: 8, height: 8, background: TEAM_COLORS[t.name], borderRadius: "50%" }} />
                        <span style={{ fontFamily: theme.fonts.display, fontSize: 14, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{t.name}</span>
                      </div>
                      <FigureNum theme={theme} size={18}>{t.count}</FigureNum>
                    </div>
                  ))}
                </div>
              </div>
            )}
          </div>

          {/* player list */}
          <div style={{ flex: 1, overflowY: "auto", padding: "16px 36px", background: theme.bg }}>
            {players.length === 0 ? (
              <div style={{ padding: 40, textAlign: "center" }}>
                <Eyebrow theme={theme}>WACHTEN OP SPELERS…</Eyebrow>
                <div style={{ marginTop: 8, fontFamily: theme.fonts.mono, fontSize: 11, color: theme.fgDim }}>
                  Deel <b>{code}</b> of de QR-code
                </div>
              </div>
            ) : (
              <div style={{ display: "flex", flexDirection: "column" }}>
                {[...players].reverse().map((p, idx) => {
                  const online = onlineIds.includes(p.id);
                  return (
                  <div key={p.id} style={{
                    display: "flex", alignItems: "center", gap: 14,
                    padding: "12px 0",
                    borderBottom: idx < players.length - 1 ? `1px dashed ${theme.rule}` : "none",
                    animation: idx === 0 ? "slidein 0.4s ease-out" : "none",
                    opacity: online ? 1 : 0.5,
                  }}>
                    <div style={{ position: "relative" }}>
                      <Monogram theme={theme} text={p.initials} color={p.team ? TEAM_COLORS[p.team] : theme.fg} size={36} />
                      <span style={{
                        position: "absolute", bottom: -2, right: -2,
                        width: 10, height: 10, borderRadius: "50%",
                        background: online ? "#16a34a" : theme.fgDim,
                        border: `2px solid ${theme.bg}`,
                      }} />
                    </div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontFamily: theme.fonts.display, fontSize: 18, lineHeight: 1.1 }}>{p.name}</div>
                      {p.team && <Eyebrow theme={theme}>{p.team}</Eyebrow>}
                    </div>
                    <Eyebrow theme={theme} style={{ color: online ? "#16a34a" : theme.fgDim }}>
                      {online ? "ONLINE" : "OFFLINE"}
                    </Eyebrow>
                  </div>
                  );
                })}
              </div>
            )}
          </div>

          {/* Start */}
          <div style={{ borderTop: `1px solid ${theme.rule}`, padding: 20 }}>
            {countdown !== null && countdown > 0 ? (
              <div style={{
                background: theme.signal, color: "#fff",
                padding: "20px 24px", textAlign: "center",
              }}>
                <Eyebrow theme={theme} style={{ color: "#fff", opacity: 0.9 }}>── STARTEN OVER</Eyebrow>
                <FigureNum theme={theme} size={88}>{countdown}</FigureNum>
              </div>
            ) : (countdown === 0 || started) ? (
              <div style={{
                background: theme.accent, color: "#fff",
                padding: "20px 24px", textAlign: "center",
                fontFamily: theme.fonts.display, fontSize: 28,
              }}>De quiz is begonnen.</div>
            ) : (
              <>
                <Btn theme={theme} size="lg" onClick={startSession} disabled={!code} style={{ width: "100%", justifyContent: "center", opacity: code ? 1 : 0.5 }}>
                  Start de sessie · {players.length} {players.length === 1 ? "speler" : "spelers"}
                  <span style={{ fontFamily: theme.fonts.display, }}>→</span>
                </Btn>
                <Btn theme={theme} variant="outline" onClick={openProjector} style={{ width: "100%", justifyContent: "center", marginTop: 8 }}>
                  Open projectorvenster ↗
                </Btn>
              </>
            )}
            <Eyebrow theme={theme} style={{ textAlign: "center", marginTop: 10 }}>
              SPELERS KUNNEN OOK NOG TIJDENS DE COUNTDOWN AANSLUITEN
            </Eyebrow>
          </div>
        </section>
      </div>
      )}

      {showHostGuide && (
        <HostGuide
          theme={theme}
          onClose={() => setShowHostGuide(false)}
          onDismissForever={() => {
            try { window.localStorage.setItem("kwist-hide-host-guide", "1"); } catch {}
            setShowHostGuide(false);
          }}
        />
      )}

      <style>{`
        @keyframes blink { 50% { opacity: 0.3 } }
        @keyframes slidein { from { transform: translateX(20px); opacity: 0 } to { transform: translateX(0); opacity: 1 } }
      `}</style>
    </div>
  );
}

// =================== HOST ONBOARDING WIZARD ===================
function HostGuide({ theme, onClose, onDismissForever }) {
  const [step, setStep] = useStateLobby(0);
  const steps = [
    {
      eyebrow: "── WELKOM, QUIZMASTER",
      title: "Klaar om te starten?",
      body: "Even snel door de basics. Drie stappen, je bent in 30 seconden weg.",
    },
    {
      eyebrow: "── STAP 1 · DEEL DE CODE",
      title: "Spelers joinen via een code.",
      body: "Op het hoofdscherm zie je een grote code en een QR. Spelers gaan naar kwisthet.be/join, vullen die in, kiezen een naam — en je ziet ze rechts verschijnen. Wacht tot iedereen erin staat.",
    },
    {
      eyebrow: "── STAP 2 · OPEN DE PROJECTOR",
      title: "Twee schermen, twee rollen.",
      body: "Het projectorvenster opent automatisch in een nieuw browservenster. Sleep dat naar je beamer of tweede scherm — daar zien spelers de vraag, zonder het antwoord. Op je eigen scherm hou jij de regie: je ziet wél het juiste antwoord, hoeveel mensen al geantwoord hebben, en de live tussenstand.",
    },
    {
      eyebrow: "── STAP 3 · GA DOOR DE VRAGEN",
      title: "Jij bent de dirigent.",
      body: "Druk op 'Volgende vraag' wanneer iedereen geantwoord heeft of de tijd op is. Tussen vragen door kun je 'Toon tussenstand' tonen — dat verschijnt ook live op de projector met geanimeerde balkjes. Aan het einde zie je het volledige klassement.",
    },
    {
      eyebrow: "── EXTRA",
      title: "Goed om te weten.",
      body: "Alles wordt automatisch opgeslagen. Mocht je browser crashen, dan kun je terug naar deze sessie. De resultaten van afgelopen quizzes vind je later terug onder 'Resultaten' in de hoofdnavigatie.",
    },
  ];
  const cur = steps[step];
  const isLast = step === steps.length - 1;

  return (
    <div style={{
      position: "fixed", inset: 0,
      background: "rgba(0,0,0,0.7)",
      display: "grid", placeItems: "center",
      zIndex: 300,
      animation: "fadein 0.25s ease-out",
    }} onClick={onClose}>
      <div style={{
        background: theme.bg, color: theme.fg,
        width: "min(640px, 92vw)", maxHeight: "88vh",
        border: `3px double ${theme.rule}`,
        boxShadow: `8px 8px 0 0 ${theme.fg}`,
        display: "flex", flexDirection: "column",
        overflow: "hidden",
      }} onClick={(e) => e.stopPropagation()}>
        <div style={{
          padding: "14px 24px", borderBottom: `1px solid ${theme.rule}`,
          display: "flex", justifyContent: "space-between", alignItems: "center",
          fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.15em", color: theme.fgDim,
        }}>
          <span>QUIZMASTER · GIDS</span>
          <span>{step + 1} / {steps.length}</span>
          <button onClick={onClose} style={{
            background: "transparent", border: "none", cursor: "pointer",
            fontFamily: theme.fonts.display, fontSize: 18, color: theme.fg,
          }}>✕</button>
        </div>

        <div style={{ padding: "32px 36px", flex: 1, overflowY: "auto" }}>
          <div style={{ fontSize: 56, marginBottom: 16 }}>{cur.visual}</div>
          <Eyebrow theme={theme} style={{ color: theme.accent, marginBottom: 10 }}>{cur.eyebrow}</Eyebrow>
          <Display theme={theme} size={42} style={{ marginBottom: 16 }}>{cur.title}</Display>
          <p style={{ fontSize: 16, lineHeight: 1.6, color: theme.fg }}>{cur.body}</p>
        </div>

        <div style={{
          padding: "16px 24px", borderTop: `1px solid ${theme.rule}`,
          display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12,
        }}>
          <div style={{ display: "flex", gap: 6 }}>
            {steps.map((_, i) => (
              <div key={i} style={{
                width: 24, height: 4,
                background: i <= step ? theme.accent : theme.rule,
                transition: "background 0.2s",
              }} />
            ))}
          </div>
          <div style={{ display: "flex", gap: 8 }}>
            {step > 0 && (
              <Btn theme={theme} variant="outline" onClick={() => setStep(step - 1)}>← Terug</Btn>
            )}
            {!isLast ? (
              <Btn theme={theme} onClick={() => setStep(step + 1)}>Volgende →</Btn>
            ) : (
              <>
                <Btn theme={theme} variant="outline" onClick={onDismissForever}>
                  Laat volgende keer niet meer zien
                </Btn>
                <Btn theme={theme} onClick={onClose}>Aan de slag →</Btn>
              </>
            )}
          </div>
        </div>
      </div>
      <style>{`@keyframes fadein { from { opacity: 0 } to { opacity: 1 } }`}</style>
    </div>
  );
}

// =================== HOST GAME RUNNER ===================
// Toont de huidige vraag (met juist antwoord), live answer count, en heeft
// een "Volgende vraag"-knop die /api/sessions/:code/next aanroept.
function HostGameView({ theme, quiz, question, players, answeredIds = [], answeredCount, onlineIds = [], onAdvance, onClose, onOpenProjector, onBroadcastStandings }) {
  const [secondsLeft, setSecondsLeft] = useStateLobby(null);
  const [showStandings, setShowStandings] = useStateLobby(false);

  const toggleStandings = () => {
    setShowStandings((s) => {
      const next = !s;
      if (onBroadcastStandings) onBroadcastStandings(next);
      return next;
    });
  };

  useEffectLobby(() => {
    if (!question || !question.time_limit) { setSecondsLeft(null); return; }
    setSecondsLeft(question.time_limit);
    const id = setInterval(() => {
      setSecondsLeft((s) => (s === null || s <= 0) ? s : s - 1);
    }, 1000);
    return () => clearInterval(id);
  }, [question?.id]);

  const accent = quiz?.color || theme.accent;
  const optionsHasCorrect = (opts) => Array.isArray(opts) && opts.some((o) => o.correct);

  return (
    <div style={{ flex: 1, display: "grid", gridTemplateColumns: "2fr 1fr", position: "relative" }}>
      {/* LEFT: question */}
      <section style={{
        background: theme.bg, color: theme.fg,
        padding: "44px 56px",
        display: "flex", flexDirection: "column", gap: 28,
        borderRight: `1px solid ${theme.rule}`,
      }}>
        {!question ? (
          <div style={{ margin: "auto", textAlign: "center" }}>
            <Eyebrow theme={theme} style={{ color: accent, marginBottom: 12 }}>── DE QUIZ IS BEGONNEN</Eyebrow>
            <Display theme={theme} size={72} style={{ marginBottom: 18 }}>Klaar?</Display>
            <p style={{ color: theme.fgDim, fontSize: 16, maxWidth: 480, margin: "0 auto 28px" }}>
              Druk op "Toon eerste vraag" om de quiz écht te starten. Spelers zien hem direct op hun telefoon.
            </p>
            <Btn theme={theme} size="lg" onClick={onAdvance}>Toon eerste vraag →</Btn>
          </div>
        ) : (
          <>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
              <Eyebrow theme={theme} style={{ color: accent }}>── VRAAG {(question.position ?? 0) + 1} / {quiz?.questions || "?"}</Eyebrow>
              {secondsLeft !== null && (
                <FigureNum theme={theme} size={36} accent={secondsLeft <= 5}>{secondsLeft}<span style={{ fontSize: 18, marginLeft: 4, color: theme.fgDim }}>sec</span></FigureNum>
              )}
            </div>
            <Display theme={theme} size={56} style={{ lineHeight: 1.1 }}>{question.prompt}</Display>

            {question.type === "mc" && Array.isArray(question.options) && (
              <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                {question.options.map((o, i) => {
                  const correct = !!o.correct;
                  return (
                    <div key={o.id || i} style={{
                      padding: "16px 20px",
                      border: `1px solid ${correct ? theme.accent : theme.rule}`,
                      background: correct ? `${theme.accent}10` : "transparent",
                      color: correct ? theme.accent : theme.fg,
                      display: "flex", justifyContent: "space-between", alignItems: "center",
                      fontFamily: theme.fonts.body, fontSize: 17,
                    }}>
                      <span><span style={{ fontFamily: theme.fonts.mono, marginRight: 14, color: theme.fgDim }}>{String.fromCharCode(65 + i)}.</span>{o.text}</span>
                      {correct && <span style={{ fontFamily: theme.fonts.display, fontSize: 16 }}>✓ JUIST</span>}
                    </div>
                  );
                })}
                {!optionsHasCorrect(question.options) && (
                  <Eyebrow theme={theme} style={{ color: theme.accent }}>LET OP — geen juist antwoord ingesteld</Eyebrow>
                )}
              </div>
            )}

            {question.type === "tf" && (
              <div style={{
                padding: "20px 24px",
                border: `1px solid ${theme.accent}`,
                background: `${theme.accent}10`,
                color: theme.accent,
                fontFamily: theme.fonts.display, fontSize: 22,
                textTransform: "uppercase",
              }}>✓ {question.answer || "—"}</div>
            )}

            {question.type === "open" && (
              <div style={{
                padding: "20px 24px",
                border: `1px solid ${theme.accent}`,
                background: `${theme.accent}10`,
                color: theme.accent,
                fontFamily: theme.fonts.display, fontSize: 22,
              }}>✓ {question.answer || "—"}</div>
            )}
          </>
        )}
      </section>

      {/* RIGHT: live counters + advance */}
      <section style={{ display: "flex", flexDirection: "column", background: theme.bg2, color: theme.fg }}>
        <div style={{ padding: "28px 36px", borderBottom: `1px solid ${theme.rule}` }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
            <Display theme={theme} size={36}>Live</Display>
            <button onClick={onClose} style={{
              background: "transparent", border: "none",
              fontFamily: theme.fonts.mono, fontSize: 11, color: theme.fgDim, letterSpacing: "0.1em",
              cursor: "pointer", textTransform: "uppercase",
            }}>Verberg ↗</button>
          </div>
          <Eyebrow theme={theme} style={{ marginTop: 4 }}>── ANTWOORDEN BINNEN</Eyebrow>
          <div style={{ display: "flex", alignItems: "baseline", gap: 14, marginTop: 18 }}>
            <FigureNum theme={theme} size={88} accent>{answeredCount}</FigureNum>
            <div style={{ fontFamily: theme.fonts.display, fontSize: 30, color: theme.fgDim }}>/ {players.length}</div>
          </div>
          <div style={{ marginTop: 12, height: 6, background: theme.rule, position: "relative" }}>
            <div style={{
              position: "absolute", top: 0, left: 0, height: "100%",
              width: `${players.length ? (answeredCount / players.length) * 100 : 0}%`,
              background: theme.accent, transition: "width .3s",
            }} />
          </div>
        </div>

        <div style={{ flex: 1, padding: "20px 36px", overflowY: "auto" }}>
          <Eyebrow theme={theme} style={{ marginBottom: 10 }}>
            ── SPELERS ({onlineIds.length}/{players.length} ONLINE)
          </Eyebrow>
          <div style={{ display: "flex", flexDirection: "column" }}>
            {players.map((p, idx) => {
              const online = onlineIds.includes(p.id);
              const answered = answeredIds.includes(p.id);
              return (
                <div key={p.id} style={{
                  display: "flex", alignItems: "center", gap: 12,
                  padding: "8px 0",
                  borderBottom: idx < players.length - 1 ? `1px dashed ${theme.rule}` : "none",
                  opacity: online ? 1 : 0.5,
                }}>
                  <div style={{ position: "relative" }}>
                    <Monogram theme={theme} text={p.initials} size={28} color={p.team ? TEAM_COLORS[p.team] : theme.fg} />
                    <span style={{
                      position: "absolute", bottom: -2, right: -2,
                      width: 9, height: 9, borderRadius: "50%",
                      background: online ? "#16a34a" : theme.fgDim,
                      border: `2px solid ${theme.bg2}`,
                    }} />
                  </div>
                  <div style={{ flex: 1, fontFamily: theme.fonts.display, fontSize: 16 }}>{p.name}</div>
                  {question && answered && (
                    <Eyebrow theme={theme} style={{ color: theme.accent }}>✓</Eyebrow>
                  )}
                  <Eyebrow theme={theme}>{(p.score || 0).toLocaleString("nl-NL")} pt</Eyebrow>
                </div>
              );
            })}
          </div>
        </div>

        <div style={{ borderTop: `1px solid ${theme.rule}`, padding: 20, display: "flex", flexDirection: "column", gap: 10 }}>
          <Btn theme={theme} size="lg" onClick={onAdvance} style={{ width: "100%", justifyContent: "center" }}>
            {!question ? "Toon eerste vraag" : "Volgende vraag"}
            <span style={{ fontFamily: theme.fonts.display }}>→</span>
          </Btn>
          <Btn theme={theme} variant="outline" onClick={toggleStandings} style={{ width: "100%", justifyContent: "center" }}>
            {showStandings ? "Hervat quiz" : "Pauzeer quiz"}
          </Btn>
          {onOpenProjector && (
            <Btn theme={theme} variant="outline" onClick={onOpenProjector} style={{ width: "100%", justifyContent: "center" }}>
              Open projectorvenster ↗
            </Btn>
          )}
          <Eyebrow theme={theme} style={{ textAlign: "center", marginTop: 4 }}>
            DRUK ZODRA IEDEREEN GEANTWOORD HEEFT (OF DE TIJD OM IS)
          </Eyebrow>
        </div>
      </section>

      {showStandings && (
        <div style={{
          position: "absolute", inset: 0,
          background: "rgba(0,0,0,0.6)",
          display: "grid", placeItems: "center",
          zIndex: 100,
        }} onClick={toggleStandings}>
          <div style={{
            background: theme.bg, color: theme.fg,
            padding: "36px 48px", maxWidth: 600, width: "90%",
            maxHeight: "80vh", overflowY: "auto",
            border: `3px double ${theme.rule}`,
          }} onClick={(e) => e.stopPropagation()}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 20 }}>
              <Display theme={theme} size={36}>Tussenstand</Display>
              <button onClick={toggleStandings} style={{
                background: "transparent", border: "none",
                fontFamily: theme.fonts.display, fontSize: 20, color: theme.fg, cursor: "pointer",
              }}>✕</button>
            </div>
            {[...players].sort((a, b) => (b.score || 0) - (a.score || 0)).map((p, i) => (
              <div key={p.id} style={{
                display: "grid", gridTemplateColumns: "32px 28px 1fr auto",
                alignItems: "center", gap: 12,
                padding: "10px 0",
                borderBottom: `1px dashed ${theme.rule}`,
              }}>
                <FigureNum theme={theme} size={18}>{i + 1}</FigureNum>
                <Monogram theme={theme} text={p.initials} size={28} color={p.team ? TEAM_COLORS[p.team] : theme.fg} />
                <div style={{ fontFamily: theme.fonts.display, fontSize: 18 }}>{p.name}</div>
                <FigureNum theme={theme} size={20} accent>{(p.score || 0).toLocaleString("nl-NL")}</FigureNum>
              </div>
            ))}
            {players.length === 0 && <Eyebrow theme={theme}>GEEN SPELERS</Eyebrow>}
          </div>
        </div>
      )}
    </div>
  );
}

// =================== SCOREBOARD ===================
function ScoreboardView({ theme, quiz, scoreboard, onClose }) {
  const top = (scoreboard || []).slice(0, 10);
  const podium = top.slice(0, 3);
  const rest = top.slice(3);
  const accent = quiz?.color || theme.accent;

  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", background: theme.bg }}>
      <div style={{
        background: accent, color: "#fff",
        padding: "44px 56px",
        textAlign: "center",
      }}>
        <div style={{ fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.15em", opacity: 0.85 }}>── EINDSTAND</div>
        <div style={{ fontFamily: theme.fonts.display, fontSize: "clamp(48px, 6vw, 92px)", lineHeight: 1, marginTop: 14 }}>
          De winnaars.
        </div>
        {podium.length > 0 && (
          <div style={{
            marginTop: 32,
            display: "grid",
            gridTemplateColumns: "1fr 1fr 1fr",
            gap: 18, alignItems: "end",
            maxWidth: 720, marginLeft: "auto", marginRight: "auto",
          }}>
            {[1, 0, 2].map((rankIdx) => {
              const p = podium[rankIdx];
              if (!p) return <div key={rankIdx} />;
              const heights = [120, 80, 60];
              return (
                <div key={p.id} style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 8 }}>
                  <div style={{ fontFamily: theme.fonts.display, fontSize: 22 }}>{p.name}</div>
                  <div style={{ fontFamily: theme.fonts.mono, fontSize: 12, opacity: 0.85 }}>{(p.score || 0).toLocaleString("nl-NL")} pt</div>
                  <div style={{
                    width: "100%", height: heights[rankIdx],
                    background: rankIdx === 0 ? "rgba(255,255,255,0.95)" : rankIdx === 1 ? "rgba(255,255,255,0.7)" : "rgba(255,255,255,0.5)",
                    color: accent,
                    fontFamily: theme.fonts.display, fontSize: 56,
                    display: "grid", placeItems: "center",
                  }}>{rankIdx + 1}</div>
                </div>
              );
            })}
          </div>
        )}
      </div>

      <div style={{ padding: "32px 56px", flex: 1 }}>
        {rest.length > 0 && (
          <>
            <Eyebrow theme={theme} style={{ marginBottom: 12 }}>── EN VERDER</Eyebrow>
            <div>
              {rest.map((p, i) => (
                <div key={p.id} style={{
                  display: "grid", gridTemplateColumns: "40px 1fr auto",
                  alignItems: "center", gap: 14,
                  padding: "12px 0",
                  borderBottom: i < rest.length - 1 ? `1px dashed ${theme.rule}` : "none",
                }}>
                  <FigureNum theme={theme} size={20}>{i + 4}</FigureNum>
                  <div style={{ fontFamily: theme.fonts.display, fontSize: 18 }}>{p.name}</div>
                  <FigureNum theme={theme} size={20} accent>{(p.score || 0).toLocaleString("nl-NL")}</FigureNum>
                </div>
              ))}
            </div>
          </>
        )}
        {(!scoreboard || scoreboard.length === 0) && (
          <div style={{ padding: 40, textAlign: "center" }}>
            <Eyebrow theme={theme}>GEEN DEELNEMERS GEREGISTREERD</Eyebrow>
          </div>
        )}
      </div>

      <div style={{ borderTop: `1px solid ${theme.rule}`, padding: "20px 40px", display: "flex", justifyContent: "space-between" }}>
        <Eyebrow theme={theme}>SESSIE BEËINDIGD · DE LINK BLIJFT WERKEN VOOR EEN HERSPELING</Eyebrow>
        <Btn theme={theme} variant="outline" onClick={onClose}>← Naar dashboard</Btn>
      </div>
    </div>
  );
}

function QRCode({ theme, size = 180, value }) {
  // Echte, scanbare QR-code via qrcode-generator (UMD globaal `qrcode`).
  // typeNumber 0 = automatisch, errorCorrection "M" = 15% redundancy.
  const matrix = (() => {
    if (!value || typeof window.qrcode !== "function") return null;
    try {
      const qr = window.qrcode(0, "M");
      qr.addData(value);
      qr.make();
      const n = qr.getModuleCount();
      const arr = [];
      for (let r = 0; r < n; r++) {
        const row = [];
        for (let c = 0; c < n; c++) row.push(qr.isDark(r, c));
        arr.push(row);
      }
      return arr;
    } catch (e) {
      return null;
    }
  })();

  if (!matrix) {
    return (
      <div style={{ background: "#fff", padding: 10, width: size + 20, height: size + 20, display: "grid", placeItems: "center", boxSizing: "content-box", color: "#000", fontFamily: theme.fonts.mono, fontSize: 10 }}>
        QR…
      </div>
    );
  }

  const cells = matrix.length;
  const cellSize = size / cells;
  return (
    <div style={{ background: "#fff", padding: 10, width: size + 20, boxSizing: "content-box" }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} shapeRendering="crispEdges">
        <rect width={size} height={size} fill="#fff" />
        {matrix.map((row, r) => row.map((on, c) => on && (
          <rect key={`${r}-${c}`} x={c * cellSize} y={r * cellSize} width={cellSize} height={cellSize} fill="#000" />
        )))}
      </svg>
    </div>
  );
}

window.LobbyScreen = LobbyScreen;
window.QRCode = QRCode;
