/* Hamlet — Review & Self-Test · React app */

const { useState, useEffect, useMemo, useCallback, useRef } = React;
const DATA = window.HAMLET_DATA;
const QUIZ_DEFS = {
  play:    { label: "Whole Play", short: "PLAY", count: 50 },
  insight: { label: "Insight",    short: "INS",  count: 30 },
  act1:    { label: "Act I",   short: "I",   count: 99, act: 1 },
  act2:    { label: "Act II",  short: "II",  count: 99, act: 2 },
  act3:    { label: "Act III", short: "III", count: 99, act: 3 },
  act4:    { label: "Act IV",  short: "IV",  count: 99, act: 4 },
  act5:    { label: "Act V",   short: "V",   count: 99, act: 5 },
};
const modeLabel = (m) => (QUIZ_DEFS[m] ? QUIZ_DEFS[m].label : m);
const modeShort = (m) => (QUIZ_DEFS[m] ? QUIZ_DEFS[m].short : m);
function bankFor(mode) {
  if (mode === "play") return [1,2,3,4,5].reduce((a,n) => a.concat(DATA.quiz.acts[n]), []);
  if (mode === "insight") return DATA.quiz.insight;
  return DATA.quiz.acts[QUIZ_DEFS[mode].act];
}

// ─── Firebase (leaderboard + stats) ───────────────────────────
const FB_CFG = window.FIREBASE_CONFIG || {};
const FB_READY = !!window.firebase && !!FB_CFG.apiKey && FB_CFG.apiKey !== "PASTE_API_KEY";

let _db = null;
function db() {
  if (!FB_READY) return null;
  if (_db) return _db;
  if (!firebase.apps.length) firebase.initializeApp(FB_CFG);
  _db = firebase.firestore();
  return _db;
}
const SCORES = () => db().collection("hamlet_scores");
const HSTATS = () => db().collection("hamlet_stats").doc("global");

async function fetchLeaderboard() {
  if (!FB_READY) return null;
  try {
    const snap = await SCORES().orderBy("pct", "desc").limit(50).get();
    const rows = snap.docs.map((d) => ({ id: d.id, ...d.data() }));
    rows.sort((a, b) => (b.pct - a.pct) || ((a.ts?.seconds || 0) - (b.ts?.seconds || 0)));
    return rows;
  } catch (e) { console.warn("leaderboard read failed", e); return null; }
}
async function fetchStats() {
  if (!FB_READY) return null;
  try {
    const snap = await HSTATS().get();
    return snap.exists ? snap.data() : { totalAttempts: 0, scoreSumPct: 0 };
  } catch (e) { console.warn("stats read failed", e); return null; }
}
// Write the row, then roll the aggregate so it satisfies the Firestore rules
// (totalAttempts only ever rises by 1).
async function submitScore({ name, pct, correct, total, mode }) {
  if (!FB_READY) return null;
  try {
    const ref = await SCORES().add({
      name, pct, correct, total, mode,
      ts: firebase.firestore.FieldValue.serverTimestamp(),
    });
    const sref = HSTATS();
    await db().runTransaction(async (t) => {
      const snap = await t.get(sref);
      const cur = snap.exists ? snap.data() : { totalAttempts: 0, scoreSumPct: 0 };
      const next = {
        totalAttempts: (cur.totalAttempts || 0) + 1,
        scoreSumPct: (cur.scoreSumPct || 0) + pct,
      };
      if (snap.exists) t.update(sref, next); else t.set(sref, next);
    });
    return ref.id;
  } catch (e) { console.warn("score write failed", e); return null; }
}

