// Examine — Practice / Exam runner
function Runner({ state, setState, sessionId, onExit }) {
  const session = state.sessions[sessionId];
  if (!session) return <div className="empty">Session not found.</div>;
  const set = window.EXAM_DATA.sets.find(s => s.id === session.setId);
  const [current, setCurrent] = useState(session.currentIdx || 0);
  const [showFeedback, setShowFeedback] = useState(false);
  const [now, setNow] = useState(Date.now());

  const isExam = session.mode === 'exam';
  const finished = !!session.finishedAt;

  // Timer
  useEffect(() => {
    if (!isExam || finished || !state.timerEnabled) return;
    const t = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(t);
  }, [isExam, finished, state.timerEnabled]);

  const timerInfo = useMemo(() => {
    if (!isExam || !state.timerEnabled) return null;
    const total = state.timerMinutes * 60 * 1000;
    const elapsed = now - (session.startedAt || now);
    const remaining = Math.max(0, total - elapsed);
    const mm = Math.floor(remaining / 60000);
    const ss = Math.floor((remaining % 60000) / 1000);
    return { remaining, label: `${String(mm).padStart(2,'0')}:${String(ss).padStart(2,'0')}`, warn: remaining < 5*60*1000 };
  }, [now, isExam, state.timerEnabled, state.timerMinutes, session.startedAt]);

  // Auto-finish on timeout
  useEffect(() => {
    if (timerInfo && timerInfo.remaining === 0 && !finished) finish();
  }, [timerInfo?.remaining]);

  // Persist current idx
  useEffect(() => {
    setState(s => ({
      ...s,
      sessions: { ...s.sessions, [sessionId]: { ...s.sessions[sessionId], currentIdx: current } }
    }));
    setShowFeedback(!!session.answers[current] !== undefined && !isExam);
  }, [current]);

  const q = set.questions[current];
  const selected = session.answers[current];
  const hasAnswered = selected !== undefined;

  const recordAnswer = (choiceIdx) => {
    if (hasAnswered && !isExam) return; // lock answer in practice once given
    setState(s => {
      const updated = { ...s.sessions[sessionId].answers, [current]: choiceIdx };
      return {
        ...s,
        sessions: { ...s.sessions, [sessionId]: { ...s.sessions[sessionId], answers: updated } }
      };
    });
    if (!isExam) setShowFeedback(true);
  };

  const goNext = () => { if (current < set.questions.length - 1) { setCurrent(current + 1); setShowFeedback(false); } };
  const goPrev = () => { if (current > 0) { setCurrent(current - 1); setShowFeedback(!isExam); } };

  function finish() {
    setState(s => {
      const sess = s.sessions[sessionId];
      const correct = Object.entries(sess.answers || {}).filter(([i, a]) => set.questions[+i].a === a).length;
      const finished = { ...sess, finishedAt: Date.now(), score: correct };
      const history = [...(s.history || []), { setId: set.id, mode: sess.mode, score: correct, total: set.questions.length, finishedAt: finished.finishedAt }];
      return {
        ...s,
        sessions: { ...s.sessions, [sessionId]: finished },
        activeSession: null,
        history
      };
    });
  }

  // Keyboard
  useEffect(() => {
    const onKey = (e) => {
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
      if (e.key === 'ArrowRight') goNext();
      else if (e.key === 'ArrowLeft') goPrev();
      else if (['1','2','3','4','5'].includes(e.key)) {
        const ix = +e.key - 1;
        if (q && ix < q.c.length) recordAnswer(ix);
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [current, hasAnswered]);

  if (finished) return <Results state={state} session={state.sessions[sessionId]} set={set} onExit={onExit} onRetry={() => {
    // start fresh session
    const newId = 'sess_' + Date.now();
    setState(s => ({
      ...s,
      sessions: { ...s.sessions, [newId]: { setId: set.id, mode: session.mode, answers: {}, startedAt: Date.now(), currentIdx: 0 } },
      activeSession: newId
    }));
  }} />;

  const answeredCount = Object.keys(session.answers || {}).length;

  return (
    <div className="fade-in">
      <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom:'1.2rem', flexWrap:'wrap', gap:'1rem'}}>
        <div>
          <div className="eyebrow" style={{fontSize:'0.72rem', letterSpacing:'0.16em', textTransform:'uppercase', color:'var(--ink-3)', fontWeight:600}}>{set.title}</div>
          <h2 style={{marginTop:'0.4rem'}}>{isExam ? 'Exam Mode' : 'Practice Session'}</h2>
        </div>
        <button className="btn btn-ghost" onClick={onExit}>Exit</button>
      </div>

      <ModeBanner
        mode={session.mode}
        onMode={(m) => setState(s => ({...s, sessions: {...s.sessions, [sessionId]: {...s.sessions[sessionId], mode: m}}}))}
        instantFeedback={state.instantFeedback}
        onInstant={(v) => setState(s => ({...s, instantFeedback: v}))}
        role={state.role}
        timer={timerInfo}
      />

      <div className="exam-shell">
        <aside className="q-rail">
          <h4>Questions</h4>
          <div className="q-grid">
            {set.questions.map((qq, i) => {
              const ans = session.answers[i];
              const isAnswered = ans !== undefined;
              const isCurrent = i === current;
              const showResult = isExam ? false : isAnswered;
              const isCorrect = isAnswered && ans === qq.a;
              const cls = ['q-pill'];
              if (isCurrent) cls.push('current');
              else if (showResult) cls.push(isCorrect ? 'correct' : 'wrong');
              else if (isAnswered) cls.push('answered');
              return <button key={i} className={cls.join(' ')} onClick={() => { setCurrent(i); setShowFeedback(!isExam && isAnswered); }}>{i+1}</button>;
            })}
          </div>
          <div className="rail-meta">
            <div className="row"><span>Answered</span><span className="v">{answeredCount}/{set.questions.length}</span></div>
            <div className="row"><span>Progress</span><span className="v">{Math.round(answeredCount/set.questions.length*100)}%</span></div>
            {state.role === 'instructor' && (
              <div className="row"><span>Mode</span><span className="v">{session.mode}</span></div>
            )}
          </div>
          <button className="btn btn-clay" style={{width:'100%', marginTop:'1rem', justifyContent:'center'}} onClick={() => {
            if (answeredCount < set.questions.length && !confirm(`You have ${set.questions.length - answeredCount} unanswered question(s). Submit anyway?`)) return;
            finish();
          }}>
            Submit Exam
          </button>
        </aside>

        <main>
          <div className="q-card">
            <div className="q-meta">
              <span className="q-num">Question {current+1} / {set.questions.length}</span>
              <TopicTag topic={q.t} />
              {state.role === 'instructor' && <span className="tag" style={{background:'var(--plum-soft)', color:'var(--plum)', borderColor:'transparent'}}>Answer: {String.fromCharCode(65 + q.a)}</span>}
            </div>
            <div className="q-stem">{q.q}</div>

            <div className="choices">
              {q.c.map((choice, i) => {
                const cls = ['choice'];
                const showAnswerState = showFeedback || (isExam && finished);
                if (showAnswerState) {
                  if (i === q.a) cls.push('correct');
                  else if (i === selected) cls.push('incorrect');
                  else cls.push('dim');
                } else if (selected === i) cls.push('selected');
                return (
                  <div key={i} className={cls.join(' ')} onClick={() => recordAnswer(i)}>
                    <div className="choice-letter">{String.fromCharCode(65+i)}</div>
                    <div className="choice-text">{choice}</div>
                  </div>
                );
              })}
            </div>

            {showFeedback && (
              <div className={`feedback ${selected === q.a ? 'correct' : 'wrong'}`}>
                <h4>{selected === q.a ? '✓ Correct' : '✗ Not quite'} — Explanation</h4>
                <p>{q.e}</p>
              </div>
            )}

            <div className="q-actions">
              <div className="left">
                <button className="btn btn-ghost" onClick={goPrev} disabled={current === 0}><Icon name="arrowL" size={14}/> Prev</button>
                <button className="btn btn-ghost" onClick={goNext} disabled={current === set.questions.length - 1}>Next <Icon name="arrow" size={14}/></button>
              </div>
              <div style={{display:'flex', gap:'0.5rem', alignItems:'center', fontSize:'0.78rem', color:'var(--ink-3)'}}>
                <span className="kbd">←</span><span className="kbd">→</span> nav · <span className="kbd">1</span>–<span className="kbd">{q.c.length}</span> select
              </div>
            </div>
          </div>
        </main>
      </div>
    </div>
  );
}

function Results({ session, set, onExit, onRetry }) {
  const correct = Object.entries(session.answers || {}).filter(([i, a]) => set.questions[+i].a === a).length;
  const total = set.questions.length;
  const pct = correct / total;
  const skipped = total - Object.keys(session.answers || {}).length;
  const wrong = total - correct - skipped;
  const elapsed = session.finishedAt && session.startedAt ? Math.floor((session.finishedAt - session.startedAt) / 60000) : null;

  // Topic breakdown
  const topicAgg = {};
  set.questions.forEach((q, i) => {
    if (!topicAgg[q.t]) topicAgg[q.t] = { correct: 0, total: 0 };
    topicAgg[q.t].total++;
    if (session.answers[i] === q.a) topicAgg[q.t].correct++;
  });

  const [reviewIdx, setReviewIdx] = useState(null);

  return (
    <div className="fade-in">
      <div className="results-hero">
        <ScoreRing pct={pct} label={`${correct} / ${total}`} />
        <h2 style={{marginBottom:'0.4rem'}}>{pct >= 0.85 ? 'Outstanding' : pct >= 0.7 ? 'Solid work' : pct >= 0.5 ? 'Keep going' : 'Time to review'}</h2>
        <p style={{color:'var(--ink-3)', maxWidth:'48ch', margin:'0 auto'}}>{set.title} · {session.mode === 'exam' ? 'Exam' : 'Practice'}</p>
      </div>

      <div className="results-summary">
        <div className="summary-tile"><div className="num" style={{color:'var(--good)'}}>{correct}</div><div className="lbl">Correct</div></div>
        <div className="summary-tile"><div className="num" style={{color:'var(--bad)'}}>{wrong}</div><div className="lbl">Incorrect</div></div>
        <div className="summary-tile"><div className="num" style={{color:'var(--ink-3)'}}>{skipped}</div><div className="lbl">Skipped</div></div>
        {elapsed !== null && <div className="summary-tile"><div className="num">{elapsed}<span style={{fontSize:'0.9rem', color:'var(--ink-3)'}}>m</span></div><div className="lbl">Time</div></div>}
      </div>

      <div className="section-title">Topic breakdown</div>
      <div className="panel" style={{marginBottom:'2rem'}}>
        {Object.entries(topicAgg).map(([t, v]) => {
          const tInfo = window.EXAM_DATA.topics[t];
          const tPct = v.correct / v.total;
          return (
            <div key={t} className="topic-row">
              <div className="lbl"><TopicDot topic={t} />{tInfo?.label}</div>
              <div className="bar"><div style={{ width: `${tPct*100}%`, background: tInfo?.color }}></div></div>
              <div className="pct">{v.correct}/{v.total}</div>
            </div>
          );
        })}
      </div>

      <div className="section-title">Question-by-question</div>
      <div className="review-list">
        {set.questions.map((q, i) => {
          const ans = session.answers[i];
          const status = ans === undefined ? 'skipped' : (ans === q.a ? 'correct' : 'wrong');
          return (
            <div key={i} className="review-item" onClick={() => setReviewIdx(reviewIdx === i ? null : i)}>
              <span className="ix">Q{String(i+1).padStart(2,'0')}</span>
              <div>
                <div className="stem">{q.q}</div>
                {reviewIdx === i && (
                  <div style={{marginTop:'0.6rem', paddingTop:'0.6rem', borderTop:'1px dashed var(--rule)'}}>
                    {q.c.map((c, ci) => (
                      <div key={ci} style={{
                        padding:'0.4rem 0.7rem', marginBottom:'0.3rem', borderRadius:'6px',
                        background: ci === q.a ? 'var(--moss-soft)' : ci === ans ? 'var(--clay-soft)' : 'transparent',
                        color: ci === q.a ? 'var(--good)' : ci === ans && ans !== q.a ? 'var(--bad)' : 'var(--ink-3)',
                        fontSize:'0.9rem'
                      }}>
                        <strong>{String.fromCharCode(65+ci)}.</strong> {c}
                      </div>
                    ))}
                    <div style={{marginTop:'0.6rem', fontSize:'0.88rem', fontFamily:'var(--serif)', color:'var(--ink-2)', fontStyle:'italic'}}>{q.e}</div>
                  </div>
                )}
              </div>
              <span className={`badge ${status}`}>{status}</span>
            </div>
          );
        })}
      </div>

      <div style={{display:'flex', gap:'0.6rem', justifyContent:'center', marginTop:'2.5rem'}}>
        <button className="btn btn-primary" onClick={onRetry}>Retry this set</button>
        <button className="btn btn-ghost" onClick={onExit}>Back to home</button>
      </div>
    </div>
  );
}

window.Runner = Runner;
window.Results = Results;
