/* global React, Mascot, Confetti, Btn, ProgressBar, StreakBadge, Icon */
const { useState, useEffect, useRef, useMemo } = React;

// Local hook by design — duplicated into screens-1 and screens-3; no shared module under no-bundler constraint.
function useIsNarrow(breakpoint = 720) {
  const [narrow, setNarrow] = useState(() =>
    typeof window !== 'undefined' ? window.innerWidth <= breakpoint : false
  );
  useEffect(() => {
    setNarrow(window.innerWidth <= breakpoint);
    const onResize = () => setNarrow(window.innerWidth <= breakpoint);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, [breakpoint]);
  return narrow;
}

// ============================================================
// QUIZ SETUP — pick count + domain filter
// ============================================================
function QuizSetup({ course, mode, onStart, onBack, theme }) {
  const [count, setCount] = useState(25);
  const [domain, setDomain] = useState('');
  const counts = mode === 'study' ? [10, 20, 50] : [10, 25, 50, course.questionCount];

  const titleMap = {
    drill: 'Drill mode',
    study: 'Study session',
    mock:  'Mock exam',
  };
  const descMap = {
    drill: 'Random practice. Get instant feedback after each question.',
    study: `${course.progress?.dueNow ?? 0} due for review · spaced repetition prioritizes overdue items first.`,
    mock:  `${course.mockExam?.questionCount} questions · ${course.mockExam?.durationMinutes} min · no feedback during exam.`,
  };

  return (
    <div style={{ maxWidth: 720, margin: '0 auto', padding: '32px 32px 80px' }}>
      <Btn variant="ghost" size="sm" icon={<Icon name="arrow-left" size={18}/>} onClick={onBack}>Home</Btn>

      <header style={{ margin: '24px 0 32px', display: 'flex', alignItems: 'center', gap: 20 }}>
        <div style={{ flexShrink: 0 }}><Mascot mood="ready" size={90} theme={theme} /></div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
          <h1 style={{ fontSize: 'clamp(30px, 4vw, 44px)' }}>{titleMap[mode]}</h1>
          <p style={{ color: 'var(--ink-soft)', fontSize: 17 }}>{descMap[mode]}</p>
        </div>
      </header>

      {mode !== 'mock' && (
        <div className="card" style={{ marginBottom: 20 }}>
          <div style={{ fontSize: 12, fontWeight: 800, textTransform: 'uppercase', letterSpacing: '0.06em', color: 'var(--ink-soft)', marginBottom: 12 }}>
            How many questions?
          </div>
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            {counts.map(n => (
              <Btn
                key={n}
                variant={count === n ? 'primary' : 'default'}
                size="lg"
                onClick={() => setCount(n)}
              >
                {n === course.questionCount ? 'All' : n}
              </Btn>
            ))}
          </div>
        </div>
      )}

      {mode === 'drill' && (
        <div className="card" style={{ marginBottom: 20 }}>
          <div style={{ fontSize: 12, fontWeight: 800, textTransform: 'uppercase', letterSpacing: '0.06em', color: 'var(--ink-soft)', marginBottom: 12 }}>
            Domain filter
          </div>
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            <Btn variant={domain === '' ? 'secondary' : 'default'} onClick={() => setDomain('')}>All domains</Btn>
            {course.domains.map(d => (
              <Btn key={d.id} variant={domain === d.id ? 'secondary' : 'default'} onClick={() => setDomain(d.id)}>
                {d.id} {d.label}
              </Btn>
            ))}
          </div>
        </div>
      )}

      {mode === 'mock' && (
        <div className="card" style={{ marginBottom: 20 }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16 }}>
            <Stat label="Questions" value={course.mockExam.questionCount} />
            <Stat label="Minutes" value={course.mockExam.durationMinutes} />
            <Stat label="Pass" value={`${course.mockExam.passThresholdPct}%`} />
          </div>
        </div>
      )}

      <Btn variant="primary" size="xl" onClick={() => onStart({ count, domain })} style={{ width: '100%' }}>
        Let's go <Icon name="arrow-right" size={22} strokeWidth={3} />
      </Btn>
    </div>
  );
}

function Stat({ label, value }) {
  return (
    <div style={{ textAlign: 'center' }}>
      <div style={{ fontSize: 36, fontFamily: 'var(--font-display)', fontWeight: 900, lineHeight: 1 }}>{value}</div>
      <div style={{ fontSize: 11, fontWeight: 800, textTransform: 'uppercase', letterSpacing: '0.06em', color: 'var(--ink-soft)', marginTop: 4 }}>{label}</div>
    </div>
  );
}