// ─── helpers ──────────────────────────────────────────────────
function shuffle(arr) {
  const a = arr.slice();
  for (let i = a.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [a[i], a[j]] = [a[j], a[i]]; }
  return a;
}
function pad(n) { return String(n).padStart(2, "0"); }
function fmtDate(ts) {
  if (!ts || !ts.seconds) return "—";
  return new Date(ts.seconds * 1000).toLocaleDateString("en-CA", { month: "short", day: "numeric" });
}
// Real-name entry (no login). Two-tier screen so legitimate names aren't blocked:
// long unambiguous strings match anywhere; short fragments must be a standalone
// word (so "Cassidy", "Titus", "Dickens" pass). Teacher still moderates via console.
const BAD_SUBSTR = ["fuck","fuk","fck","shit","cunt","nigger","nigga","faggot","pussy","whore","penis","vagina","asshole","bitch","bastard","dildo"];
const BAD_WORD = ["fag","kkk","nazi","rape","dick","cock","cum","sex","hoe","tit"];
function cleanName(raw) {
  return (raw || "").replace(/[^A-Za-z '\-]/g, "").replace(/\s{2,}/g, " ").replace(/^\s+/, "").slice(0, 20);
}
function isBad(name) {
  const l = name.toLowerCase();
  if (BAD_SUBSTR.some((w) => l.includes(w))) return true;
  const toks = l.split(/[^a-z]+/).filter(Boolean);
  return BAD_WORD.some((w) => toks.includes(w));
}

// Build a quiz: pick N questions for the mode, shuffle each question's options.
function buildQuiz(mode) {
  const bank = shuffle(bankFor(mode));
  const n = Math.min(QUIZ_DEFS[mode].count, bank.length);
  return bank.slice(0, n).map((item) => ({
    prompt: item.q,
    answer: item.answer,
    explain: item.explain,
    options: shuffle(item.options),
  }));
}

// ─── Top mode switch (Reference vs Self-Test) ─────────────────
function ModeSwitch({ view, setView }) {
  return (
    <div className="mode-switch">
      <button className={"ms-btn" + (view === "reference" ? " on" : "")} onClick={() => setView("reference")}>
        <span className="ms-n">01</span><span className="ms-l">Review</span>
      </button>
      <button className={"ms-btn" + (view === "quiz" ? " on" : "")} onClick={() => setView("quiz")}>
        <span className="ms-n">02</span><span className="ms-l">Self-Test</span>
      </button>
    </div>
  );
}

// ─── Reference (the review guide) ─────────────────────────────
const REF_TABS = [
  ["story", "The Play"],
  ["characters", "Characters"],
  ["relationships", "Relationships"],
  ["themes", "Themes & Motifs"],
  ["quotes", "Key Lines"],
];

function ReferenceView() {
  const [tab, setTab] = useState("story");
  const [zoom, setZoom] = useState(null);
  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") setZoom(null); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);
  return (
    <div className="ref-wrap">
      <div className="subtabs">
        {REF_TABS.map(([id, label]) => (
          <button key={id} className={"subtab" + (tab === id ? " on" : "")} onClick={() => setTab(id)}>{label}</button>
        ))}
      </div>

      {tab === "story" && (
        <div className="ref-section">
          {DATA.acts.map((a) => (
            <div className="act-card" key={a.n}>
              {a.img && (
                <img className="act-poster" src={a.img} alt={"Act " + a.roman + " — " + a.title} loading="lazy" onClick={() => setZoom(a.img)} />
              )}
              <div className="act-body">
                <div className="act-head"><span className="act-roman">Act {a.roman}</span><h3 className="act-title">{a.title}</h3></div>
                <p className="act-summary">{a.summary}</p>
                <ul className="act-beats">{a.beats.map((b, i) => <li key={i}>{b}</li>)}</ul>
                {a.watch && <div className="act-watch"><span className="aw-lab">What to watch for</span> {a.watch}</div>}
              </div>
            </div>
          ))}
        </div>
      )}

      {tab === "characters" && (
        <div className="char-grid">
          {DATA.characters.map((c) => (
            <div className="char-card" key={c.id}>
              <div className="char-name">{c.name}</div>
              <div className="char-role">{c.role}</div>
              <div className="char-traits">{c.traits}</div>
              <p className="char-note">{c.note}</p>
              <div className="char-quote">“{c.quote}”</div>
            </div>
          ))}
        </div>
      )}

      {tab === "relationships" && (
        <div className="ref-section">
          {DATA.relationships.map((r, i) => (
            <div className="rel-row" key={i}><div className="rel-pair">{r.pair}</div><p className="rel-note">{r.note}</p></div>
          ))}
        </div>
      )}

      {tab === "themes" && (
        <div className="ref-section">
          <div className="theme-grid">
            {DATA.themes.map((t) => (
              <div className="theme-card" key={t.id}>
                <div className="theme-name">{t.name}</div>
                <p className="theme-blurb">{t.blurb}</p>
                <div className="theme-ev"><span className="ev-lab">In the play</span> {t.evidence}</div>
              </div>
            ))}
          </div>
          <div className="motif-block">
            <div className="motif-head">Motifs &amp; symbols</div>
            {DATA.motifs.map((m, i) => (
              <div className="motif-row" key={i}><span className="motif-name">{m.name}</span><span className="motif-mean">{m.meaning}</span></div>
            ))}
          </div>
        </div>
      )}

      {tab === "quotes" && (
        <div className="quote-grid">
          {DATA.quotes.map((q, i) => (
            <div className="quote-card" key={i}>
              <div className="quote-line">“{q.line}”</div>
              <div className="quote-attr"><span className="quote-sp">{q.speaker}</span><span className="quote-where">{q.where}</span></div>
              <div className="quote-sig">{q.sig}</div>
            </div>
          ))}
        </div>
      )}

      {zoom && (
        <div className="poster-lightbox" onClick={() => setZoom(null)}>
          <img src={zoom} alt="" onClick={(e) => e.stopPropagation()} />
          <button className="pl-close" onClick={() => setZoom(null)}>✕&nbsp;ESC</button>
        </div>
      )}
    </div>
  );
}

// ─── Leaderboard ──────────────────────────────────────────────
function Leaderboard({ rows, stats, loading, highlightId }) {
  const [filter, setFilter] = useState("all");
  if (!FB_READY) return null;
  const filtered = (rows || []).filter((r) => filter === "all" || (filter === "acts" ? String(r.mode).indexOf("act") === 0 : r.mode === filter)).slice(0, 20);
  const avg = stats && stats.totalAttempts ? Math.round(stats.scoreSumPct / stats.totalAttempts) : null;
  return (
    <div className="lb">
      <div className="lb-head">
        <span className="lb-title">LEADERBOARD</span>
        <div className="lb-filters">
          {["all", "play", "insight", "acts"].map((f) => (
            <button key={f} className={"lb-filter" + (filter === f ? " on" : "")} onClick={() => setFilter(f)}>
              {f.toUpperCase()}
            </button>
          ))}
        </div>
      </div>
      {stats && stats.totalAttempts > 0 && (
        <div className="lb-stats"><span>{stats.totalAttempts} attempts</span>{avg != null && <span>· class average {avg}%</span>}</div>
      )}
      {loading && <div className="lb-loading">loading…</div>}
      {!loading && filtered.length === 0 && <div className="lb-empty">No scores yet — be the first.</div>}
      {!loading && filtered.length > 0 && (
        <div className="lb-rows">
          {filtered.map((r, i) => (
            <div className={"lb-row" + (r.id === highlightId ? " me" : "")} key={r.id}>
              <span className="lb-rank">{pad(i + 1)}</span>
              <span className="lb-name">{r.name}</span>
              <span className="lb-mode">{modeShort(r.mode)}</span>
              <span className="lb-date">{fmtDate(r.ts)}</span>
              <span className="lb-pct">{r.pct}%</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ─── Self-Test ────────────────────────────────────────────────
function QuizView() {
  const [phase, setPhase] = useState("setup");
  const [mode, setMode] = useState("knowledge");
  const [quiz, setQuiz] = useState([]);
  const [idx, setIdx] = useState(0);
  const [picked, setPicked] = useState(null);
  const [answers, setAnswers] = useState([]);
  const [rows, setRows] = useState(null);
  const [stats, setStats] = useState(null);
  const [lbLoading, setLbLoading] = useState(false);
  const [initials, setInitials] = useState("");
  const [submitState, setSubmitState] = useState("idle");
  const [myId, setMyId] = useState(null);

  const loadBoard = useCallback(async () => {
    if (!FB_READY) return;
    setLbLoading(true);
    const [r, s] = await Promise.all([fetchLeaderboard(), fetchStats()]);
    if (r) setRows(r); if (s) setStats(s);
    setLbLoading(false);
  }, []);
  useEffect(() => { loadBoard(); }, [loadBoard]);

  const start = (m) => {
    setMode(m); setQuiz(buildQuiz(m)); setIdx(0); setPicked(null); setAnswers([]);
    setInitials(""); setSubmitState("idle"); setMyId(null); setPhase("playing");
  };
  const choose = (opt) => {
    if (picked != null) return;
    setPicked(opt);
    const cur = quiz[idx];
    setAnswers((a) => [...a, { prompt: cur.prompt, answer: cur.answer, explain: cur.explain, chosen: opt, correct: opt === cur.answer }]);
  };
  const next = () => { if (idx + 1 < quiz.length) { setIdx(idx + 1); setPicked(null); } else setPhase("results"); };

  const correctCount = answers.filter((a) => a.correct).length;
  const pct = quiz.length ? Math.round((correctCount / quiz.length) * 100) : 0;

  const doSubmit = async () => {
    const name = cleanName(initials).trim();
    if (name.length < 2) { setSubmitState("short"); return; }
    if (isBad(name)) { setSubmitState("bad"); return; }
    setSubmitState("saving");
    const id = await submitScore({ name, pct, correct: correctCount, total: quiz.length, mode });
    if (id) { setMyId(id); setSubmitState("done"); await loadBoard(); } else setSubmitState("error");
  };

  if (phase === "setup") {
    const acts = [["act1", "Act I"], ["act2", "Act II"], ["act3", "Act III"], ["act4", "Act IV"], ["act5", "Act V"]];
    return (
      <div className="quiz-wrap">
        <div className="setup-intro">
          <h3 className="setup-title">Test yourself on Hamlet.</h3>
          <p className="setup-sub">Quiz a single act, the whole play, or the big ideas. Questions are drawn fresh each time — no login. Post your score to the leaderboard with your initials.</p>
        </div>
        <div className="setup-group">
          <div className="sg-head">The whole play</div>
          <div className="level-cards">
            <button className="level-card" onClick={() => start("play")}>
              <span className="lc-tag">{QUIZ_DEFS.play.count} QUESTIONS</span><span className="lc-name">Whole Play</span>
              <span className="lc-desc">Plot, characters, and key moments drawn from all five acts. The full review.</span>
              <span className="lc-go">BEGIN →</span>
            </button>
            <button className="level-card adv" onClick={() => start("insight")}>
              <span className="lc-tag">{QUIZ_DEFS.insight.count} QUESTIONS</span><span className="lc-name">Insight</span>
              <span className="lc-desc">Themes, motifs, and the meaning behind the famous lines. Exam-level.</span>
              <span className="lc-go">BEGIN →</span>
            </button>
          </div>
        </div>
        <div className="setup-group">
          <div className="sg-head">By act <span className="sg-sub">— focused review, one act at a time</span></div>
          <div className="act-cards">
            {acts.map(([id, label]) => (
              <button key={id} className="act-btn" onClick={() => start(id)}>
                <span className="ab-label">{label}</span>
                <span className="ab-n">{DATA.quiz.acts[QUIZ_DEFS[id].act].length} Q</span>
              </button>
            ))}
          </div>
        </div>
        <Leaderboard rows={rows} stats={stats} loading={lbLoading} highlightId={myId} />
      </div>
    );
  }

  if (phase === "results") {
    const missed = answers.filter((a) => !a.correct);
    const grade = pct >= 90 ? "EXCELLENT" : pct >= 75 ? "STRONG" : pct >= 50 ? "GETTING THERE" : "KEEP STUDYING";
    return (
      <div className="quiz-wrap">
        <div className="results">
          <div className="res-score-card">
            <div className="ex-rec res-rec"><span className="rec-dot" /><span className="rec-text">RESULT</span></div>
            <div className="res-pct">{pct}<span className="res-pct-sm">%</span></div>
            <div className="res-frac">{correctCount} / {quiz.length} correct</div>
            <div className="res-grade">{grade}</div>
            <div className="res-mode">{modeLabel(mode)}</div>
          </div>

          {FB_READY && (
            <div className="submit-box">
              {submitState !== "done" ? (
                <div className="submit-row">
                  <label className="submit-lab">POST TO LEADERBOARD</label>
                  <div className="submit-input-row">
                    <input className="initials-input" value={initials}
                      onChange={(e) => { setInitials(cleanName(e.target.value)); if (submitState !== "saving") setSubmitState("idle"); }}
                      placeholder="Your first name" maxLength={20} aria-label="Your name" />
                    <button className="btn-primary" onClick={doSubmit} disabled={submitState === "saving"}>
                      {submitState === "saving" ? "SAVING…" : "SUBMIT"}
                    </button>
                  </div>
                  <div className="submit-hint">
                    {submitState === "short" && <span className="warnmsg">Enter your name (2+ letters).</span>}
                    {submitState === "bad" && <span className="warnmsg">Please choose a different name.</span>}
                    {submitState === "error" && <span className="warnmsg">Couldn’t save — try again.</span>}
                    {submitState === "idle" && <span>Shown publicly on the leaderboard.</span>}
                  </div>
                </div>
              ) : (
                <div className="submit-done">✓ Posted as <strong>{cleanName(initials)}</strong> — you’re on the board.</div>
              )}
            </div>
          )}

          {missed.length > 0 && (
            <div className="res-review">
              <div className="rr-head">REVIEW · {missed.length} missed</div>
              {missed.map((a, i) => (
                <div className="rr-row" key={i}>
                  <div className="rr-q">{a.prompt}</div>
                  <div className="rr-correct"><span className="rr-tick">✓</span><span className="rr-name">{a.answer}</span></div>
                  <div className="rr-wrong">you chose <span>{a.chosen}</span></div>
                  {a.explain && <div className="rr-explain">{a.explain}</div>}
                </div>
              ))}
            </div>
          )}
          {missed.length === 0 && <div className="res-perfect">Perfect — every question right.</div>}

          <div className="res-actions">
            <button className="btn-primary" onClick={() => start(mode)}>RETAKE · {modeLabel(mode).toUpperCase()}</button>
            <button className="btn-ghost" onClick={() => setPhase("setup")}>← ALL QUIZZES</button>
          </div>
          <Leaderboard rows={rows} stats={stats} loading={lbLoading} highlightId={myId} />
        </div>
      </div>
    );
  }

  const cur = quiz[idx];
  const answered = picked != null;
  return (
    <div className="quiz-wrap">
      <div className="quiz-play">
        <div className="qp-head">
          <button className="back-btn" onClick={() => setPhase("setup")}><span className="arr">←</span><span>END</span></button>
          <div className="qp-meta"><span className="qp-mode">{modeLabel(mode).toUpperCase()}</span><span className="qp-count">{pad(idx + 1)} / {pad(quiz.length)}</span></div>
        </div>
        <div className="qp-progress"><div className="qp-progress-fill" style={{ width: `${(idx / quiz.length) * 100}%` }} /></div>
        <div className="qp-evidence"><p className="qp-prompt">{cur.prompt}</p></div>
        <div className="qp-options stack">
          {cur.options.map((opt) => {
            let cls = "opt";
            if (answered) {
              if (opt === cur.answer) cls += " correct";
              else if (opt === picked) cls += " wrong";
              else cls += " dim";
            }
            return (
              <button key={opt} className={cls} disabled={answered} onClick={() => choose(opt)}>
                <span className="opt-name">{opt}</span>
                {answered && opt === cur.answer && <span className="opt-ic">✓</span>}
                {answered && opt === picked && opt !== cur.answer && <span className="opt-ic">✕</span>}
              </button>
            );
          })}
        </div>
        {answered && (
          <div className="qp-feedback">
            {cur.explain && <p className="qp-fb-def">{cur.explain}</p>}
            <button className="btn-primary qp-next" onClick={next}>{idx + 1 < quiz.length ? "NEXT →" : "SEE RESULTS →"}</button>
          </div>
        )}
      </div>
    </div>
  );
}

// ─── App ──────────────────────────────────────────────────────
function App() {
  const [view, setView] = useState("reference");
  return (
    <div>
      <ModeSwitch view={view} setView={setView} />
      {view === "reference" ? <ReferenceView /> : <QuizView />}
    </div>
  );
}
ReactDOM.createRoot(document.getElementById("hamlet-root")).render(<App />);
