/* global React, Btn, Eyebrow, Display, Field, Wordmark, Monogram, FigureNum */
const { useState: useStateJoin, useEffect: useEffectJoin, useRef: useRefJoin } = React;

function savePlayerSession(code, playerId) {
  try { localStorage.setItem(`kwist.player.${code}`, playerId); } catch {}
}
function getSavedPlayerId(code) {
  try { return localStorage.getItem(`kwist.player.${code}`) || null; } catch { return null; }
}
function clearPlayerSession(code) {
  try { localStorage.removeItem(`kwist.player.${code}`); } catch {}
}

function JoinScreen({ theme, initialCode }) {
  const [phase, setPhase] = useStateJoin(initialCode ? "code" : "code");
  const [code, setCode] = useStateJoin((initialCode || "").toUpperCase());
  const [session, setSession] = useStateJoin(null);
  const [quiz, setQuiz] = useStateJoin(null);
  const [name, setName] = useStateJoin("");
  const [team, setTeam] = useStateJoin("");
  const [player, setPlayer] = useStateJoin(null);
  const [question, setQuestion] = useStateJoin(null);
  const [feedback, setFeedback] = useStateJoin(null);
  const [totalScore, setTotalScore] = useStateJoin(0);
  const [error, setError] = useStateJoin(null);
  const [busy, setBusy] = useStateJoin(false);
  const [rejoinAvailable, setRejoinAvailable] = useStateJoin(null);
  const wsRef = useRefJoin(null);
  const playerTokenRef = useRefJoin(null);
  const questionStartRef = useRefJoin(0);

  useEffectJoin(() => {
    if (initialCode) lookup(initialCode);
  }, []);

  const lookup = async (c) => {
    setError(null); setBusy(true);
    try {
      const res = await fetch(`/api/sessions/code/${encodeURIComponent(c)}`);
      if (!res.ok) {
        if (res.status === 404) throw new Error("Onbekende code.");
        throw new Error(`HTTP ${res.status}`);
      }
      const r = await res.json();
      setSession(r.session); setQuiz(r.quiz);
      const savedId = getSavedPlayerId(c.toUpperCase());
      if (savedId) {
        const savedPlayer = (r.players || []).find((p) => p.id === savedId);
        if (savedPlayer) {
          setRejoinAvailable(savedPlayer);
          setPhase("rejoin");
          return;
        } else {
          clearPlayerSession(c.toUpperCase());
        }
      }
      setPhase("name");
    } catch (e) {
      setError(e.message || "Kon de sessie niet vinden.");
    } finally {
      setBusy(false);
    }
  };

  const rejoin = async () => {
    if (!rejoinAvailable) return;
    setError(null); setBusy(true);
    try {
      const res = await fetch(`/api/sessions/${session.code}/rejoin`, {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ playerId: rejoinAvailable.id }),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({}));
        if (res.status === 404 || res.status === 409) {
          clearPlayerSession(session.code);
          setRejoinAvailable(null);
          setPhase("name");
          throw new Error(err.error || "Sessie niet meer beschikbaar.");
        }
        throw new Error(err.error || `HTTP ${res.status}`);
      }
      const r = await res.json();
      setPlayer(r.player);
      setTotalScore(r.player.score || 0);
      playerTokenRef.current = r.playerToken;
      openSocket(r.player.id);
      const status = r.session?.status || session?.status;
      if (status === "running") setPhase("playing");
      else if (status === "finished") setPhase("done");
      else setPhase("lobby");
    } catch (e) {
      setError(e.message || "Herverbinding mislukt.");
    } finally {
      setBusy(false);
    }
  };

  const joinAsNew = () => {
    clearPlayerSession(code);
    setRejoinAvailable(null);
    setPhase("name");
  };

  const join = async () => {
    if (!name.trim()) { setError("Naam invullen graag."); return; }
    setError(null); setBusy(true);
    try {
      const res = await fetch(`/api/sessions/${session.code}/join`, {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({
          name: name.trim(),
          team: session.teamsEnabled ? (team || null) : null,
        }),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({}));
        throw new Error(err.error || `HTTP ${res.status}`);
      }
      const r = await res.json();
      setPlayer(r.player);
      playerTokenRef.current = r.playerToken;
      savePlayerSession(session.code, r.player.id);
      openSocket(r.player?.id);
      setPhase("lobby");
    } catch (e) {
      setError(e.message || "Kon niet joinen.");
    } finally {
      setBusy(false);
    }
  };

  const openSocket = (pid) => {
    if (wsRef.current) return;
    const proto = window.location.protocol === "https:" ? "wss:" : "ws:";
    const ws = new WebSocket(`${proto}//${window.location.host}/ws/sessions/${session.code}`);
    wsRef.current = ws;
    ws.onopen = () => {
      // Announce presence so the host can see this player as online.
      try { ws.send(JSON.stringify({ type: "presence:hello", playerId: pid || null })); } catch {}
    };
    ws.onmessage = (ev) => {
      let msg = null;
      try { msg = JSON.parse(ev.data); } catch { return; }
      if (msg.type === "session:started") {
        setPhase("playing"); setQuestion(null); setFeedback(null);
      } else if (msg.type === "question:show" && msg.question) {
        setQuestion(msg.question);
        setFeedback(null);
        questionStartRef.current = Date.now();
        setPhase("playing");
      } else if (msg.type === "session:finished") {
        setPhase("done");
      }
    };
    ws.onclose = () => { wsRef.current = null; };
  };

  const submit = async (answer) => {
    if (!question) return;
    const msTaken = Date.now() - (questionStartRef.current || Date.now());
    setFeedback({ pending: true });
    try {
      // Direct fetch met het player-token — niet via window.kwistApi om geen
      // host-state te verstoren.
      const res = await fetch(`/api/sessions/${session.code}/answer`, {
        method: "POST",
        headers: {
          "content-type": "application/json",
          authorization: `Bearer ${playerTokenRef.current}`,
        },
        body: JSON.stringify({ questionId: question.id, answer, msTaken }),
      });
      const r = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(r.error || `HTTP ${res.status}`);
      if (r.correct && r.points) setTotalScore((s) => s + r.points);
      setFeedback({ correct: r.correct, points: r.points });
    } catch (e) {
      setFeedback({ error: e.message });
    }
  };

  return (
    <div style={{
      minHeight: "100vh",
      background: theme.bg,
      display: "flex", flexDirection: "column",
      alignItems: "center",
      padding: "32px 20px",
    }}>
      <Wordmark size={140} />
      <Eyebrow theme={theme} style={{ marginTop: 6 }}>── DOE MEE</Eyebrow>

      <div style={{ width: "100%", maxWidth: 460, marginTop: 36 }}>
        {phase === "code" && (
          <CodeStep theme={theme} code={code} setCode={setCode} onSubmit={() => lookup(code)} busy={busy} error={error} />
        )}
        {phase === "rejoin" && rejoinAvailable && (
          <RejoinStep theme={theme} player={rejoinAvailable} quiz={quiz} onRejoin={rejoin} onJoinNew={joinAsNew} busy={busy} error={error} />
        )}
        {phase === "name" && session && (
          <NameStep theme={theme} session={session} quiz={quiz} name={name} setName={setName} team={team} setTeam={setTeam} onSubmit={join} busy={busy} error={error} />
        )}
        {phase === "lobby" && (
          <LobbyWait theme={theme} player={player} quiz={quiz} />
        )}
        {phase === "playing" && (
          <Playing theme={theme} question={question} feedback={feedback} totalScore={totalScore} onSubmit={submit} />
        )}
        {phase === "done" && (
          <Done theme={theme} player={player} totalScore={totalScore} />
        )}
      </div>
    </div>
  );
}

