/* The Literary Device — React app */

const { useState, useEffect, useMemo, useCallback, useRef } = React;
const DATA = window.DEVICES_DATA;
const ALL = DATA.devices;
const BY_ID = Object.fromEntries(ALL.map((d) => [d.id, d]));
const QUESTIONS_PER_QUIZ = 25;

// ─── Firebase (optional global 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 STATS_DOC = () => db().collection("litdevice").doc("global");

async function fetchStats() {
  if (!FB_READY) return null;
  try {
    const snap = await STATS_DOC().get();
    return snap.exists ? snap.data() : { totalQuizzes: 0, scoreSumPct: 0, misidentified: {} };
  } catch (e) {
    console.warn("stats read failed", e);
    return null;
  }
}

// Record a finished quiz. Done in a transaction so concurrent takers don't
// clobber each other, and so values satisfy the Firestore rules (totalQuizzes
// only ever rises by exactly 1).
async function recordResult(scorePct, wrongIds) {
  if (!FB_READY) return null;
  try {
    const ref = STATS_DOC();
    return await db().runTransaction(async (t) => {
      const snap = await t.get(ref);
      const cur = snap.exists
        ? snap.data()
        : { totalQuizzes: 0, scoreSumPct: 0, misidentified: {} };
      const mis = Object.assign({}, cur.misidentified || {});
      wrongIds.forEach((id) => { mis[id] = (mis[id] || 0) + 1; });
      const next = {
        totalQuizzes: (cur.totalQuizzes || 0) + 1,
        scoreSumPct: (cur.scoreSumPct || 0) + scorePct,
        misidentified: mis,
      };
      if (snap.exists) t.update(ref, next);
      else t.set(ref, next);
      return next;
    });
  } catch (e) {
    console.warn("stats 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 buildQuiz(mode) {
  const pool = mode === "beginner" ? ALL.filter((d) => d.level === "beginner") : ALL;
  const n = QUESTIONS_PER_QUIZ;

  // Build a device sequence of length n. If the pool is smaller than n
  // (Beginner has 15 devices), cycle through reshuffled bags so devices repeat
  // — but never the same device twice in a row.
  const seq = [];
  let bag = [];
  while (seq.length < n) {
    if (!bag.length) {
      bag = shuffle(pool);
      if (seq.length && bag.length > 1 && bag[0].id === seq[seq.length - 1].id) {
        [bag[0], bag[1]] = [bag[1], bag[0]];
      }
    }
    seq.push(bag.shift());
  }

  const seen = {};
  return seq.map((dev) => {
    const k = (seen[dev.id] = (seen[dev.id] || 0) + 1);
    // rotate to the alternate example when a device comes up again
    const prompt = dev.quiz[(k - 1) % dev.quiz.length];
    // distractors: prefer same channel, then anyone else
    const sameGroup = shuffle(pool.filter((d) => d.id !== dev.id && d.group === dev.group));
    const others = shuffle(pool.filter((d) => d.id !== dev.id && d.group !== dev.group));
    const distractors = sameGroup.concat(others).slice(0, 3);
    const options = shuffle([dev, ...distractors]).map((d) => d.id);
    return { deviceId: dev.id, prompt, options };
  });
}

// ─── Mode switch (Reference / Self-Test) ──────────────────────
function ModeSwitch({ view, setView }) {
  return (
    <div className="mode-switch">
      <button
        className={`mode-tab ${view === "reference" ? "active" : ""}`}
        onClick={() => setView("reference")}
      >
        <span className="mode-idx">01</span>
        <span className="mode-label">Reference</span>
        <span className="mode-desc">Every device, defined</span>
      </button>
      <button
        className={`mode-tab ${view === "quiz" ? "active" : ""}`}
        onClick={() => setView("quiz")}
      >
        <span className="mode-idx">02</span>
        <span className="mode-label">Self-Test</span>
        <span className="mode-desc">Identify the device</span>
      </button>
    </div>
  );
}

// ─── Reference view ───────────────────────────────────────────
function ReferenceView() {
  const [group, setGroup] = useState("all");
  const [q, setQ] = useState("");

  const filtered = useMemo(() => {
    const needle = q.trim().toLowerCase();
    return ALL.filter((d) => {
      if (group !== "all" && d.group !== group) return false;
      if (!needle) return true;
      return (
        d.name.toLowerCase().includes(needle) ||
        d.def.toLowerCase().includes(needle) ||
        d.examples.some((e) => e.toLowerCase().includes(needle))
      );
    });
  }, [group, q]);

  const grouped = useMemo(() => {
    const map = {};
    filtered.forEach((d) => { (map[d.group] = map[d.group] || []).push(d); });
    return DATA.groupOrder.filter((g) => map[g]).map((g) => ({ g, items: map[g] }));
  }, [filtered]);

  return (
    <div className="ref-wrap">
      <div className="ref-controls">
        <div className="chip-row">
          <button className={`chip ${group === "all" ? "active" : ""}`} onClick={() => setGroup("all")}>
            ALL · {ALL.length}
          </button>
          {DATA.groupOrder.map((g) => (
            <button
              key={g}
              className={`chip ${group === g ? "active" : ""}`}
              onClick={() => setGroup(g)}
            >
              {DATA.groups[g].code}
            </button>
          ))}
        </div>
        <div className="search">
          <span className="search-ic">⌕</span>
          <input
            type="text"
            placeholder="Search devices, definitions, examples…"
            value={q}
            onChange={(e) => setQ(e.target.value)}
          />
          {q && <button className="search-clr" onClick={() => setQ("")}>✕</button>}
        </div>
      </div>

      {grouped.length === 0 && (
        <div className="empty">NO MATCHES — try another term.</div>
      )}

      {grouped.map(({ g, items }) => (
        <section className="ref-section" key={g}>
          <div className="ref-section-head">
            <span className="rs-code">{DATA.groups[g].code}</span>
            <h3 className="rs-name">{DATA.groups[g].name}</h3>
            <span className="rs-kicker">{DATA.groups[g].kicker}</span>
            <span className="rs-count">{pad(items.length)}</span>
          </div>
          <div className="dev-grid">
            {items.map((d) => (
              <article className="dev-card" key={d.id}>
                <div className="dev-top">
                  <h4 className="dev-name">{d.name}</h4>
                  <span className={`lvl lvl-${d.level}`}>{d.level === "beginner" ? "CORE" : "ADV"}</span>
                </div>
                <p className="dev-def">{d.def}</p>
                <div className="dev-ex">
                  {d.examples.map((ex, i) => (
                    <div className="ex-line" key={i}>
                      <span className="ex-mark">e.g.</span>
                      <span className="ex-text">{ex}</span>
                    </div>
                  ))}
                </div>
              </article>
            ))}
          </div>
        </section>
      ))}
    </div>
  );
}

// ─── Global stats panel ───────────────────────────────────────
function StatsPanel({ stats, loading }) {
  if (!FB_READY) {
    return (
      <div className="stats-panel quiet">
        <div className="stats-head"><span className="rec-dot" /> GLOBAL STATS</div>
        <p className="stats-na">Offline — global stats activate once Firebase is configured.</p>
      </div>
    );
  }
  const total = stats ? stats.totalQuizzes || 0 : 0;
  const avg = stats && total ? Math.round((stats.scoreSumPct || 0) / total) : null;
  const top = stats
    ? Object.entries(stats.misidentified || {})
        .sort((a, b) => b[1] - a[1])
        .slice(0, 3)
    : [];

  return (
    <div className="stats-panel">
      <div className="stats-head"><span className="rec-dot" /> GLOBAL STATS {loading ? "· syncing…" : ""}</div>
      <div className="stats-grid">
        <div className="stat">
          <div className="stat-num">{total.toLocaleString()}</div>
          <div className="stat-lab">Quizzes taken</div>
        </div>
        <div className="stat">
          <div className="stat-num">{avg == null ? "—" : avg + "%"}</div>
          <div className="stat-lab">Average score</div>
        </div>
      </div>
      <div className="stats-top">
        <div className="stats-top-lab">Most misidentified</div>
        {top.length === 0 && <div className="stats-na">No data yet — be the first.</div>}
        <ol className="top-list">
          {top.map(([id, count], i) => (
            <li key={id}>
              <span className="top-rank">{i + 1}</span>
              <span className="top-name">{BY_ID[id] ? BY_ID[id].name : id}</span>
              <span className="top-count">×{count}</span>
            </li>
          ))}
        </ol>
      </div>
    </div>
  );
}

// ─── Quiz view ────────────────────────────────────────────────
function QuizView() {
  const [phase, setPhase] = useState("setup"); // setup | playing | results
  const [mode, setMode] = useState("beginner");
  const [quiz, setQuiz] = useState([]);
  const [idx, setIdx] = useState(0);
  const [picked, setPicked] = useState(null);     // selected option id (this question)
  const [answers, setAnswers] = useState([]);     // {deviceId, chosenId, correct}
  const [stats, setStats] = useState(null);
  const [statsLoading, setStatsLoading] = useState(false);

  const loadStats = useCallback(async () => {
    if (!FB_READY) return;
    setStatsLoading(true);
    const s = await fetchStats();
    setStats(s);
    setStatsLoading(false);
  }, []);

  useEffect(() => { loadStats(); }, [loadStats]);

  const start = (m) => {
    setMode(m);
    setQuiz(buildQuiz(m));
    setIdx(0);
    setPicked(null);
    setAnswers([]);
    setPhase("playing");
  };

  const choose = (optId) => {
    if (picked != null) return; // lock after first pick
    setPicked(optId);
    const cur = quiz[idx];
    setAnswers((a) => [...a, { deviceId: cur.deviceId, chosenId: optId, correct: optId === cur.deviceId }]);
  };

  const next = async () => {
    if (idx + 1 < quiz.length) {
      setIdx(idx + 1);
      setPicked(null);
      return;
    }
    // finished — compute + record
    const correctCount = answers.filter((a) => a.correct).length;
    const pct = Math.round((correctCount / quiz.length) * 100);
    const wrongIds = answers.filter((a) => !a.correct).map((a) => a.deviceId);
    setPhase("results");
    if (FB_READY) {
      setStatsLoading(true);
      const s = await recordResult(pct, wrongIds);
      if (s) setStats(s);
      else await loadStats();
      setStatsLoading(false);
    }
  };

  // ── setup screen ──
  if (phase === "setup") {
    const begCount = ALL.filter((d) => d.level === "beginner").length;
    return (
      <div className="quiz-wrap">
        <div className="quiz-setup">
          <div className="setup-intro">
            <h3 className="setup-title">Identify the device.</h3>
            <p className="setup-sub">
              You’ll see {QUESTIONS_PER_QUIZ} short examples. Pick the literary device each one shows.
              No login, no limit — retake as often as you like.
            </p>
          </div>
          <div className="level-cards">
            <button className="level-card" onClick={() => start("beginner")}>
              <span className="lc-tag">LEVEL 01</span>
              <span className="lc-name">Beginner</span>
              <span className="lc-desc">
                The {begCount} core devices, with clear, everyday examples. Best place to start.
              </span>
              <span className="lc-go">BEGIN →</span>
            </button>
            <button className="level-card adv" onClick={() => start("advanced")}>
              <span className="lc-tag">LEVEL 02</span>
              <span className="lc-name">Advanced</span>
              <span className="lc-desc">
                All {ALL.length} devices — subtler examples, trickier look-alikes. For exam prep.
              </span>
              <span className="lc-go">BEGIN →</span>
            </button>
          </div>
          <StatsPanel stats={stats} loading={statsLoading} />
        </div>
      </div>
    );
  }

  // ── results screen ──
  if (phase === "results") {
    const correctCount = answers.filter((a) => a.correct).length;
    const pct = Math.round((correctCount / quiz.length) * 100);
    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="syn-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">{mode === "beginner" ? "Beginner" : "Advanced"} set</div>
          </div>

          {missed.length > 0 && (
            <div className="res-review">
              <div className="rr-head">REVIEW · {missed.length} missed</div>
              {missed.map((a, i) => {
                const dev = BY_ID[a.deviceId];
                const chosen = BY_ID[a.chosenId];
                return (
                  <div className="rr-row" key={i}>
                    <div className="rr-correct">
                      <span className="rr-tick">✓</span>
                      <span className="rr-name">{dev.name}</span>
                      <span className="rr-def">{dev.def}</span>
                    </div>
                    <div className="rr-wrong">you chose <span>{chosen ? chosen.name : "—"}</span></div>
                  </div>
                );
              })}
            </div>
          )}
          {missed.length === 0 && (
            <div className="res-perfect">Clean sweep — every device identified correctly.</div>
          )}

          <div className="res-actions">
            <button className="btn-primary" onClick={() => start(mode)}>RETAKE · {mode === "beginner" ? "BEGINNER" : "ADVANCED"}</button>
            <button className="btn-ghost" onClick={() => start(mode === "beginner" ? "advanced" : "beginner")}>
              TRY {mode === "beginner" ? "ADVANCED" : "BEGINNER"}
            </button>
            <button className="btn-ghost" onClick={() => setPhase("setup")}>← SETUP</button>
          </div>

          <StatsPanel stats={stats} loading={statsLoading} />
        </div>
      </div>
    );
  }

  // ── playing screen ──
  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">{mode === "beginner" ? "BEGINNER" : "ADVANCED"}</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">
          <div className="qp-q">WHICH DEVICE IS THIS?</div>
          <p className="qp-prompt">“{cur.prompt}”</p>
        </div>

        <div className="qp-options">
          {cur.options.map((optId) => {
            const dev = BY_ID[optId];
            let cls = "opt";
            if (answered) {
              if (optId === cur.deviceId) cls += " correct";
              else if (optId === picked) cls += " wrong";
              else cls += " dim";
            }
            return (
              <button key={optId} className={cls} disabled={answered} onClick={() => choose(optId)}>
                <span className="opt-name">{dev.name}</span>
                {answered && optId === cur.deviceId && <span className="opt-ic">✓</span>}
                {answered && optId === picked && optId !== cur.deviceId && <span className="opt-ic">✕</span>}
              </button>
            );
          })}
        </div>

        {answered && (
          <div className="qp-feedback">
            <p className="qp-fb-def"><strong>{BY_ID[cur.deviceId].name}:</strong> {BY_ID[cur.deviceId].def}</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("device-root")).render(<App />);
