// Results + dashboard + question review
const { useState: useState_R, useMemo: useMemo_R, useRef: useRef_R, useEffect: useEffect_R } = React;

// Build mock results from questions + answers
function buildResults(questions, answers) {
  const per = questions.map((q, i) => {
    const correct = answers[i] === q.correct;
    return { q, userAnswer: answers[i], correct };
  });
  const score = per.filter(p => p.correct).length;
  const total = per.length;

  // Topic accuracy (group by topicId, fill 14 topics)
  const byTopic = TOPICS.map(topic => {
    const items = per.filter(p => p.q.topicId === topic.id);
    const n = items.length;
    const correct = items.filter(p => p.correct).length;
    // Plausible-looking synthetic values for topics not exercised by the 10 Qs,
    // so a hero/demo results view shows the full 14-topic picture.
    let acc, basis;
    if (n > 0) {
      acc = correct / n;
      basis = `${correct}/${n}`;
    } else {
      const syn = 0.55 + ((topic.id * 37) % 41) / 100;
      acc = Math.min(0.95, syn);
      basis = "—";
    }
    return { topic, n, correct, acc, basis };
  });
  return { per, score, total, byTopic };
}

function BellCurveLarge({ percentile }) {
  const w = 680, h = 220;
  const N = 80;
  const mean = 0.55, sd = 0.17;
  const pts = [];
  for (let i = 0; i <= N; i++) {
    const x = i / N;
    const y = Math.exp(-((x - mean) ** 2) / (2 * sd * sd));
    pts.push([x, y]);
  }
  const maxY = Math.max(...pts.map(p => p[1]));
  const xAt = (x) => x * w;
  const yAt = (y) => h - (y / maxY) * (h - 24) - 12;
  const path = pts.map(([x, y], i) => `${i === 0 ? "M" : "L"}${xAt(x).toFixed(1)},${yAt(y).toFixed(1)}`).join(" ");
  const p = percentile / 100;
  const markerX = xAt(p);
  const markerY = yAt(Math.exp(-((p - mean) ** 2) / (2 * sd * sd)));
  const leftArea = pts.filter(pt => pt[0] <= p)
    .map(([x, y], i) => `${i === 0 ? "M" : "L"}${xAt(x).toFixed(1)},${yAt(y).toFixed(1)}`).join(" ");
  return (
    <svg viewBox={`0 0 ${w} ${h + 30}`} style={{ width: "100%", height: "auto", display: "block" }}>
      <defs>
        <linearGradient id="bellLeft" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor="var(--indigo)" stopOpacity="0.28" />
          <stop offset="1" stopColor="var(--indigo)" stopOpacity="0.02" />
        </linearGradient>
        <linearGradient id="bellRight" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor="var(--paper-3)" stopOpacity="0.8" />
          <stop offset="1" stopColor="var(--paper-3)" stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={`${path} L${w},${h} L0,${h} Z`} fill="url(#bellRight)" />
      <path d={`${leftArea} L${markerX},${h} L0,${h} Z`} fill="url(#bellLeft)" />
      <path d={path} fill="none" stroke="var(--indigo)" strokeWidth="1.6" />
      <line x1="0" x2={w} y1={h} y2={h} stroke="var(--line-2)" strokeWidth="1" />
      {[0.25, 0.5, 0.75].map(t => (
        <g key={t}>
          <line x1={xAt(t)} x2={xAt(t)} y1={h} y2={h + 6} stroke="var(--ink-4)" strokeWidth="1" />
          <text x={xAt(t)} y={h + 20} textAnchor="middle" fontSize="10" fill="var(--ink-3)" fontFamily="IBM Plex Mono">
            {Math.round(t * 100)}%
          </text>
        </g>
      ))}
      <line x1={markerX} x2={markerX} y1={markerY} y2={h} stroke="var(--ink-1)" strokeDasharray="3 3" strokeWidth="1" />
      <circle cx={markerX} cy={markerY} r="8" fill="var(--amber)" stroke="var(--ink-1)" strokeWidth="1.8" />
      <text x={markerX} y={markerY - 14} textAnchor="middle" fontSize="11" fontFamily="IBM Plex Mono" fill="var(--ink-1)" fontWeight="500">YOU</text>
    </svg>
  );
}