function CodeStep({ theme, code, setCode, onSubmit, busy, error }) {
  return (
    <div>
      <Display theme={theme} size={56}>De code,<br/><span style={{ color: theme.accent }}>graag</span>.</Display>
      <p style={{ color: theme.fgDim, fontSize: 15, lineHeight: 1.55, marginTop: 14 }}>
        Hij staat op het scherm van de host. Vier letters, soms cijfers.
      </p>
      <form onSubmit={(e) => { e.preventDefault(); onSubmit(); }} style={{ marginTop: 28 }}>
        <input
          autoFocus
          value={code}
          onChange={(e) => setCode(e.target.value.toUpperCase())}
          placeholder="KW-XXXX"
          style={{
            width: "100%",
            background: "transparent", color: theme.fg,
            border: "none", borderBottom: `1px solid ${theme.rule}`,
            padding: "12px 0",
            fontFamily: theme.fonts.display, fontSize: 56,
            outline: "none", letterSpacing: "0.04em",
          }}
        />
        {error && <Eyebrow theme={theme} style={{ color: theme.accent, marginTop: 10 }}>{error}</Eyebrow>}
        <Btn theme={theme} size="lg" type="submit" onClick={onSubmit} disabled={busy} style={{ width: "100%", justifyContent: "center", marginTop: 24, opacity: busy ? 0.6 : 1 }}>
          {busy ? "Even kijken…" : "Verder"} <span style={{ fontFamily: theme.fonts.display }}>→</span>
        </Btn>
      </form>
    </div>
  );
}