// ============================================================
// QUIZ SESSION — the main play surface
// ============================================================
function QuizSession({ course, mode, questions, startedAt, onFinish, onExit, theme }) {
  const [deck, setDeck] = useState(questions);
  const [idx, setIdx] = useState(0);
  const [selected, setSelected] = useState([]);
  const [phase, setPhase] = useState('answering'); // answering | feedback
  const [attempts, setAttempts] = useState(() => new Map());
  const [streakInRun, setStreakInRun] = useState(0);
  const [wrongInRow, setWrongInRow] = useState(0);
  const [showConfetti, setShowConfetti] = useState(false);
  const [shake, setShake] = useState(false);
  const finishedRef = useRef(false);
  const isNarrow = useIsNarrow();

  const isMock = mode === 'mock';
  const mockStartedAtMs = useMemo(
    () => (startedAt ? new Date(startedAt).getTime() : Date.now()),
    [startedAt]
  );
  const mockDurationMs = useMemo(
    () => (course.mockExam?.durationMinutes ?? 90) * 60 * 1000,
    [course.mockExam?.durationMinutes]
  );
  const [nowMs, setNowMs] = useState(() => Date.now());

  useEffect(() => {
    if (!isMock) return;
    const id = setInterval(() => setNowMs(Date.now()), 250);
    return () => clearInterval(id);
  }, [isMock]);

  const timer = isMock
    ? window.QuizEngine.tickMockTimer({ startedAt: mockStartedAtMs, durationMs: mockDurationMs, now: nowMs })
    : null;

  useEffect(() => {
    if (!isMock || !timer?.expired) return;
    const final = new Map(attempts);
    for (const dq of deck) {
      if (!final.has(dq.id)) {
        final.set(dq.id, window.QuizEngine.mergeAttempt(undefined, {
          questionId: dq.id,
          selected: [],
          correct: false,
        }));
      }
    }
    finishOnce({ answers: Array.from(final.values()), questions });
  }, [isMock, timer?.expired, attempts, deck, finishOnce, questions]);

  const handleExit = () => {
    if (isMock) {
      const ok = window.confirm('End the exam now? Unanswered questions will be marked wrong.');
      if (!ok) return;
      const final = new Map(attempts);
      for (const dq of deck) {
        if (!final.has(dq.id)) {
          final.set(dq.id, window.QuizEngine.mergeAttempt(undefined, {
            questionId: dq.id,
            selected: [],
            correct: false,
          }));
        }
      }
      finishOnce({ answers: Array.from(final.values()), questions });
      return;
    }
    onExit();
  };

  const q = deck[idx];
  const isMulti = q.type === 'multiple';
  const correctSet = useMemo(() => new Set(q.correct), [q]);
  const isCorrect = phase === 'feedback' && arraysEqual(selected.sort(), [...q.correct].sort());

  const toggle = (label) => {
    if (phase !== 'answering') return;
    if (isMulti) {
      setSelected(s => s.includes(label) ? s.filter(x => x !== label) : [...s, label]);
    } else {
      setSelected([label]);
    }
  };

  const finishOnce = (payload) => {
    if (finishedRef.current) return;
    finishedRef.current = true;
    onFinish(payload);
  };

  const submit = () => {
    if (selected.length === 0) return;
    const correct = arraysEqual([...selected].sort(), [...q.correct].sort());
    const updated = new Map(attempts);
    updated.set(q.id, window.QuizEngine.mergeAttempt(updated.get(q.id), {
      questionId: q.id,
      selected,
      correct,
    }));
    setAttempts(updated);

    if (isMock) {
      if (idx + 1 >= deck.length) {
        finishOnce({ answers: Array.from(updated.values()), questions });
      } else {
        setIdx(idx + 1);
        setSelected([]);
        // remain in 'answering' phase
      }
      return;
    }

    setPhase('feedback');
    if (correct) {
      setStreakInRun(s => s + 1);
      setWrongInRow(0);
      if (streakInRun + 1 >= 3) {
        setShowConfetti(true);
        setTimeout(() => setShowConfetti(false), 2200);
      }
    } else {
      setStreakInRun(0);
      setWrongInRow(w => w + 1);
      setShake(true);
      setTimeout(() => setShake(false), 500);
      if (mode === 'study') {
        setDeck(d => window.QuizEngine.requeueOnMiss(d, idx, q.id, 5));
      }
    }
  };

  const next = () => {
    if (idx + 1 >= deck.length) {
      finishOnce({ answers: Array.from(attempts.values()), questions });
    } else {
      setIdx(idx + 1);
      setSelected([]);
      setPhase('answering');
    }
  };

  // keyboard
  useEffect(() => {
    const onKey = (e) => {
      if (isMock || phase === 'answering') {
        if (['1','2','3','4'].includes(e.key)) {
          const i = Number(e.key) - 1;
          if (q.options[i]) toggle(q.options[i].label);
        } else if (e.key === 'Enter' && selected.length > 0) {
          submit();
        }
      } else {
        if (e.key === 'Enter' || e.key === 'ArrowRight' || e.key === ' ') next();
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [phase, selected, idx, isMock]);

  // Context-aware mood: while answering, thinking; on feedback, react.
  // Sympathetic mood after 2+ wrong in a row — less harsh than 'failed-sad'.
  const mood = phase === 'feedback'
    ? (isCorrect
        ? (streakInRun >= 5 ? 'fire-streak' : streakInRun >= 3 ? 'celebrate' : streakInRun >= 1 ? 'mild-happy' : 'happy')
        : (wrongInRow >= 2 ? 'sympathetic' : 'sad'))
    : 'thinking';

  return (
    <div style={{ maxWidth: 880, margin: '0 auto', padding: isNarrow ? '16px 16px 60px' : '24px 32px 80px' }} className={shake ? 'shake' : ''}>
      <Confetti active={showConfetti} />

      {/* top bar */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 18 }}>
        <Btn variant="ghost" size="sm" icon={<Icon name="x" size={18}/>} onClick={handleExit}>
          {isMock ? 'End exam' : 'Exit'}
        </Btn>
        <div className="font-mono" style={{ fontSize: 13, color: 'var(--ink-soft)', fontWeight: 700 }}>
          {capitalize(mode)} · Q{idx + 1}/{deck.length}
        </div>
        <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 10 }}>
          {isMock && timer && (
            <div
              className="chip font-mono"
              style={{
                fontWeight: 800,
                fontSize: 16,
                padding: '6px 14px',
                background: timer.remainingMs < 60_000 ? 'var(--incorrect-bg)' : 'var(--surface-2)',
                color: timer.remainingMs < 60_000 ? 'var(--incorrect)' : 'var(--ink)',
              }}
            >
              {formatTimer(timer.remainingMs)}
            </div>
          )}
          {!isMock && streakInRun >= 2 && (
            <div className="chip chip-tertiary pop-in" key={streakInRun}>
              <Icon name="lightning" size={14}/> {streakInRun} in a row
            </div>
          )}
        </div>
      </div>

      <ProgressBar value={idx + (phase === 'feedback' ? 1 : 0)} max={deck.length} height={20} />

      <div style={{
        display: 'grid',
        gridTemplateColumns: isNarrow ? '1fr' : '110px 1fr',
        gap: isNarrow ? 12 : 24,
        marginTop: isNarrow ? 18 : 28,
        alignItems: 'start',
      }}>
        {!isNarrow && (
          <div style={{ position: 'sticky', top: 20 }}>
            <Mascot mood={mood} size={110} theme={theme} />
          </div>
        )}

        <div className="card pop-in" key={q.id} style={{ minHeight: isNarrow ? 0 : 400 }}>
          <div className="chip" style={{ marginBottom: 14 }}>Domain {q.domain}</div>
          <h2 style={{ fontSize: isNarrow ? 18 : 24, lineHeight: 1.3, marginBottom: isNarrow ? 18 : 24, fontFamily: 'var(--font-body)', fontWeight: 800 }}>
            {q.question}
          </h2>

          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {q.options.map((o, i) => {
              const isSelected = selected.includes(o.label);
              const isCorrectOpt = correctSet.has(o.label);
              const reveal = phase === 'feedback';
              let bg = 'var(--surface)';
              let border = 'var(--line)';
              let ring = '';
              if (reveal) {
                if (isCorrectOpt) { bg = 'var(--correct-bg)'; border = 'var(--correct)'; }
                else if (isSelected) { bg = 'var(--incorrect-bg)'; border = 'var(--incorrect)'; }
              } else if (isSelected) {
                bg = 'var(--bg-tint)';
                border = 'var(--primary)';
                ring = 'var(--primary)';
              }
              return (
                <OptionRow
                  key={o.label}
                  option={o}
                  index={i}
                  selected={isSelected}
                  reveal={reveal}
                  isCorrect={isCorrectOpt}
                  bg={bg}
                  border={border}
                  ring={ring}
                  onClick={() => toggle(o.label)}
                />
              );
            })}
          </div>

          {isMulti && phase === 'answering' && (
            <p style={{ marginTop: 14, fontSize: 13, color: 'var(--muted)', fontStyle: 'italic' }}>
              Multi-select — choose all that apply.
            </p>
          )}

          {!isMock && phase === 'feedback' && (
            <div className="pop-in" style={{
              marginTop: 24, padding: 20, borderRadius: 'var(--radius)',
              background: isCorrect ? 'var(--correct-bg)' : 'var(--incorrect-bg)',
              border: 'var(--outline-width) solid ' + (isCorrect ? 'var(--correct)' : 'var(--incorrect)'),
            }}>
              <div style={{
                display: 'flex', alignItems: 'center', gap: 10,
                fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 26,
                color: isCorrect ? 'var(--correct)' : 'var(--incorrect)',
                marginBottom: 8,
              }}>
                {isCorrect ? <><Icon name="check" size={28} strokeWidth={4}/> Nailed it!</>
                           : <><Icon name="x" size={28} strokeWidth={4}/> Not quite.</>}
              </div>
              <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--ink)', marginBottom: 6 }}>
                Correct answer: <strong>{q.correct.join(', ')}</strong>
              </div>
              {q.explanation
                ? <p style={{ fontSize: 14, color: 'var(--ink-soft)', lineHeight: 1.5 }}>{q.explanation}</p>
                : <p style={{ fontSize: 13, color: 'var(--muted)', fontStyle: 'italic', lineHeight: 1.5 }}>
                    No explanation captured for this question yet ({q.id}).
                  </p>}
            </div>
          )}

          <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 24, gap: 10 }}>
            {(isMock || phase === 'answering') ? (
              <Btn variant="primary" size="lg" disabled={selected.length === 0} onClick={submit}>
                {isMock && idx + 1 >= deck.length ? 'Submit & finish' : 'Submit'}
              </Btn>
            ) : (
              <Btn variant="primary" size="lg" onClick={next}>
                {idx + 1 >= deck.length ? 'See results' : 'Next'}
                <Icon name="arrow-right" size={20} strokeWidth={3}/>
              </Btn>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

function OptionRow({ option, index, selected, reveal, isCorrect, bg, border, ring, onClick }) {
  const [press, setPress] = useState(false);
  return (
    <div
      onClick={() => {
        if (!reveal) { setPress(true); setTimeout(() => setPress(false), 300); }
        onClick();
      }}
      className={press ? 'squish' : ''}
      style={{
        display: 'flex', alignItems: 'center', gap: 14,
        padding: 16,
        background: bg,
        border: 'var(--outline-width) solid ' + border,
        borderRadius: 'var(--radius)',
        cursor: reveal ? 'default' : 'pointer',
        boxShadow: ring ? `0 0 0 4px color-mix(in oklch, ${ring} 30%, transparent)` : 'none',
        transition: 'all 140ms var(--ease-out-soft)',
        userSelect: 'none',
      }}
    >
      <div style={{
        width: 36, height: 36, flexShrink: 0,
        borderRadius: '50%',
        background: selected || (reveal && isCorrect) ? (reveal ? (isCorrect ? 'var(--correct)' : 'var(--incorrect)') : 'var(--primary)') : 'var(--surface-2)',
        color: selected || (reveal && isCorrect) ? '#fff' : 'var(--ink)',
        border: 'var(--outline-width) solid var(--line)',
        display: 'grid', placeItems: 'center',
        fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 16,
      }}>
        {reveal && isCorrect ? <Icon name="check" size={18} strokeWidth={4} color="#fff"/>
         : reveal && selected && !isCorrect ? <Icon name="x" size={18} strokeWidth={4} color="#fff"/>
         : option.label}
      </div>
      <div style={{ fontWeight: 600, fontSize: 16, lineHeight: 1.4, flex: 1 }}>{option.text}</div>
      <div className="font-mono" style={{ fontSize: 11, color: 'var(--muted)', fontWeight: 700 }}>{index + 1}</div>
    </div>
  );
}

function arraysEqual(a, b) {
  if (a.length !== b.length) return false;
  for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
  return true;
}
function capitalize(s) { return s[0].toUpperCase() + s.slice(1); }

function formatTimer(ms) {
  const totalSeconds = Math.ceil(ms / 1000);
  const m = Math.floor(totalSeconds / 60);
  const s = totalSeconds % 60;
  return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
}

Object.assign(window, { QuizSetup, QuizSession });
