/* global React, Mascot, Confetti, Btn, ProgressBar, StreakBadge, Icon */
const { useState, useEffect, 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;
}

// ============================================================
// RESULTS
// ============================================================
function Results({ course, mode, answers, questions, onHome, onRestudy, theme }) {
  const isNarrow = useIsNarrow();
  const correct = answers.filter(a => a.correct).length;
  const total = answers.length;
  const pct = total ? Math.round((correct / total) * 100) : 0;
  const passed = mode === 'mock' ? pct >= (course.mockExam?.passThresholdPct ?? 78) : pct >= 70;
  const missed = answers.filter(a => !a.correct);

  // domain breakdown
  const byDomain = {};
  for (const a of answers) {
    const q = questions.find(x => x.id === a.questionId);
    if (!q) continue;
    const d = q.domain;
    if (!byDomain[d]) byDomain[d] = { seen: 0, correct: 0 };
    byDomain[d].seen++;
    if (a.correct) byDomain[d].correct++;
  }

  const [confetti, setConfetti] = useState(passed && pct >= 80);
  useEffect(() => {
    if (confetti) {
      const t = setTimeout(() => setConfetti(false), 2400);
      return () => clearTimeout(t);
    }
  }, []);

  const message = pct >= 90 ? "Beautiful work."
                : pct >= 80 ? "Nice run."
                : pct >= 70 ? "Solid — a few spots to revisit."
                : pct >= 50 ? "Keep going. Study mode will help."
                : "Tough round. Rest up, come back fresh.";

  // Pick precise mascot mood based on outcome tier
  const resultMood = mode === 'mock'
    ? (passed ? 'fire-streak' : 'sympathetic')
    : !passed
      ? (pct < 50 ? 'failed-sad' : 'sympathetic')
      : (pct >= 90 ? 'celebrate' : pct >= 80 ? 'passed-cheer' : 'barely-passed');

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

      <Btn variant="ghost" size="sm" icon={<Icon name="arrow-left" size={18}/>} onClick={onHome}>Home</Btn>

      <header style={{
        display: 'grid',
        gridTemplateColumns: isNarrow ? '1fr' : '1fr auto',
        alignItems: 'center',
        gap: isNarrow ? 16 : 24,
        margin: isNarrow ? '16px 0 20px' : '24px 0 32px',
      }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
          <div className="chip chip-primary" style={{ alignSelf: 'flex-start', whiteSpace: 'nowrap' }}>{capitalize(mode)} session</div>
          <h1 style={{ fontSize: 'clamp(34px, 4.6vw, 52px)' }}>{message}</h1>
          <p style={{ fontSize: 18, color: 'var(--ink-soft)' }}>You answered <strong>{correct}</strong> of <strong>{total}</strong> correctly.</p>
        </div>
        <div className="float-y">
          <Mascot mood={resultMood} size={150} theme={theme} />
        </div>
      </header>

      {mode === 'mock' && (
        <div
          className="card pop-in"
          style={{
            textAlign: 'center',
            padding: '20px 24px',
            marginBottom: 16,
            background: passed ? 'var(--correct-bg)' : 'var(--incorrect-bg)',
            border: 'var(--outline-width) solid ' + (passed ? 'var(--correct)' : 'var(--incorrect)'),
          }}
        >
          <div
            style={{
              fontFamily: 'var(--font-display)',
              fontWeight: 900,
              fontSize: 28,
              color: passed ? 'var(--correct)' : 'var(--incorrect)',
            }}
          >
            {passed
              ? `Passed · ${pct}% (threshold ${course.mockExam?.passThresholdPct}%)`
              : `Below threshold · ${pct}% (need ${course.mockExam?.passThresholdPct}%)`}
          </div>
        </div>
      )}

      {/* big score card */}
      <div className="card pop-in" style={{
        textAlign: 'center', padding: '40px 24px',
        background: passed ? 'var(--correct-bg)' : 'var(--surface)',
        marginBottom: 24,
      }}>
        <div style={{ fontSize: 14, fontWeight: 800, textTransform: 'uppercase', letterSpacing: '0.08em', color: 'var(--ink-soft)', marginBottom: 8 }}>
          {mode === 'mock' ? `Pass threshold ≈ ${course.mockExam?.passThresholdPct}%` : 'Score'}
        </div>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 'clamp(72px, 12vw, 120px)', lineHeight: 0.95, color: passed ? 'var(--correct)' : 'var(--incorrect)' }}>
          {pct}%
        </div>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22, color: 'var(--ink-soft)', marginTop: 12 }}>
          {correct} / {total}
        </div>
      </div>

      {/* domain breakdown */}
      <div className="card" style={{ marginBottom: 20 }}>
        <h2 style={{ fontSize: 24, marginBottom: 16 }}>By domain</h2>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          {Object.entries(byDomain).map(([d, s]) => {
            const dPct = Math.round((s.correct / s.seen) * 100);
            const color = dPct >= 80 ? 'var(--correct)' : dPct >= 60 ? 'var(--tertiary)' : 'var(--incorrect)';
            return (
              <div key={d}>
                <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6, fontSize: 14, fontWeight: 800 }}>
                  <span>Domain {d}</span>
                  <span className="font-mono">{s.correct}/{s.seen} · {dPct}%</span>
                </div>
                <ProgressBar value={s.correct} max={s.seen} color={color} />
              </div>
            );
          })}
        </div>
      </div>

      {/* review accordion */}
      <ReviewAccordion answers={answers} questions={questions} />

      <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
        {missed.length > 0 && (
          <Btn variant="primary" size="lg" onClick={onRestudy}>
            <Icon name="lightning" size={20}/> Study these again
          </Btn>
        )}
        <Btn variant="default" size="lg" onClick={onHome}>Back to home</Btn>
      </div>
    </div>
  );
}