function RejoinStep({ theme, player, quiz, onRejoin, onJoinNew, busy, error }) {
  return (
    <div style={{ textAlign: "center" }}>
      <Monogram theme={theme} text={player.initials} size={64} color={theme.accent} />
      <Display theme={theme} size={42} style={{ marginTop: 16 }}>Welkom terug!</Display>
      <p style={{ color: theme.fgDim, fontSize: 15, lineHeight: 1.55, marginTop: 12 }}>
        Je was al ingeschreven als <b style={{ color: theme.fg }}>{player.name}</b>.
        Wil je herverbinden met je bestaande score?
      </p>
      <div style={{
        marginTop: 20, padding: "14px 20px",
        border: `1px solid ${theme.rule}`,
        display: "inline-block",
      }}>
        <Eyebrow theme={theme}>── HUIDIGE SCORE</Eyebrow>
        <FigureNum theme={theme} size={48} accent>{(player.score || 0).toLocaleString("nl-NL")}</FigureNum>
      </div>
      {error && <Eyebrow theme={theme} style={{ color: theme.accent, marginTop: 10, display: "block" }}>{error}</Eyebrow>}
      <div style={{ marginTop: 24, display: "flex", flexDirection: "column", gap: 10 }}>
        <Btn theme={theme} size="lg" onClick={onRejoin} disabled={busy} style={{ width: "100%", justifyContent: "center", opacity: busy ? 0.6 : 1 }}>
          {busy ? "Herverbinden..." : "Herverbinden als " + player.name} <span style={{ fontFamily: theme.fonts.display }}>→</span>
        </Btn>
        <Btn theme={theme} variant="outline" onClick={onJoinNew} disabled={busy} style={{ width: "100%", justifyContent: "center" }}>
          Nee, ik wil opnieuw joinen
        </Btn>
      </div>
    </div>
  );
}