function ResultsView({ questions, answers, paperName, isSample, onReviewQ, onExit, onRegister, onLogin, onGoDashboard, onGoTests, authed, userName, savedSessionId }) {
  const { t, lang } = useT();
  const locked = isSample && !authed;
  const results = useMemo_R(() => buildResults(questions, answers), [questions, answers]);
  const pct = Math.round((results.score / results.total) * 100);

  // Cohort stats: DB includes seeded fake cohort (100명) + real users combined.
  const [stats, setStats] = useState_R({ participants: 0, percentile: 0, rank: 0, live: false, loading: true });
  React.useEffect(() => {
    if (!window._sb) { setStats((s) => ({ ...s, loading: false })); return; }
    let cancelled = false;
    const paperId = isSample
      ? 0
      : parseInt(((paperName && paperName.match(/\d+/)) || ["0"])[0]);
    (async () => {
      let scores = null;
      const rpc = await window._sb.rpc("get_paper_score_distribution", { p_paper_id: paperId });
      if (!rpc.error && Array.isArray(rpc.data) && rpc.data.length > 0) {
        scores = rpc.data.map((r) => r.score);
      } else {
        const { data, error } = await window._sb
          .from("test_sessions").select("score").eq("paper_id", paperId).limit(10000);
        if (!error && data && data.length > 0) scores = data.map((r) => r.score);
      }
      if (cancelled) return;
      if (!scores || scores.length === 0) { setStats({ participants: 0, percentile: 50, rank: 1, live: false, loading: false }); return; }
      const participants = scores.length;
      const lower = scores.filter((s) => s < results.score).length;
      const higher = scores.filter((s) => s > results.score).length;
      const percentile = Math.min(99, Math.max(1, Math.round((lower / participants) * 100)));
      setStats({ participants, percentile, rank: higher + 1, live: true, loading: false });
    })();
    return () => { cancelled = true; };
  }, [isSample, paperName, results.score, pct, savedSessionId]);

  const percentile = stats.percentile;
  const participants = stats.participants;
  const statsLoading = stats.loading;

  return (
    <div style={{ minHeight: "100vh", background: "var(--paper)" }}>
      {/* Results header */}
      <div style={{
        background: "var(--ink-1)", color: "var(--paper)", padding: "48px 28px 80px",
        backgroundImage: "radial-gradient(circle at 15% 100%, color-mix(in oklab, var(--indigo) 45%, var(--ink-1)) 0%, var(--ink-1) 60%)"
      }}>
        <div style={{ maxWidth: 1240, margin: "0 auto" }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <button onClick={onExit} style={{
                background: "transparent", border: "1px solid color-mix(in oklab, white 25%, transparent)",
                color: "var(--paper)", padding: "6px 12px", borderRadius: 6, cursor: "pointer",
                fontSize: 12, fontFamily: "inherit",
              }}>
                ← {lang === "ko" ? "나가기" : "Exit"}
              </button>
              {!locked && (
                <>
                  <button onClick={onGoDashboard} style={{
                    background: "transparent", border: "1px solid color-mix(in oklab, white 25%, transparent)",
                    color: "var(--paper)", padding: "6px 12px", borderRadius: 6, cursor: "pointer",
                    fontSize: 12, fontFamily: "inherit",
                  }}>
                    {lang === "ko" ? "대시보드" : "Dashboard"}
                  </button>
                  <button onClick={onGoTests} style={{
                    background: "var(--paper)", border: "none",
                    color: "var(--ink-1)", padding: "6px 12px", borderRadius: 6, cursor: "pointer",
                    fontSize: 12, fontFamily: "inherit", fontWeight: 500,
                  }}>
                    {lang === "ko" ? "모의고사 보러가기" : "Mock tests"}
                  </button>
                </>
              )}
            </div>
            <div className="mono" style={{ fontSize: 11, letterSpacing: "0.08em", opacity: 0.6, textTransform: "uppercase" }}>
              {paperName}
            </div>
          </div>

          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 40, marginTop: 32, alignItems: "end" }}>
            <div>
              <div className="mono" style={{ fontSize: 11, letterSpacing: "0.1em", opacity: 0.6, textTransform: "uppercase" }}>
                {t("res_title")}
              </div>
              {userName && (
                <div style={{ fontFamily: "var(--font-serif)", fontSize: 22, marginTop: 10, opacity: 0.85, fontStyle: "italic" }}>
                  {lang === "ko" ? `${userName}, 수고했어요!` : `Nicely done, ${userName}!`}
                </div>
              )}
              <div style={{ fontFamily: "var(--font-serif)", fontSize: 96, lineHeight: 1, marginTop: 12, letterSpacing: "-0.03em" }}>
                <span className="tabular">{results.score}</span>
                <span style={{ opacity: 0.4, fontSize: 60 }}> / {results.total}</span>
              </div>
              <div style={{ display: "flex", gap: 24, marginTop: 20 }}>
                {[
                  { label: t("res_score"), value: `${pct}%`, loading: false },
                  { label: t("res_percentile"), value: `${lang === "ko" ? "상위 " : "Top "}${100 - percentile}%`, loading: statsLoading },
                  { label: lang === "ko" ? "총 응시자" : "Participants", value: participants.toLocaleString(), loading: statsLoading },
                ].map((m, i) => (
                  <div key={i}>
                    <div className="mono" style={{ fontSize: 10, opacity: 0.55, letterSpacing: "0.08em", textTransform: "uppercase" }}>{m.label}</div>
                    <div className="tabular" style={{ fontFamily: "var(--font-serif)", fontSize: 24, marginTop: 4, opacity: m.loading ? 0.35 : 1 }}>
                      {m.loading ? "···" : m.value}
                    </div>
                  </div>
                ))}
              </div>
            </div>

            <div style={{
              background: "color-mix(in oklab, white 6%, transparent)",
              border: "1px solid color-mix(in oklab, white 12%, transparent)",
              borderRadius: 14, padding: 20,
            }}>
              <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 8 }}>
                <div style={{ fontSize: 13, opacity: statsLoading ? 0.35 : 0.8 }}>
                  <span className="mono">{statsLoading ? "····" : participants.toLocaleString()}</span> {t("res_participants")}
                </div>
                <div style={{ fontSize: 12, opacity: 0.6 }}>
                  {statsLoading ? (lang === "ko" ? "분포 계산 중…" : "Loading cohort…") : (
                    <>{t("res_bell_caption")} <span style={{ color: "var(--amber)", fontWeight: 500 }}>{percentile}%</span> {t("res_of_students")}</>
                  )}
                </div>
              </div>
              <div style={{ opacity: statsLoading ? 0.4 : 1, transition: "opacity 0.3s" }}>
                <BellCurveLarge percentile={percentile} />
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* Main body — blurred + gated when user is not logged in (sample) */}
      <div style={{ position: "relative" }}>
        <div style={{
          filter: locked ? "blur(7px)" : "none",
          pointerEvents: locked ? "none" : "auto",
          userSelect: locked ? "none" : "auto",
          transition: "filter 0.3s ease",
        }} aria-hidden={locked ? "true" : undefined}>
          <ResultsMainBody
            results={results} isSample={locked}
            onReviewQ={onReviewQ} paperName={paperName}
          />
          {/* Next-steps band — only when unlocked (authed / real test) */}
          {!locked && (
            <div style={{
              maxWidth: 1240, margin: "0 auto", padding: "0 28px 64px",
            }}>
              <div style={{
                background: "var(--ink-1)", color: "var(--paper)", borderRadius: 16,
                padding: "32px 36px", display: "grid", gridTemplateColumns: "1fr auto auto", gap: 20, alignItems: "center",
                backgroundImage: "radial-gradient(circle at 100% 0%, color-mix(in oklab, var(--indigo) 45%, var(--ink-1)) 0%, var(--ink-1) 60%)",
              }}>
                <div>
                  <div className="mono" style={{ fontSize: 11, letterSpacing: "0.08em", opacity: 0.6, textTransform: "uppercase" }}>
                    {lang === "ko" ? "다음 할 일" : "What's next"}
                  </div>
                  <div style={{ fontFamily: "var(--font-serif)", fontSize: 24, marginTop: 8, letterSpacing: "-0.01em", lineHeight: 1.3 }}>
                    {lang === "ko"
                      ? "진짜 50문제 실전 모의고사에 도전해보세요."
                      : "Ready for the real thing? Start a 50-question mock paper."}
                  </div>
                  <div style={{ fontSize: 13, opacity: 0.7, marginTop: 6 }}>
                    {lang === "ko" ? "14개 유형 · 50분 · 백분위 랭� 제공" : "14 topics · 50 minutes · percentile rank included"}
                  </div>
                </div>
                <button onClick={onGoDashboard} style={{
                  background: "transparent", color: "var(--paper)",
                  border: "1px solid color-mix(in oklab, white 25%, transparent)",
                  padding: "12px 18px", borderRadius: 8, cursor: "pointer", fontSize: 14, fontFamily: "inherit",
                }}>
                  {lang === "ko" ? "대시보드" : "Dashboard"}
                </button>
                <button className="btn" onClick={onGoTests} style={{
                  background: "var(--paper)", color: "var(--ink-1)", padding: "12px 18px", fontSize: 14,
                }}>
                  {lang === "ko" ? "모의고사 시작 →" : "Start a mock test →"}
                </button>
              </div>
            </div>
          )}
        </div>

        {locked && (
          <div style={{
            position: "absolute", inset: 0,
            display: "flex", alignItems: "flex-start", justifyContent: "center",
            paddingTop: 96, paddingLeft: 24, paddingRight: 24,
            background: "linear-gradient(180deg, color-mix(in oklab, var(--paper) 55%, transparent) 0%, color-mix(in oklab, var(--paper) 92%, transparent) 40%, var(--paper) 100%)",
          }}>
            <div style={{
              background: "white", border: "1px solid var(--line)", borderRadius: 16,
              boxShadow: "var(--shadow-lg)", maxWidth: 480, width: "100%",
              padding: "36px 32px", textAlign: "center",
            }}>
              <div style={{
                width: 52, height: 52, borderRadius: 14, margin: "0 auto",
                background: "var(--indigo-tint)", display: "flex", alignItems: "center", justifyContent: "center",
              }}>
                <svg width="24" height="24" viewBox="0 0 32 32" fill="none">
                  <rect x="6" y="14" width="20" height="14" rx="2" stroke="var(--indigo)" strokeWidth="1.6" />
                  <path d="M10 14v-3a6 6 0 0112 0v3" stroke="var(--indigo)" strokeWidth="1.6" strokeLinecap="round" />
                </svg>
              </div>
              <div className="mono" style={{ fontSize: 11, color: "var(--ink-3)", letterSpacing: "0.1em", textTransform: "uppercase", marginTop: 20 }}>
                {lang === "ko" ? "리포트 잠김" : "Report locked"}
              </div>
              <h2 style={{
                fontFamily: "var(--font-serif)", fontSize: 26, marginTop: 10, letterSpacing: "-0.01em", lineHeight: 1.3,
              }}>
                {lang === "ko" ? "로그인하면 전체 리포트를 볼 수 있어요" : "Log in to see the full report"}
              </h2>
              <p style={{ fontSize: 14, color: "var(--ink-3)", marginTop: 10, lineHeight: 1.6 }}>
                {lang === "ko"
                  ? "14개 유형별 분석, 문제별 정답률과 난이도, 소스가 포함된 풀이를 무료로 확인하세요."
                  : "Unlock topic-level breakdown, historical accuracy per question, and worked solutions — free."}
              </p>
              <button className="btn btn-dark" onClick={onRegister} style={{ width: "100%", marginTop: 22, padding: 14, justifyContent: "center", fontSize: 14 }}>
                {lang === "ko" ? "무료 가입하고 잠금 해제" : "Create free account to unlock"}
              </button>
              <div style={{ marginTop: 14, fontSize: 12, color: "var(--ink-3)" }}>
                {lang === "ko" ? "이미 계정이 있으세요? " : "Already have an account? "}
                <button onClick={onLogin} style={{
                  border: "none", background: "transparent", color: "var(--indigo)",
                  fontFamily: "inherit", fontSize: 12, cursor: "pointer",
                  fontWeight: 500, textDecoration: "underline",
                }}>
                  {lang === "ko" ? "로그인" : "Log in"}
                </button>
              </div>
              <div className="mono" style={{ marginTop: 18, fontSize: 10, color: "var(--ink-4)", letterSpacing: "0.06em" }}>
                {lang === "ko" ? "60초 · 결제 정보 불필요" : "60 seconds · no payment info"}
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// New main body: question table + topic filter
function ResultsMainBody({ results, isSample, onReviewQ, paperName }) {
  const { t, lang } = useT();
  const [activeTopic, setActiveTopic] = useState_R(null);
  // { [qIndex]: { correct: number, total: number } } — populated from DB
  const [realAccuracy, setRealAccuracy] = useState_R({});

  useEffect_R(() => {
    if (!window._sb || !paperName) return;
    const paperId = parseInt((paperName.match(/\d+/) || ["0"])[0]);
    if (!paperId) return;
    (async () => {
      const { data: sessions } = await window._sb
        .from("test_sessions").select("id").eq("paper_id", paperId);
      if (!sessions || sessions.length === 0) return;
      const ids = sessions.map(s => s.id);
      const { data: qa } = await window._sb
        .from("question_answers").select("question_index, is_correct").in("session_id", ids);
      if (!qa || qa.length === 0) return;
      const acc = {};
      qa.forEach(r => {
        if (!acc[r.question_index]) acc[r.question_index] = { correct: 0, total: 0 };
        acc[r.question_index].total++;
        if (r.is_correct) acc[r.question_index].correct++;
      });
      setRealAccuracy(acc);
    })();
  }, [paperName]);

  // Returns { pct, n, live }. Uses real DB data when n >= 3, else synthetic fallback.
  const MIN_SAMPLE = 3;
  const histFor = (qId, qIdx) => {
    const real = realAccuracy[qIdx];
    if (real && real.total >= MIN_SAMPLE) {
      return { pct: Math.round(real.correct / real.total * 100), n: real.total, live: true };
    }
    const seed = (qId * 97 + 13) % 73;
    return { pct: 20 + seed, n: real ? real.total : 0, live: false };
  };
  const levelFor = (hist) => {
    const pct = typeof hist === "object" ? hist.pct : hist;
    if (pct <= 30) return { id: "adv", label: lang === "ko" ? "고난도" : "Advanced", color: "var(--rose)", bg: "var(--rose-tint)" };
    if (pct <= 60) return { id: "int", label: lang === "ko" ? "중난도" : "Intermediate", color: "var(--amber)", bg: "var(--amber-tint)" };
    return { id: "beg", label: lang === "ko" ? "기초" : "Beginner", color: "var(--emerald)", bg: "var(--emerald-tint)" };
  };

  const filteredIdxs = activeTopic == null
    ? results.per.map((_, i) => i)
    : results.per.map((p, i) => p.q.topicId === activeTopic ? i : null).filter(i => i !== null);

  // count per topic
  const countByTopic = {};
  results.per.forEach(p => { countByTopic[p.q.topicId] = (countByTopic[p.q.topicId] || 0) + 1; });

  return (
    <div style={{ maxWidth: 1240, margin: "0 auto", padding: "48px 28px", display: "grid", gridTemplateColumns: "1.7fr 1fr", gap: 36 }}>
      {/* Left: full question list */}
      <section>
        <div style={{ marginBottom: 18, display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
          <div>
            <h2 style={{ fontSize: 24, letterSpacing: "-0.01em" }}>
              {lang === "ko" ? "문제별 결과" : "Question-by-question"}
            </h2>
            <div style={{ fontSize: 13, color: "var(--ink-3)", marginTop: 4 }}>
              {lang === "ko" ? "행을 눌러 해설을 확인하세요." : "Click any row for the worked solution."}
              {activeTopic != null && (
                <span style={{ marginLeft: 10, color: "var(--indigo)" }}>
                  · {lang === "ko" ? "필터:" : "Filter:"} {topicName(TOPICS.find(t => t.id === activeTopic), lang)}
                  <button onClick={() => setActiveTopic(null)} style={{
                    marginLeft: 8, border: "none", background: "transparent", color: "var(--ink-3)",
                    cursor: "pointer", fontSize: 12, textDecoration: "underline", fontFamily: "inherit"
                  }}>× {lang === "ko" ? "해제" : "clear"}</button>
                </span>
              )}
            </div>
          </div>
          <div className="mono" style={{ fontSize: 11, color: "var(--ink-3)" }}>
            {filteredIdxs.length} / {results.per.length}
          </div>
        </div>

        <div style={{
          background: "white", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden",
        }}>
          <div style={{
            display: "grid", gridTemplateColumns: "44px 1fr 120px 100px 40px",
            padding: "12px 16px", background: "var(--paper-2)",
            borderBottom: "1px solid var(--line)",
            fontSize: 10, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: "0.08em",
            fontFamily: "var(--font-mono)", alignItems: "center", gap: 12,
          }}>
            <div>#</div>
            <div>{lang === "ko" ? "문제" : "Question"}</div>
            <div>{lang === "ko" ? "난이도" : "Level"}</div>
            <div title={lang === "ko" ? "전체 사용자 중 맞춘 비율" : "% of users who got this right"}>
              {lang === "ko" ? "정답률" : "% Correct"}
            </div>
            <div></div>
          </div>

          {filteredIdxs.map(i => {
            const p = results.per[i];
            const topic = TOPICS.find(tp => tp.id === p.q.topicId);
            const hist = histFor(p.q.id, i);
            const lvl = levelFor(hist);
            const stemRaw = lang === "ko" ? p.q.ko : p.q.en;
            // For the list row we want a plain-text preview — strip any HTML (e.g. inline fractions).
            const stem = p.q._html
              ? stemRaw.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim().slice(0, 120)
              : stemRaw;
            return (
              <button key={i} onClick={() => !isSample && onReviewQ(i)}
                disabled={isSample}
                style={{
                  display: "grid", gridTemplateColumns: "44px 1fr 120px 100px 40px",
                  padding: "14px 16px", width: "100%", textAlign: "left", gap: 12,
                  borderTop: "none", borderLeft: "none", borderRight: "none",
                  borderBottom: "1px solid var(--line)",
                  background: p.correct ? "rgba(46,204,113,0.03)" : "rgba(231,76,60,0.03)",
                  cursor: isSample ? "not-allowed" : "pointer",
                  alignItems: "center", fontFamily: "inherit", fontSize: 13,
                  opacity: isSample ? 0.75 : 1,
                }}
                onMouseEnter={(e) => !isSample && (e.currentTarget.style.background = "var(--paper-2)")}
                onMouseLeave={(e) => e.currentTarget.style.background = p.correct ? "rgba(46,204,113,0.03)" : "rgba(231,76,60,0.03)"}
              >
                <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                  <span style={{
                    width: 22, height: 22, borderRadius: 5,
                    background: p.correct ? "var(--emerald-tint)" : "var(--rose-tint)",
                    color: p.correct ? "var(--emerald)" : "var(--rose)",
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    fontSize: 13, fontFamily: "var(--font-mono)", fontWeight: 700,
                  }}>{p.correct ? "✓" : "✗"}</span>
                  <span className="mono tabular" style={{ color: "var(--ink-3)", fontSize: 11 }}>
                    {String(i + 1).padStart(2, "0")}
                  </span>
                </div>
                <div style={{
                  overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
                  color: "var(--ink-1)", fontFamily: "var(--font-serif)", fontSize: 14,
                }}>
                  {stem}
                </div>
                <div>
                  <span style={{
                    padding: "3px 9px", borderRadius: 999, fontSize: 11,
                    background: lvl.bg, color: lvl.color,
                    border: "1px solid color-mix(in oklab, " + lvl.color + " 20%, transparent)",
                    fontFamily: "var(--font-mono)", letterSpacing: "0.04em", textTransform: "uppercase",
                  }}>{lvl.label}</span>
                </div>
                <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                  <div style={{ width: 36, height: 4, background: "var(--paper-3)", borderRadius: 2, overflow: "hidden" }}>
                    <div style={{ width: `${hist.pct}%`, height: "100%", background: lvl.color }} />
                  </div>
                  <span className="mono tabular" style={{ fontSize: 12, color: "var(--ink-2)" }}>{hist.pct}%</span>
                  <span title={hist.live ? `실제 데이터 (n=${hist.n})` : "예상치"} style={{
                    fontSize: 9, fontFamily: "var(--font-mono)",
                    color: hist.live ? "var(--emerald)" : "var(--ink-4)",
                    letterSpacing: 0,
                  }}>{hist.live ? `n=${hist.n}` : "~"}</span>
                </div>
                <div style={{ color: "var(--ink-4)", textAlign: "right" }}>›</div>
              </button>
            );
          })}
        </div>
      </section>

      {/* Right: most-missed topics (weakest 3, click to filter the list) */}
      <aside>
        <div style={{ marginBottom: 18 }}>
          <h2 style={{ fontSize: 24, letterSpacing: "-0.01em" }}>
            {lang === "ko" ? "가장 많이 틀린 유형" : "Most missed topics"}
          </h2>
          <div style={{ fontSize: 13, color: "var(--ink-3)", marginTop: 4 }}>
            {lang === "ko" ? "유형을 누르면 왼쪽 목록이 해당 유형으로 좁혀집니다." : "Click a topic to filter the question list."}
          </div>
        </div>

        <div style={{
          background: "white", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden",
        }}>
          {(() => {
            const top3 = results.byTopic
              .filter(t => t.n > 0)
              .sort((a, b) => a.acc - b.acc)
              .slice(0, 3);
            if (top3.length === 0) {
              return (
                <div style={{ padding: 18, color: "var(--ink-3)", fontSize: 13, textAlign: "center" }}>
                  {lang === "ko" ? "응답된 유형이 없습니다." : "No topics answered yet."}
                </div>
              );
            }
            return top3.map((row, i) => {
              const active = activeTopic === row.topic.id;
              const pctTopic = Math.round(row.acc * 100);
              return (
                <button key={row.topic.id}
                  onClick={() => setActiveTopic(active ? null : row.topic.id)}
                  style={{
                    display: "grid", gridTemplateColumns: "28px 1fr auto",
                    padding: "12px 16px", width: "100%", textAlign: "left", gap: 12, alignItems: "center",
                    border: "none",
                    borderBottom: i === top3.length - 1 ? "none" : "1px solid var(--line)",
                    background: active ? "var(--indigo-tint)" : "white",
                    cursor: "pointer", fontFamily: "inherit", fontSize: 13,
                  }}>
                  <div className="mono tabular" style={{ color: "var(--ink-4)", fontSize: 11 }}>
                    {String(row.topic.id).padStart(2, "0")}
                  </div>
                  <div style={{
                    overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
                    color: active ? "var(--indigo)" : "var(--ink-1)",
                    fontWeight: active ? 500 : 400,
                  }}>
                    {topicName(row.topic, lang)}
                  </div>
                  <span className="mono tabular" style={{ fontSize: 12, color: "var(--ink-2)" }}>
                    {pctTopic}%
                  </span>
                </button>
              );
            });
          })()}
        </div>
      </aside>
    </div>
  );
}

// ---------- Question review (worked solution + similar question) ----------
function QuestionReview({ questions, answers, qIndex, onBack, onChangeIndex, paperId }) {
  const { t, lang } = useT();
  const [showSimilar, setShowSimilar] = useState_R(false);
  const [similarAnswer, setSimilarAnswer] = useState_R(null);
  const q = questions[qIndex];
  const isCorrect = answers[qIndex] === q.correct;
  const topic = TOPICS.find(tt => tt.id === q.topicId);
  const stem = lang === "ko" ? q.ko : q.en;
  const solution = lang === "ko" ? q.solutionKo : q.solutionEn;
  const useHtml = !!q._html;
  const diagramHtml = q._diagramHtml || "";
  const followHtml = q._questionHtml || "";

  // Similar question: live re-roll via the engine that owns this paper's templates,
  // so a Paper 02 review re-rolls a Paper 02 template (not a Sutton or Paper 01 one).
  const similar = React.useMemo(() => {
    const engine = paperId === 1 ? (window.Paper01Engine || window.SuttonEngine)
                 : paperId === 2 ? (window.Paper02Engine || window.SuttonEngine)
                 : paperId === 3 ? (window.Paper03Engine || window.SuttonEngine)
                 : (window.SuttonEngine || window.Paper01Engine || window.Paper02Engine || window.Paper03Engine);
    if (useHtml && engine && engine.renderOne) {
      const r = engine.renderOne(q.id);
      if (r) {
        const opts = r.choices ? r.choices.map(c => c.html) : q.optionsLabeled;
        const idx = r.choices ? r.choices.findIndex(c => c.value === r.answerKey) : 0;
        return {
          stem: r.promptHtml + (r.diagramHtml ? `<div class="sutton-diagram">${r.diagramHtml}</div>` : "") + (r.questionHtml ? `<div class="q-follow">${r.questionHtml}</div>` : ""),
          options: opts,
          useHtml: true,
          correct: idx < 0 ? 0 : idx,
        };
      }
    }

    // Stub: shift all integers in the stem by OFFSET, then build fresh choices so a
    // correct answer actually exists (original had same choices with an arbitrary index).
    const OFFSET = 5;
    const letters = ["A", "B", "C", "D", "E"];
    const shiftedStem = String(stem).replace(/\b(\d+)\b/g, n => String(Math.max(2, parseInt(n) + OFFSET)));
    const correctOpt = q.optionsLabeled[q.correct] || "";
    const m = correctOpt.match(/^([A-E]\.\s*)([\d.]+)(.*)/);
    if (m) {
      const [, , numStr, suffix] = m;
      const newAns = Math.max(1, Math.round(parseFloat(numStr) + OFFSET));
      const pool = [newAns, newAns - 3, newAns - 2, newAns + 1, newAns + 2].filter(v => v > 0);
      // Fisher-Yates shuffle
      for (let k = pool.length - 1; k > 0; k--) {
        const j = Math.floor(Math.random() * (k + 1));
        [pool[k], pool[j]] = [pool[j], pool[k]];
      }
      const opts5 = pool.slice(0, 5);
      const correctPos = opts5.indexOf(newAns);
      return {
        stem: lang === "ko" ? `(유사 문제) ${shiftedStem}` : `(Similar) ${shiftedStem}`,
        options: opts5.map((v, i) => `${letters[i]}. ${v}${suffix}`),
        useHtml: false,
        correct: correctPos >= 0 ? correctPos : 0,
      };
    }
    // Fallback when answer has no parseable number: keep correct index, shift options text
    return {
      stem: lang === "ko" ? `(유사 문제) ${shiftedStem}` : `(Similar) ${shiftedStem}`,
      options: q.optionsLabeled.map((o, i) =>
        o.replace(/\b(\d+)\b/g, n => String(Math.max(2, parseInt(n) + OFFSET)))
      ),
      useHtml: false,
      correct: q.correct,
    };
  }, [qIndex, useHtml, q, lang, paperId]);

  return (
    <div style={{ minHeight: "100vh" }}>
      <div style={{ maxWidth: 1100, margin: "0 auto", padding: "28px 28px 80px" }}>
        <button className="btn btn-ghost" onClick={onBack} style={{ padding: "6px 12px", fontSize: 13 }}>
          ← {t("rev_back")}
        </button>

        <div style={{ marginTop: 24, display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 36 }}>
          {/* Left: question + solution */}
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
              <div className="pill" style={{
                color: isCorrect ? "var(--emerald)" : "var(--rose)",
                background: isCorrect ? "var(--emerald-tint)" : "var(--rose-tint)",
                borderColor: "transparent",
              }}>
                <span className="dot" /> {isCorrect ? t("rev_correct") : (lang === "ko" ? "오답" : "Incorrect")}
              </div>
              <div className="mono" style={{ fontSize: 11, color: "var(--ink-3)", letterSpacing: "0.06em", textTransform: "uppercase" }}>
                Q{qIndex + 1} · {topicName(topic, lang)}
              </div>
            </div>

            {useHtml ? (
              <h1 className="q-stem" style={{ fontFamily: "var(--font-serif)", fontSize: 24, marginTop: 16, lineHeight: 1.5, fontWeight: 400, letterSpacing: "-0.01em" }}
                dangerouslySetInnerHTML={{ __html: stem }} />
            ) : (
              <h1 style={{ fontFamily: "var(--font-serif)", fontSize: 26, marginTop: 16, lineHeight: 1.4, fontWeight: 400, letterSpacing: "-0.01em" }}>
                {stem}
              </h1>
            )}

            {diagramHtml && (
              <div className="sutton-diagram" dangerouslySetInnerHTML={{ __html: diagramHtml }} />
            )}
            {followHtml && (
              <div className="q-follow" dangerouslySetInnerHTML={{ __html: followHtml }} />
            )}

            <div style={{ marginTop: 24, display: "grid", gap: 8 }}>
              {q.optionsLabeled.map((opt, i) => {
                const isUser = answers[qIndex] === i;
                const isAns = q.correct === i;
                let bg = "white", bd = "var(--line)", clr = "var(--ink-1)";
                if (isAns) { bg = "var(--emerald-tint)"; bd = "var(--emerald)"; clr = "var(--ink-1)"; }
                else if (isUser && !isAns) { bg = "var(--rose-tint)"; bd = "var(--rose)"; }
                return (
                  <div key={i} style={{
                    padding: "12px 16px", borderRadius: 10,
                    border: "1.5px solid " + bd, background: bg, color: clr,
                    display: "flex", alignItems: "center", gap: 14, fontSize: 15,
                  }}>
                    <span className="mono" style={{
                      width: 26, height: 26, borderRadius: 6, display: "flex", alignItems: "center", justifyContent: "center",
                      background: "color-mix(in oklab, white 65%, transparent)", border: "1px solid var(--line)", fontSize: 12,
                    }}>{String.fromCharCode(65 + i)}</span>
                    {useHtml
                      ? <span style={{ fontFamily: "var(--font-serif)", flex: 1 }} dangerouslySetInnerHTML={{ __html: opt }} />
                      : <span style={{ fontFamily: "var(--font-serif)", flex: 1 }}>{opt}</span>
                    }
                    {isAns && <span className="mono" style={{ fontSize: 11, color: "var(--emerald)" }}>{t("rev_answer").toUpperCase()}</span>}
                    {isUser && !isAns && <span className="mono" style={{ fontSize: 11, color: "var(--rose)" }}>{t("rev_wrong").toUpperCase()}</span>}
                  </div>
                );
              })}
            </div>

            <div style={{
              marginTop: 28, padding: 22, borderRadius: 12,
              background: "var(--paper-2)", border: "1px solid var(--line)",
            }}>
              <div className="mono" style={{ fontSize: 10, color: "var(--ink-3)", letterSpacing: "0.08em", textTransform: "uppercase" }}>
                {t("rev_solution")}
              </div>
              {useHtml ? (
                <div style={{ fontFamily: "var(--font-serif)", fontSize: 17, marginTop: 10, lineHeight: 1.7, color: "var(--ink-1)" }}
                  dangerouslySetInnerHTML={{ __html: solution }} />
              ) : (
                <div style={{ fontFamily: "var(--font-serif)", fontSize: 17, marginTop: 10, lineHeight: 1.7, color: "var(--ink-1)" }}>
                  {solution}
                </div>
              )}
            </div>

            {/* Similar question */}
            <div style={{ marginTop: 28 }}>
              {!showSimilar ? (
                <button className="btn btn-primary" onClick={() => setShowSimilar(true)}>
                  <svg width="14" height="14" viewBox="0 0 20 20" fill="none">
                    <path d="M4 10a6 6 0 1110 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
                    <path d="M14 11v3h3" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                  </svg>
                  {t("rev_similar")}
                </button>
              ) : (
                <div style={{
                  padding: 22, borderRadius: 12, background: "white",
                  border: "1.5px dashed var(--indigo)",
                }}>
                  <div className="mono" style={{ fontSize: 10, color: "var(--indigo)", letterSpacing: "0.08em", textTransform: "uppercase" }}>
                    {lang === "ko" ? "파라미터 조정된 쌍둥이 문제" : "Parameter-shifted twin question"}
                  </div>
                  {similar.useHtml ? (
                    <div className="q-stem" style={{ fontFamily: "var(--font-serif)", fontSize: 18, marginTop: 10, lineHeight: 1.55 }}
                      dangerouslySetInnerHTML={{ __html: similar.stem }} />
                  ) : (
                    <div style={{ fontFamily: "var(--font-serif)", fontSize: 18, marginTop: 10, lineHeight: 1.5 }}>
                      {similar.stem}
                    </div>
                  )}
                  <div style={{ marginTop: 16, display: "grid", gap: 8 }}>
                    {similar.options.map((opt, i) => {
                      const picked = similarAnswer === i;
                      const submitted = similarAnswer !== null;
                      const right = similar.correct === i;
                      let bg = "white", bd = "var(--line)";
                      if (submitted) {
                        if (right) { bg = "var(--emerald-tint)"; bd = "var(--emerald)"; }
                        else if (picked) { bg = "var(--rose-tint)"; bd = "var(--rose)"; }
                      } else if (picked) {
                        bg = "var(--paper-2)"; bd = "var(--ink-1)";
                      }
                      return (
                        <button key={i} onClick={() => setSimilarAnswer(i)}
                          disabled={submitted}
                          style={{
                            textAlign: "left", padding: "12px 14px", borderRadius: 8,
                            border: "1.5px solid " + bd, background: bg, cursor: submitted ? "default" : "pointer",
                            fontFamily: "inherit", fontSize: 14, display: "flex", alignItems: "center", gap: 12,
                          }}>
                          <span className="mono" style={{ fontSize: 11, color: "var(--ink-3)" }}>{String.fromCharCode(65 + i)}</span>
                          {similar.useHtml
                            ? <span style={{ fontFamily: "var(--font-serif)" }} dangerouslySetInnerHTML={{ __html: opt }} />
                            : <span style={{ fontFamily: "var(--font-serif)" }}>{opt}</span>}
                        </button>
                      );
                    })}
                  </div>
                  {similarAnswer !== null && (
                    <div style={{ marginTop: 12, fontSize: 13, color: similarAnswer === similar.correct ? "var(--emerald)" : "var(--rose)" }}>
                      {similarAnswer === similar.correct
                        ? (lang === "ko" ? "정답! 유사 문제 하나 더 받을까요?" : "Correct! Try another variant?")
                        : (lang === "ko" ? "오답 — 풀이를 다시 확인해보세요." : "Not quite — revisit the solution above.")}
                    </div>
                  )}
                </div>
              )}
            </div>
          </div>

          {/* Right: nav sidebar */}
          <aside>
            <div style={{
              position: "sticky", top: 24,
              background: "var(--paper-2)", border: "1px solid var(--line)", borderRadius: 12,
              padding: 20,
            }}>
              <div className="mono" style={{ fontSize: 10, color: "var(--ink-3)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 10 }}>
                {lang === "ko" ? "전체 문제" : "All questions"}
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 6 }}>
                {questions.map((_, i) => {
                  const correct = answers[i] === questions[i].correct;
                  const current = i === qIndex;
                  return (
                    <button key={i} onClick={() => onChangeIndex(i)} style={{
                      aspectRatio: "1 / 1", borderRadius: 6,
                      border: "1.5px solid " + (current ? "var(--ink-1)" : "transparent"),
                      background: correct ? "var(--emerald-tint)" : "var(--rose-tint)",
                      color: correct ? "var(--emerald)" : "var(--rose)",
                      fontFamily: "var(--font-mono)", fontSize: 11,
                      cursor: "pointer",
                    }}>{i + 1}</button>
                  );
                })}
              </div>
              <div style={{ marginTop: 16, paddingTop: 16, borderTop: "1px solid var(--line)", fontSize: 12, color: "var(--ink-2)", lineHeight: 1.6 }}>
                <div style={{ display: "flex", justifyContent: "space-between" }}>
                  <span>{lang === "ko" ? "이 유형 정답률" : "Your accuracy (topic)"}</span>
                  <span className="mono tabular" style={{ color: "var(--ink-1)" }}>
                    {(() => {
                      const items = answers.map((a, i) => ({ correct: a === questions[i].correct, tid: questions[i].topicId }))
                        .filter(x => x.tid === q.topicId);
                      if (!items.length) return "—";
                      return `${Math.round(items.filter(x => x.correct).length / items.length * 100)}%`;
                    })()}
                  </span>
                </div>
                <div style={{ display: "flex", justifyContent: "space-between", marginTop: 6 }}>
                  <span>{lang === "ko" ? "전체 응시자 정답률" : "Cohort accuracy"}</span>
                  <span className="mono tabular" style={{ color: "var(--ink-3)" }}>62%</span>
                </div>
              </div>
            </div>
          </aside>
        </div>
      </div>
    </div>
  );
}

// ---------- User dashboard ----------
function UserDashboard({ setView, onViewReport, onBuyCredits, refreshKey }) {
  const { t, lang } = useT();
  const [history, setHistory] = useState_R([]);
  const [weak, setWeak] = useState_R([]);
  const [dbLoading, setDbLoading] = useState_R(true);
  const [userName, setUserName] = useState_R("");
  const [credits, setCredits] = useState_R(0);

  React.useEffect(() => {
    (async () => {
      if (!window._sb) { setDbLoading(false); return; }
      const { data: { session } } = await window._sb.auth.getSession();
      if (!session) { setDbLoading(false); return; }
      const uid = session.user.id;

      // Load profile name
      const { data: profile } = await window._sb.from("profiles").select("name").eq("id", uid).single();
      if (profile) setUserName(profile.name || "");
      // Credits (optional column; silently 0 if not present)
      const { data: creditsRow } = await window._sb.from("profiles").select("credits").eq("id", uid).maybeSingle();
      if (creditsRow && typeof creditsRow.credits === "number") setCredits(creditsRow.credits);

      // Load sessions
      const { data: sessions } = await window._sb.from("test_sessions")
        .select("*").eq("user_id", uid).order("completed_at", { ascending: false });
      if (sessions && sessions.length > 0) {
        setHistory(sessions.map((s) => ({
          id: s.id,
          paperId: s.paper_id,
          mode: s.mode || "online",
          date: new Date(s.completed_at).toLocaleDateString("en-GB", { day: "numeric", month: "short" }),
          score: s.score,
          total: s.total,
          // Stored at insert-time against the cohort available at that moment.
          // Falls back to null when it's missing so the UI can render "—".
          percentile: (typeof s.percentile === "number") ? s.percentile : null,
        })));

        // Load weak topics
        const { data: ans } = await window._sb.from("question_answers")
          .select("topic_id, is_correct")
          .in("session_id", sessions.map(s => s.id));
        if (ans && ans.length > 0) {
          const map = {};
          for (const a of ans) {
            if (!a.topic_id) continue;
            if (!map[a.topic_id]) map[a.topic_id] = { correct: 0, total: 0 };
            map[a.topic_id].total++;
            if (a.is_correct) map[a.topic_id].correct++;
          }
          const weakList = Object.entries(map)
            .map(([id, { correct, total }]) => ({ id, pct: Math.round(correct / total * 100) }))
            .sort((a, b) => a.pct - b.pct).slice(0, 3)
            .map(({ id, pct }) => {
              const topic = TOPICS.find(t => String(t.id) === String(id));
              return { id, nameEn: topic ? topic.en : id, nameKo: topic ? topic.ko : id, pct };
            });
          setWeak(weakList);
        }
      }
      setDbLoading(false);
    })();
  }, [refreshKey]);

  const trend = history.slice().reverse();

  return (
    <main style={{ maxWidth: 1240, margin: "0 auto", padding: "40px 28px" }}>
      <div style={{ display: "grid", gridTemplateColumns: "1fr auto", alignItems: "end", gap: 20, marginBottom: 28 }}>
        <div>
          <div className="mono" style={{ fontSize: 11, color: "var(--ink-3)", letterSpacing: "0.08em", textTransform: "uppercase" }}>
            {t("dash_hi")}{userName ? `, ${userName}` : ""}
          </div>
          <h1 style={{ fontSize: 36, marginTop: 6, letterSpacing: "-0.02em" }}>
            {dbLoading
              ? (lang === "ko" ? "불러오는 중…" : "Loading…")
              : history.length === 0
                ? (lang === "ko"
                    ? (userName ? `${userName}, 첫 시험을 시작해봐요` : "아직 응시한 시험이 없습니다")
                    : (userName ? `Ready when you are, ${userName}` : "No papers taken yet"))
                : (lang === "ko"
                    ? (userName ? `${userName}의 준비 현황` : "준비 현황")
                    : (userName ? `${userName}'s prep, at a glance` : "Your prep, at a glance"))}
          </h1>
        </div>
        <button className="btn btn-primary" onClick={() => setView("tests")}>
          {t("dash_start")}
          <svg width="14" height="14" viewBox="0 0 20 20" fill="none"><path d="M5 10h10m0 0l-4-4m4 4l-4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" /></svg>
        </button>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1.3fr 1fr", gap: 20 }}>
        {/* Left: credits + trend */}
        <div style={{ display: "grid", gap: 20 }}>
          {/* Credits */}
          <div style={{
            background: "var(--ink-1)", color: "var(--paper)", borderRadius: 14, padding: 24,
            backgroundImage: "radial-gradient(circle at 100% 0%, color-mix(in oklab, var(--indigo) 40%, var(--ink-1)) 0%, var(--ink-1) 60%)",
            display: "grid", gridTemplateColumns: "1fr auto", alignItems: "center", gap: 16,
          }}>
            <div>
              <div className="mono" style={{ fontSize: 11, letterSpacing: "0.08em", opacity: 0.6, textTransform: "uppercase" }}>
                {t("dash_credits")}
              </div>
              <div style={{ display: "flex", alignItems: "baseline", gap: 12, marginTop: 8 }}>
                <div style={{ fontFamily: "var(--font-serif)", fontSize: 56, lineHeight: 1, letterSpacing: "-0.02em" }} className="tabular">{credits}</div>
                <div style={{ opacity: 0.7, fontSize: 14 }}>
                  / 10 {lang === "ko" ? "묶음" : "pack"}
                </div>
              </div>
              <div style={{ marginTop: 12, width: 260, height: 6, background: "color-mix(in oklab, white 14%, transparent)", borderRadius: 4 }}>
                <div style={{ width: `${credits * 10}%`, height: "100%", background: "var(--amber)", borderRadius: 4 }} />
              </div>
            </div>
            <button className="btn" style={{ background: "var(--paper)", color: "var(--ink-1)" }} onClick={onBuyCredits}>
              {t("dash_buy")}
            </button>
          </div>

          {/* Trend */}
          <div style={{ background: "white", border: "1px solid var(--line)", borderRadius: 14, padding: 22 }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 14 }}>
              <div>
                <div className="mono" style={{ fontSize: 11, color: "var(--ink-3)", letterSpacing: "0.08em", textTransform: "uppercase" }}>{t("dash_trend")}</div>
                <div style={{ fontFamily: "var(--font-serif)", fontSize: 20, marginTop: 4 }}>
                  {trend.length === 0
                    ? (lang === "ko" ? "아직 기록 없음" : "No papers yet")
                    : trend.length === 1
                      ? (lang === "ko" ? "첫 시험 완료!" : "First paper done!")
                      : (lang === "ko" ? `${trend.length}회 응시` : `${trend.length} papers taken`)}
                </div>
              </div>
              {trend.length >= 2 && (() => {
                const firstPct = trend[0].score / trend[0].total;
                const lastPct = trend[trend.length - 1].score / trend[trend.length - 1].total;
                const delta = Math.round((lastPct - firstPct) * 100);
                const color = delta > 0 ? "var(--emerald)" : delta < 0 ? "var(--rose)" : "var(--ink-3)";
                const sign = delta > 0 ? "+" : "";
                return (
                  <div className="mono tabular" style={{ fontSize: 13, color }}>
                    {sign}{delta}%
                  </div>
                );
              })()}
            </div>
            {trend.length >= 2 ? (
              <svg viewBox="0 0 400 140" style={{ width: "100%", height: 140 }}>
                {[0, 25, 50, 75, 100].map((g, i) => (
                  <line key={i} x1="30" x2="390" y1={20 + (100 - g) * 1} y2={20 + (100 - g) * 1} stroke="var(--line)" strokeDasharray="2 3" />
                ))}
                {[0, 50, 100].map((g, i) => (
                  <text key={i} x="26" y={24 + (100 - g) * 1} textAnchor="end" fontSize="9" fontFamily="IBM Plex Mono" fill="var(--ink-4)">{g}</text>
                ))}
                {(() => {
                  // y-axis: % correct out of this paper's total (0..100). Works across
                  // samples (10-question) and mocks (50-question) on the same scale.
                  const pts = trend.map((h, i) => {
                    const scorePct = h.total > 0 ? (h.score / h.total) * 100 : 0;
                    return { x: 40 + i * ((390 - 40) / (trend.length - 1)), y: 20 + (100 - scorePct) };
                  });
                  const path = pts.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
                  return (
                    <>
                      <path d={`${path} L${pts[pts.length - 1].x},120 L${pts[0].x},120 Z`} fill="var(--indigo-tint)" />
                      <path d={path} fill="none" stroke="var(--indigo)" strokeWidth="2" />
                      {pts.map((p, i) => (
                        <g key={i}>
                          <circle cx={p.x} cy={p.y} r="4" fill="white" stroke="var(--indigo)" strokeWidth="2" />
                          <text x={p.x} y="134" textAnchor="middle" fontSize="10" fontFamily="IBM Plex Mono" fill="var(--ink-3)">
                            {trend[i].paperId === 0 ? "SMP" : `#${String(trend[i].paperId).padStart(2, "0")}`}
                          </text>
                        </g>
                      ))}
                    </>
                  );
                })()}
              </svg>
            ) : (
              <div style={{
                height: 140, display: "flex", alignItems: "center", justifyContent: "center",
                color: "var(--ink-3)", fontSize: 13, border: "1px dashed var(--line)", borderRadius: 8,
                fontFamily: "var(--font-mono)", letterSpacing: "0.04em",
              }}>
                {trend.length === 0
                  ? (lang === "ko" ? "아직 데이터 없음" : "No data yet")
                  : (lang === "ko" ? "최소 2회 이상 응시해야 표시됩니다" : "Take at least 2 papers to see a trend")}
              </div>
            )}
          </div>
        </div>

        {/* Right: weak topics */}
        <div style={{ background: "white", border: "1px solid var(--line)", borderRadius: 14, padding: 22 }}>
          <div className="mono" style={{ fontSize: 11, color: "var(--ink-3)", letterSpacing: "0.08em", textTransform: "uppercase" }}>{t("dash_weakest")}</div>
          <div style={{ display: "grid", gap: 14, marginTop: 16 }}>
            {weak.length === 0 && (
              <div style={{
                padding: 24, border: "1px dashed var(--line)", borderRadius: 10,
                textAlign: "center", color: "var(--ink-3)", fontSize: 13,
              }}>
                {lang === "ko" ? "시험을 풀면 취약 유형이 표시됩니다" : "Take a paper to see weak topics"}
              </div>
            )}
            {weak.map((w, i) => (
              <div key={w.id} style={{
                padding: 14, borderRadius: 10,
                background: "var(--rose-tint)", border: "1px solid color-mix(in oklab, var(--rose) 20%, transparent)",
              }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
                  <div style={{ fontFamily: "var(--font-serif)", fontSize: 16 }}>
                    {lang === "ko" ? w.nameKo : w.nameEn}
                  </div>
                  <div className="mono tabular" style={{ color: "var(--rose)", fontSize: 13 }}>{w.pct}%</div>
                </div>
                <div style={{ marginTop: 10, height: 4, background: "white", borderRadius: 2, overflow: "hidden" }}>
                  <div style={{ width: `${w.pct}%`, height: "100%", background: "var(--rose)" }} />
                </div>
                <div style={{ marginTop: 8, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                  <div style={{ fontSize: 12, color: "var(--ink-3)" }}>
                    {lang === "ko" ? "4개 연습 문제 준비됨" : "4 practice Qs ready"}
                  </div>
                  <button
                    onClick={() => alert("Coming soon")}
                    style={{
                      background: "transparent", border: "none", color: "var(--ink-1)",
                      fontSize: 12, cursor: "pointer", fontFamily: "inherit", textDecoration: "underline",
                    }}>
                    {lang === "ko" ? "연습 시작 →" : "Practice →"}
                  </button>
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* History */}
      <div style={{ marginTop: 28 }}>
        <h2 style={{ fontSize: 20, marginBottom: 14 }}>{t("dash_history")}</h2>
        <div style={{ background: "white", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden" }}>
          <div style={{
            display: "grid", gridTemplateColumns: "1fr 100px 120px 140px 100px 80px",
            padding: "12px 18px", background: "var(--paper-2)", borderBottom: "1px solid var(--line)",
            fontSize: 11, color: "var(--ink-3)", letterSpacing: "0.08em", textTransform: "uppercase", fontFamily: "var(--font-mono)",
          }}>
            <div>{lang === "ko" ? "시험" : "Paper"}</div>
            <div>{lang === "ko" ? "날짜" : "Date"}</div>
            <div>{lang === "ko" ? "점수" : "Score"}</div>
            <div>{lang === "ko" ? "백분위" : "Percentile"}</div>
            <div>{lang === "ko" ? "모드" : "Mode"}</div>
            <div></div>
          </div>
          {history.length === 0 && (
            <div style={{
              padding: "32px 18px", textAlign: "center", color: "var(--ink-3)", fontSize: 13,
            }}>
              {lang === "ko" ? "아직 응시한 시험이 없습니다. 시험을 시작해보세요." : "No papers taken yet. Start one to see your report."}
            </div>
          )}
          {history.map((h, i) => (
            <div key={h.id} style={{
              display: "grid", gridTemplateColumns: "1fr 100px 120px 140px 100px 80px",
              padding: "14px 18px", alignItems: "center",
              borderBottom: i === history.length - 1 ? "none" : "1px solid var(--line)",
              fontSize: 14,
            }}>
              <div style={{ fontFamily: "var(--font-serif)" }}>
                {h.paperId === 0
                  ? (lang === "ko" ? "샘플 · 10문제" : "Sample · 10 Q")
                  : `Mock paper ${String(h.paperId).padStart(2, "0")}`}
              </div>
              <div className="mono" style={{ color: "var(--ink-3)", fontSize: 12 }}>{h.date}</div>
              <div className="mono tabular">{h.score != null ? `${h.score}/${h.total}` : `—/${h.total}`} <span style={{ color: "var(--ink-4)" }}>{h.score != null ? `· ${Math.round(h.score / h.total * 100)}%` : ""}</span></div>
              <div className="mono tabular" style={{ color: "var(--indigo)" }}>{h.score != null && h.percentile != null ? `Top ${100 - h.percentile}%` : "—"}</div>
              <div className="mono" style={{ fontSize: 11, color: "var(--ink-3)" }}>{(h.mode || "online").toUpperCase()}</div>
              <button
                onClick={() => onViewReport && onViewReport(h.id)}
                style={{ border: "none", background: "transparent", color: "var(--ink-1)", fontSize: 13, cursor: "pointer", textDecoration: "underline", fontFamily: "inherit" }}>
                {lang === "ko" ? "리포트" : "Report"}
              </button>
            </div>
          ))}
        </div>
      </div>
    </main>
  );
}

Object.assign(window, { ResultsView, QuestionReview, UserDashboard, buildResults });