// ============================================================
// REVIEW ACCORDION
// ============================================================
function ReviewAccordion({ answers, questions }) {
  const [open, setOpen] = useState(false);
  const [filter, setFilter] = useState('missed'); // 'missed' | 'all'

  const rows = useMemo(() => {
    const byId = Object.fromEntries(questions.map(q => [q.id, q]));
    return answers
      .map(a => ({ a, q: byId[a.questionId] }))
      .filter(r => !!r.q)
      .filter(r => filter === 'all' || !r.a.correct);
  }, [answers, questions, filter]);

  const noneToReview = answers.every(a => a.correct) && filter === 'missed';

  return (
    <div className="card" style={{ marginBottom: 20 }}>
      <button
        type="button"
        onClick={() => setOpen(o => !o)}
        style={{
          all: 'unset',
          cursor: 'pointer',
          width: '100%',
          display: 'flex',
          alignItems: 'center',
          gap: 12,
          fontSize: 22,
          fontFamily: 'var(--font-display)',
          fontWeight: 800,
          borderRadius: 'var(--radius)',
          outline: 'revert',
        }}
      >
        <span
          style={{
            display: 'inline-flex',
            transform: open ? 'rotate(90deg)' : 'rotate(0deg)',
            transition: 'transform 160ms var(--ease-out-soft)',
          }}
        >
          <Icon name="arrow-right" size={20} />
        </span>
        Review answers
      </button>

      {open && (
        <div style={{ marginTop: 16 }}>
          <div style={{ display: 'flex', gap: 8, marginBottom: 16 }}>
            <Btn
              size="sm"
              variant={filter === 'missed' ? 'primary' : 'default'}
              onClick={() => setFilter('missed')}
            >
              Missed only
            </Btn>
            <Btn
              size="sm"
              variant={filter === 'all' ? 'primary' : 'default'}
              onClick={() => setFilter('all')}
            >
              All
            </Btn>
          </div>

          {noneToReview && (
            <p style={{ color: 'var(--muted)', fontSize: 14, fontStyle: 'italic' }}>
              Nothing to review — perfect run!
            </p>
          )}

          <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
            {rows.map(({ a, q }) => {
              const isCorrect = a.correct;
              return (
                <div
                  key={q.id}
                  style={{
                    padding: 16,
                    background: 'var(--surface-2)',
                    borderRadius: 'var(--radius)',
                  }}
                >
                  <div className="chip" style={{ marginBottom: 8 }}>Domain {q.domain}</div>
                  <p style={{ fontSize: 15, fontWeight: 700, marginBottom: 12, lineHeight: 1.4 }}>
                    {q.question}
                  </p>

                  <div
                    style={{
                      padding: 10,
                      borderRadius: 'var(--radius)',
                      border: 'var(--outline-width) solid ' + (isCorrect ? 'var(--correct)' : 'var(--incorrect)'),
                      background: isCorrect ? 'var(--correct-bg)' : 'var(--incorrect-bg)',
                      marginBottom: 8,
                      fontSize: 14,
                      fontWeight: 700,
                    }}
                  >
                    Your answer: {a.selected.length ? a.selected.join(', ') : '(no answer)'}
                  </div>

                  <div
                    style={{
                      padding: 10,
                      borderRadius: 'var(--radius)',
                      border: 'var(--outline-width) solid var(--correct)',
                      background: 'var(--correct-bg)',
                      marginBottom: 8,
                      fontSize: 14,
                      fontWeight: 700,
                    }}
                  >
                    Correct: {q.correct.join(', ')}
                  </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>
        </div>
      )}
    </div>
  );
}

// ============================================================
// DASHBOARD
// ============================================================
function Dashboard({ course, onBack, onDrillTag, onDrillQuestion, theme }) {
  const isNarrow = useIsNarrow();
  const raw = course._raw || {};
  const progress = raw.progress || { answers: [], sessions: [] };
  const questions = raw.questions || [];

  const trend = useMemo(() => buildTrend(progress.sessions, 14), [progress.sessions]);
  const weakTopics = useMemo(() => buildWeakTopics(progress.answers, questions), [progress.answers, questions]);
  const recent = useMemo(() => buildRecentSessions(progress.sessions), [progress.sessions]);
  const mistakes = useMemo(
    () => window.MistakeAggregator.aggregateMistakes(progress.answers, questions).slice(0, 10),
    [progress.answers, questions]
  );
  const acc = course.progress.answered > 0
    ? Math.round((course.progress.correct / course.progress.answered) * 100)
    : 0;

  return (
    <div style={{ maxWidth: 1100, margin: '0 auto', padding: isNarrow ? '20px 16px 60px' : '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', flexDirection: 'column', gap: 10 }}>
        <h1 style={{ fontSize: 'clamp(34px, 4.6vw, 48px)' }}>Dashboard</h1>
        <p style={{ color: 'var(--ink-soft)', fontSize: 17 }}>{course.name} — your trend, weak spots, and queue.</p>
      </header>

      {/* stat grid */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16, marginBottom: 24 }}>
        <BigStat label="Total answered" value={course.progress.answered} bg="var(--primary)" ink="var(--primary-ink)" />
        <BigStat label="Accuracy" value={`${acc}%`} bg="var(--secondary)" ink="var(--ink)" />
        <BigStat label="Day streak" value={course.progress.streakDays} bg="var(--tertiary)" ink="var(--ink)" suffix="🔥"/>
        <BigStat label="Due now" value={course.progress.dueNow} bg="var(--surface)" ink="var(--ink)" />
      </div>

      {/* trend chart */}
      <div className="card" style={{ marginBottom: 20 }}>
        <h2 style={{ fontSize: 22, marginBottom: 16 }}>Last 14 days</h2>
        <TrendChart trend={trend} />
      </div>

      {/* weak topics */}
      <div className="card" style={{ marginBottom: 20 }}>
        <h2 style={{ fontSize: 22, marginBottom: 8 }}>Weak topics</h2>
        <p style={{ color: 'var(--muted)', fontSize: 13, marginBottom: 16 }}>Tap to drill just this tag.</p>
        {weakTopics.length === 0 && (
          <p style={{ color: 'var(--muted)', fontSize: 14 }}>Answer at least 3 tagged questions per topic to see weak spots.</p>
        )}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {weakTopics.map(t => {
            const p = Math.round((t.correct / t.seen) * 100);
            return (
              <div key={t.tag} style={{
                display: 'grid', gridTemplateColumns: '1fr 100px auto', alignItems: 'center', gap: 16,
                padding: 14,
                background: 'var(--surface-2)',
                borderRadius: 'var(--radius)',
              }}>
                <div>
                  <div style={{ fontWeight: 800, fontSize: 15 }}>{t.label}</div>
                  <div style={{ fontSize: 12, color: 'var(--muted)', fontWeight: 700, marginTop: 2 }}>{t.correct} of {t.seen} correct</div>
                </div>
                <div>
                  <ProgressBar value={t.correct} max={t.seen} height={10} color={p >= 70 ? 'var(--secondary)' : 'var(--incorrect)'} />
                </div>
                <Btn size="sm" variant="default" onClick={() => onDrillTag(t.tag)}>Drill</Btn>
              </div>
            );
          })}
        </div>
      </div>

      {/* most missed */}
      <div className="card" style={{ marginBottom: 20 }}>
        <h2 style={{ fontSize: 22, marginBottom: 8 }}>Most missed</h2>
        {mistakes.length === 0 ? (
          <p style={{ color: 'var(--muted)', fontSize: 14 }}>No mistakes yet — keep going!</p>
        ) : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {mistakes.map(m => {
              const q = questions.find(x => x.id === m.questionId);
              const truncated = m.question.length > 80
                ? m.question.slice(0, 80).trimEnd() + '…'
                : m.question;
              const hot = m.missCount >= 3;
              return (
                <div
                  key={m.questionId}
                  style={{
                    display: 'grid',
                    gridTemplateColumns: isNarrow ? '1fr' : '1fr auto auto auto',
                    alignItems: 'center',
                    gap: 12,
                    padding: 14,
                    background: 'var(--surface-2)',
                    borderRadius: 'var(--radius)',
                  }}
                >
                  <div style={{ fontSize: 14, fontWeight: 700, lineHeight: 1.4 }}>{truncated}</div>
                  <div
                    className="chip"
                    style={{
                      background: hot ? 'var(--incorrect-bg)' : 'var(--surface)',
                      color: hot ? 'var(--incorrect)' : 'var(--ink)',
                      borderColor: hot ? 'var(--incorrect)' : 'var(--line)',
                      fontWeight: 800,
                    }}
                  >
                    Missed {m.missCount}×
                  </div>
                  <div style={{ fontSize: 12, color: 'var(--muted)', fontWeight: 700 }}>
                    {m.lastMissedAt ? relativeAgo(m.lastMissedAt) : ''}
                  </div>
                  <Btn size="sm" variant="default" disabled={!q} onClick={() => q && onDrillQuestion(q)}>
                    Drill this
                  </Btn>
                </div>
              );
            })}
          </div>
        )}
      </div>

      {/* recent sessions */}
      <div className="card">
        <h2 style={{ fontSize: 22, marginBottom: 16 }}>Recent sessions</h2>
        {recent.length === 0 && (
          <p style={{ color: 'var(--muted)', fontSize: 14 }}>No sessions yet — finish a quiz to see your history here.</p>
        )}
        <div style={{ display: 'flex', flexDirection: 'column' }}>
          {recent.map((s, i) => {
            const pct = Math.round((s.correct / s.count) * 100);
            return (
              <div key={i} style={{
                display: 'flex', alignItems: 'center', gap: 16, padding: '14px 0',
                borderBottom: i < recent.length - 1 ? '1.5px solid var(--surface-2)' : 'none',
              }}>
                <div className="chip" style={{ minWidth: 80, justifyContent: 'center' }}>{capitalize(s.mode)}</div>
                <div style={{ flex: 1, fontSize: 14, fontWeight: 700, color: 'var(--ink-soft)' }}>{s.date}</div>
                <div className="font-mono" style={{ fontSize: 14, fontWeight: 700 }}>{s.correct}/{s.count}</div>
                <div className="chip" style={{
                  background: pct >= 80 ? 'var(--correct-bg)' : pct >= 60 ? 'var(--bg-tint)' : 'var(--incorrect-bg)',
                  color: pct >= 80 ? 'var(--correct)' : pct >= 60 ? 'var(--ink)' : 'var(--incorrect)',
                  borderColor: pct >= 80 ? 'var(--correct)' : pct >= 60 ? 'var(--line)' : 'var(--incorrect)',
                  minWidth: 60, justifyContent: 'center',
                }}>{pct}%</div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

function BigStat({ label, value, bg, ink, suffix }) {
  return (
    <div className="card pop-in" style={{ background: bg, color: ink, padding: 20 }}>
      <div style={{ fontSize: 12, fontWeight: 800, textTransform: 'uppercase', letterSpacing: '0.06em', opacity: 0.7, marginBottom: 8 }}>{label}</div>
      <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 48, lineHeight: 1 }}>
        {value} {suffix && <span style={{ fontSize: 28 }}>{suffix}</span>}
      </div>
    </div>
  );
}

function TrendChart({ trend }) {
  const w = 600, h = 140, pad = 20;
  const max = Math.max(1, ...trend.map(t => t.total));
  const innerW = w - pad * 2;
  const innerH = h - pad * 2;
  const step = innerW / (trend.length - 1);
  const points = trend.map((t, i) => {
    const x = pad + i * step;
    const acc = t.total ? t.correct / t.total : 0;
    const y = pad + innerH - acc * innerH;
    return { x, y, t };
  });
  const path = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ');
  return (
    <svg viewBox={`0 0 ${w} ${h}`} style={{ width: '100%', height: 160 }} preserveAspectRatio="none">
      {/* bars: total volume */}
      {trend.map((t, i) => {
        const x = pad + i * step;
        const barH = (t.total / max) * innerH;
        return <rect key={i} x={x - 8} y={pad + innerH - barH} width={16} height={barH} rx={6} fill="var(--surface-2)" />;
      })}
      {/* accuracy line */}
      <path d={path} fill="none" stroke="var(--primary)" strokeWidth={3.5} strokeLinecap="round" strokeLinejoin="round"/>
      {points.map((p, i) => (
        <circle key={i} cx={p.x} cy={p.y} r={4.5} fill="var(--primary)" stroke="var(--surface)" strokeWidth={2}/>
      ))}
    </svg>
  );
}

function buildTrend(sessions, days) {
  const buckets = new Array(days).fill(null).map(() => ({ total: 0, correct: 0 }));
  const today = new Date();
  today.setUTCHours(0, 0, 0, 0);
  for (const s of sessions || []) {
    const when = new Date(s.finishedAt || s.startedAt);
    const dayDiff = Math.floor((today.getTime() - when.getTime()) / (24 * 60 * 60 * 1000));
    const idx = days - 1 - dayDiff;
    if (idx < 0 || idx >= days) continue;
    buckets[idx].total += s.totalQuestions ?? s.answers?.length ?? 0;
    buckets[idx].correct += s.correctCount ?? (s.answers || []).filter(a => a.correct).length;
  }
  return buckets.map((b, i) => ({ day: days - 1 - i, total: b.total, correct: b.correct }));
}

function buildWeakTopics(answers, questions) {
  if (!answers?.length) return [];
  const byId = Object.fromEntries(questions.map(q => [q.id, q]));
  const tagStats = {};
  for (const a of answers) {
    const q = byId[a.questionId];
    if (!q || !q.tags?.length) continue;
    for (const tag of q.tags) {
      if (!tagStats[tag]) tagStats[tag] = { tag, label: tag, seen: 0, correct: 0 };
      tagStats[tag].seen += 1;
      if (a.correct) tagStats[tag].correct += 1;
    }
  }
  return Object.values(tagStats)
    .filter(t => t.seen >= 3)
    .sort((a, b) => (a.correct / a.seen) - (b.correct / b.seen))
    .slice(0, 5)
    .map(t => ({ ...t, label: t.tag.charAt(0).toUpperCase() + t.tag.slice(1) }));
}

function buildRecentSessions(sessions) {
  if (!sessions?.length) return [];
  const sorted = [...sessions].sort((a, b) => {
    const ta = new Date(b.finishedAt || b.startedAt).getTime();
    const tb = new Date(a.finishedAt || a.startedAt).getTime();
    return ta - tb;
  });
  return sorted.slice(0, 8).map(s => ({
    date: relativeAgo(s.finishedAt || s.startedAt),
    mode: s.mode || 'drill',
    count: s.totalQuestions ?? s.answers?.length ?? 0,
    correct: s.correctCount ?? (s.answers || []).filter(a => a.correct).length,
  }));
}

function relativeAgo(iso) {
  if (!iso) return '';
  const diffH = (Date.now() - new Date(iso).getTime()) / (60 * 60 * 1000);
  if (diffH < 1) return 'just now';
  if (diffH < 24) {
    const h = Math.round(diffH);
    return `${h} hour${h === 1 ? '' : 's'} ago`;
  }
  const d = Math.floor(diffH / 24);
  if (d === 1) return 'yesterday';
  if (d < 7) return `${d} days ago`;
  if (d < 14) return 'last week';
  return `${Math.floor(d / 7)} weeks ago`;
}

function capitalize(s) { return s[0].toUpperCase() + s.slice(1); }

Object.assign(window, { Results, Dashboard });