function NameStep({ theme, session, quiz, name, setName, team, setTeam, onSubmit, busy, error }) {
  const teams = ["De Slimmeriken", "Kennistycoons", "Brain Storm", "Q-Force"];
  return (
    <div>
      <Eyebrow theme={theme} style={{ color: theme.accent }}>── {(quiz?.category || "QUIZ").toUpperCase()}</Eyebrow>
      <Display theme={theme} size={48} style={{ marginTop: 6 }}>{quiz?.title || "Quiz"}</Display>
      <p style={{ color: theme.fgDim, fontSize: 14, marginTop: 10 }}>
        Sessie {session.code} · status: <b style={{ color: theme.fg }}>{session.status}</b>
      </p>

      <form onSubmit={(e) => { e.preventDefault(); onSubmit(); }} style={{ marginTop: 28, display: "flex", flexDirection: "column", gap: 22 }}>
        <Field theme={theme} label="Hoe heet je?" value={name} onChange={setName} placeholder="Bijv. Floor" autoFocus />
        {session.teamsEnabled && (
          <div>
            <Eyebrow theme={theme} style={{ marginBottom: 8 }}>── Kies een team</Eyebrow>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
              {teams.map((t) => (
                <button key={t} type="button" onClick={() => setTeam(t)} style={{
                  background: team === t ? theme.fg : "transparent",
                  color: team === t ? theme.bg : theme.fg,
                  border: `1px solid ${team === t ? theme.fg : theme.rule}`,
                  padding: "10px 12px", cursor: "pointer",
                  fontFamily: theme.fonts.display, fontSize: 14, textAlign: "left",
                }}>{t}</button>
              ))}
            </div>
          </div>
        )}
        {error && <Eyebrow theme={theme} style={{ color: theme.accent }}>{error}</Eyebrow>}
        <Btn theme={theme} size="lg" type="submit" onClick={onSubmit} disabled={busy} style={{ width: "100%", justifyContent: "center", opacity: busy ? 0.6 : 1 }}>
          {busy ? "Joinen…" : "Doe mee"} <span style={{ fontFamily: theme.fonts.display }}>→</span>
        </Btn>
      </form>
    </div>
  );
}

function LobbyWait({ theme, player, quiz }) {
  return (
    <div style={{ textAlign: "center" }}>
      <Monogram theme={theme} text={player?.initials || "??"} size={64} color={theme.accent} />
      <Display theme={theme} size={42} style={{ marginTop: 16 }}>Je staat erin.</Display>
      <p style={{ color: theme.fgDim, fontSize: 15, lineHeight: 1.55, marginTop: 12 }}>
        Welkom <b style={{ color: theme.fg }}>{player?.name}</b>. We wachten tot de host op start drukt.
      </p>
      <div style={{ marginTop: 28, padding: 14, border: `1px dashed ${theme.rule}`, fontFamily: theme.fonts.mono, fontSize: 12, color: theme.fgDim, letterSpacing: "0.1em" }}>
        QUIZ · {(quiz?.title || "").toUpperCase()}<br/>
        VRAGEN: {quiz?.questions || "—"}
      </div>
      <div style={{ marginTop: 24, display: "inline-flex", alignItems: "center", gap: 8 }}>
        <span style={{ width: 8, height: 8, background: theme.accent, borderRadius: "50%", animation: "blink 1s infinite" }} />
        <Eyebrow theme={theme} style={{ color: theme.accent }}>WACHTEN OP DE HOST</Eyebrow>
      </div>
      <style>{`@keyframes blink { 50% { opacity: 0.3 } }`}</style>
    </div>
  );
}

function Playing({ theme, question, feedback, totalScore, onSubmit }) {
  if (!question) {
    return (
      <div style={{ textAlign: "center" }}>
        <Display theme={theme} size={36}>De quiz is begonnen.</Display>
        <Eyebrow theme={theme} style={{ marginTop: 12 }}>WACHTEN OP DE EERSTE VRAAG…</Eyebrow>
      </div>
    );
  }
  if (feedback && (feedback.correct !== undefined || feedback.error)) {
    return (
      <div style={{ textAlign: "center" }}>
        {feedback.correct ? (
          <>
            <FigureNum theme={theme} size={120} accent>✓</FigureNum>
            <Display theme={theme} size={36} style={{ marginTop: 8 }}>Juist!</Display>
            <Eyebrow theme={theme} style={{ marginTop: 10, color: theme.accent }}>+ {feedback.points} PUNTEN</Eyebrow>
          </>
        ) : feedback.error ? (
          <Eyebrow theme={theme} style={{ color: theme.accent }}>{feedback.error}</Eyebrow>
        ) : (
          <>
            <FigureNum theme={theme} size={120}>✕</FigureNum>
            <Display theme={theme} size={36} style={{ marginTop: 8 }}>Helaas.</Display>
          </>
        )}
        <div style={{
          marginTop: 24, padding: "14px 20px",
          border: `1px solid ${theme.rule}`,
          display: "inline-block",
        }}>
          <Eyebrow theme={theme}>── JOUW SCORE</Eyebrow>
          <FigureNum theme={theme} size={48} accent>{(totalScore || 0).toLocaleString("nl-NL")}</FigureNum>
        </div>
        <div style={{ marginTop: 12 }}>
          <Eyebrow theme={theme} style={{ color: theme.fgDim }}>Wachten op de volgende vraag…</Eyebrow>
        </div>
      </div>
    );
  }
  return (
    <div>
      <Eyebrow theme={theme} style={{ color: theme.accent }}>── VRAAG {question.position + 1}</Eyebrow>
      <Display theme={theme} size={36} style={{ marginTop: 6 }}>{question.prompt}</Display>
      <div style={{ marginTop: 24, display: "flex", flexDirection: "column", gap: 10 }}>
        {question.type === "mc" && (question.options || []).map((opt, i) => (
          <button key={opt.id || i} onClick={() => onSubmit(opt.id || opt.text)} disabled={feedback?.pending} style={{
            padding: "16px 18px",
            border: `1px solid ${theme.rule}`,
            background: theme.bg,
            color: theme.fg,
            cursor: "pointer",
            textAlign: "left",
            fontFamily: theme.fonts.body, fontSize: 16,
          }}>
            <span style={{ fontFamily: theme.fonts.mono, marginRight: 12, color: theme.fgDim }}>{String.fromCharCode(65 + i)}.</span>
            {opt.text}
          </button>
        ))}
        {question.type === "tf" && ["waar", "niet waar"].map((v) => (
          <button key={v} onClick={() => onSubmit(v)} disabled={feedback?.pending} style={{
            padding: "16px 18px",
            border: `1px solid ${theme.rule}`,
            background: theme.bg, color: theme.fg, cursor: "pointer",
            fontFamily: theme.fonts.display, fontSize: 22, textTransform: "uppercase",
          }}>{v}</button>
        ))}
        {question.type === "open" && (
          <OpenInput theme={theme} onSubmit={onSubmit} disabled={feedback?.pending} />
        )}
      </div>
      {feedback?.pending && <Eyebrow theme={theme} style={{ marginTop: 12 }}>VERZENDEN…</Eyebrow>}
    </div>
  );
}

function OpenInput({ theme, onSubmit, disabled }) {
  const [val, setVal] = useStateJoin("");
  return (
    <form onSubmit={(e) => { e.preventDefault(); if (val.trim()) onSubmit(val.trim()); }}>
      <input
        autoFocus
        value={val}
        onChange={(e) => setVal(e.target.value)}
        disabled={disabled}
        placeholder="Tik je antwoord…"
        style={{
          width: "100%",
          background: "transparent", color: theme.fg,
          border: "none", borderBottom: `1px solid ${theme.rule}`,
          padding: "12px 0", fontFamily: theme.fonts.display, fontSize: 28,
          outline: "none",
        }}
      />
      <Btn theme={theme} size="lg" type="submit" disabled={!val.trim() || disabled} style={{ width: "100%", justifyContent: "center", marginTop: 16, opacity: !val.trim() ? 0.6 : 1 }}>
        Insturen <span style={{ fontFamily: theme.fonts.display }}>→</span>
      </Btn>
    </form>
  );
}

function Done({ theme, player, totalScore }) {
  return (
    <div style={{ textAlign: "center" }}>
      <Display theme={theme} size={56}>Tot de volgende!</Display>
      <div style={{
        marginTop: 24, padding: "18px 24px",
        border: `1px solid ${theme.rule}`,
        display: "inline-block",
      }}>
        <Eyebrow theme={theme}>── JOUW EINDSCORE</Eyebrow>
        <FigureNum theme={theme} size={64} accent>{(totalScore || player?.score || 0).toLocaleString("nl-NL")}</FigureNum>
      </div>
    </div>
  );
}

window.JoinScreen = JoinScreen;
