// app-shell.jsx - main app: navigation, homepage, week pages, search, dark mode

const { useState, useEffect, useMemo, useCallback, useRef } = React;

const WEEK_NUMBERS = [1, 2, 4, 5, 6, 7, 8, 9, 11, 12];

const WEEK_META = {
  1:  { title: 'Course Introduction',              layer: 'Frame',          color: 'bg-violet-500' },
  2:  { title: 'Data Foundations & Metadata',       layer: 'L1 Operations',  color: 'bg-sky-500' },
  4:  { title: 'SQL & Data Profiling',              layer: 'L1 Operations',  color: 'bg-sky-500' },
  5:  { title: 'GenAI for Data Cleaning',           layer: 'L1 Operations',  color: 'bg-sky-500' },
  6:  { title: 'Data Architecture & Modelling',     layer: 'L1 Operations',  color: 'bg-sky-500' },
  7:  { title: 'Technical to Managerial Bridge',    layer: 'L1/L2 Bridge',   color: 'bg-teal-500' },
  8:  { title: 'Data Governance',                   layer: 'L2 Governance',  color: 'bg-amber-500' },
  9:  { title: 'Data Strategy',                     layer: 'L3 Strategy',    color: 'bg-rose-500' },
  11: { title: 'Managing an AI Project',            layer: 'L3 Strategy',    color: 'bg-rose-500' },
  12: { title: 'Responsible AI & Future',           layer: 'L3 Strategy',    color: 'bg-rose-500' },
};

// ── Search engine ──────────────────────────────────────────────
function buildSearchIndex(data) {
  const index = [];
  if (!data) return index;

  // Mastery sheets
  WEEK_NUMBERS.forEach(n => {
    const content = data.weeks[n]?.mastery || '';
    const lines = content.split('\n');
    let currentHeading = '';
    lines.forEach((line, li) => {
      const hMatch = line.match(/^(#{1,3})\s+(.*)/);
      if (hMatch) {
        currentHeading = hMatch[2];
        index.push({
          type: 'mastery-heading',
          week: n,
          heading: hMatch[2],
          level: hMatch[1].length,
          lineIdx: li,
          snippet: hMatch[2],
          route: { page: 'week', week: n, tab: 'mastery' },
        });
      } else if (line.trim() && currentHeading) {
        index.push({
          type: 'mastery-content',
          week: n,
          heading: currentHeading,
          lineIdx: li,
          snippet: line.trim().slice(0, 120),
          route: { page: 'week', week: n, tab: 'mastery' },
        });
      }
    });
  });

  // Exam-ready review
  const elines = (data.examReadyReview || '').split('\n');
  let eHeading = '';
  elines.forEach((line, li) => {
    const hMatch = line.match(/^(#{1,3})\s+(.*)/);
    if (hMatch) {
      eHeading = hMatch[2];
      index.push({ type: 'review-heading', heading: hMatch[2], lineIdx: li, snippet: hMatch[2], route: { page: 'review' } });
    }
  });

  return index;
}

function searchIndex(index, query) {
  if (!query || query.length < 2) return [];
  const q = query.toLowerCase();
  const results = [];
  const seen = new Set();
  for (const entry of index) {
    if (entry.snippet.toLowerCase().includes(q) || entry.heading.toLowerCase().includes(q)) {
      const key = `${entry.route.page}-${entry.route.week || ''}-${entry.heading}`;
      if (!seen.has(key)) {
        seen.add(key);
        results.push(entry);
      }
      if (results.length >= 20) break;
    }
  }
  return results;
}

// ── Sidebar nav ────────────────────────────────────────────────
function Sidebar({ route, navigate, darkMode, onToggleDark, data, collapsed, onToggleCollapse }) {
  const { state } = useApp();
  const dm = darkMode;

  const navItem = (label, r, icon, badge) => {
    const active = route.page === r.page && (r.page !== 'week' || route.week === r.week);
    return (
      <button
        key={label}
        onClick={() => navigate(r)}
        className={`w-full flex items-center gap-2.5 px-3 py-2 rounded-xl text-sm font-medium transition-all duration-100 group
          ${active
            ? (dm ? 'bg-amber-500/20 text-amber-400' : 'bg-amber-50 text-amber-700')
            : (dm ? 'text-stone-400 hover:text-stone-200 hover:bg-stone-800' : 'text-stone-600 hover:text-stone-900 hover:bg-stone-100')}`}
      >
        <span className="shrink-0">{icon}</span>
        {!collapsed && <span className="flex-1 text-left truncate">{label}</span>}
        {!collapsed && badge && <span className={`text-xs px-1.5 py-0.5 rounded font-mono ${dm ? 'bg-rose-500/20 text-rose-400' : 'bg-rose-100 text-rose-600'}`}>{badge}</span>}
      </button>
    );
  };

  const mockBadge = state.mockExam.started && !state.mockExam.finished ? 'live' : null;

  return (
    <div className={`flex flex-col h-full ${collapsed ? 'w-14' : 'w-56'} transition-all duration-200 shrink-0
      ${dm ? 'bg-stone-900 border-stone-800' : 'bg-white border-stone-200'} border-r`}>
      {/* Logo */}
      <div className={`flex items-center gap-2 px-3 py-4 border-b ${dm ? 'border-stone-800' : 'border-stone-100'}`}>
        {!collapsed && (
          <div className="flex-1 min-w-0">
            <div className={`text-xs font-bold uppercase tracking-widest ${dm ? 'text-amber-400' : 'text-amber-600'}`}>MIS41500</div>
            <div className={`text-xs truncate ${dm ? 'text-stone-500' : 'text-stone-400'}`}>Study Platform</div>
          </div>
        )}
        <button onClick={onToggleCollapse} className={`p-1.5 rounded-lg shrink-0 ${dm ? 'text-stone-500 hover:text-stone-300 hover:bg-stone-800' : 'text-stone-400 hover:text-stone-600 hover:bg-stone-100'}`}>
          {collapsed
            ? <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><polyline points="9 18 15 12 9 6"/></svg>
            : <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><polyline points="15 18 9 12 15 6"/></svg>}
        </button>
      </div>

      {/* Nav */}
      <div className="flex-1 overflow-y-auto py-3 px-2 space-y-0.5">
        {navItem('Home', { page: 'home' },
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
        )}
        {navItem('Mock Exam', { page: 'mock' },
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>,
          mockBadge
        )}

        {!collapsed && (
          <div className={`text-xs font-semibold uppercase tracking-widest px-3 pt-3 pb-1 ${dm ? 'text-stone-600' : 'text-stone-400'}`}>
            Content
          </div>
        )}
        {WEEK_NUMBERS.map(n => {
          const meta = WEEK_META[n];
          const wq = state.weekQuiz[n];
          const progress = wq ? `${Object.keys(wq.answers).length}/${wq.questions.length}` : null;
          return navItem(
            collapsed ? `W${n}` : `W${n} · ${meta.title}`,
            { page: 'week', week: n, tab: 'mastery' },
            <span className={`text-xs font-bold w-5 h-5 rounded flex items-center justify-center ${meta.color} text-white shrink-0`}>{n}</span>,
            (!collapsed && progress && wq.answers && Object.keys(wq.answers).length > 0) ? progress : null
          );
        })}

        {!collapsed && (
          <div className={`text-xs font-semibold uppercase tracking-widest px-3 pt-3 pb-1 ${dm ? 'text-stone-600' : 'text-stone-400'}`}>
            Reference
          </div>
        )}
        {navItem(collapsed ? '★' : 'Exam-Ready Review', { page: 'review' },
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
        )}
        {navItem(collapsed ? 'M' : 'Master Index', { page: 'index' },
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
        )}
        {navItem(collapsed ? '⊞' : 'Integration Matrix', { page: 'matrix' },
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/></svg>
        )}
      </div>

      {/* Bottom controls */}
      <div className={`p-2 border-t ${dm ? 'border-stone-800' : 'border-stone-100'}`}>
        <button onClick={onToggleDark}
          className={`w-full flex items-center gap-2 px-3 py-2 rounded-xl text-sm transition-colors ${dm ? 'text-stone-400 hover:text-stone-200 hover:bg-stone-800' : 'text-stone-500 hover:text-stone-700 hover:bg-stone-100'}`}>
          {dm
            ? <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
            : <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>}
          {!collapsed && <span>{dm ? 'Light Mode' : 'Dark Mode'}</span>}
        </button>
      </div>
    </div>
  );
}

// ── Session card ───────────────────────────────────────────────
function SessionCard({ navigate, darkMode }) {
  const { state } = useApp();
  const dm = darkMode;

  const activeSessions = [];

  // Mock exam
  if (state.mockExam.started && !state.mockExam.finished) {
    const answered = Object.keys(state.mockExam.answers).length;
    const total = state.mockExam.questions.length;
    const timeLeft = state.mockExam.timeLeft;
    const h = Math.floor(timeLeft / 3600);
    const m = Math.floor((timeLeft % 3600) / 60);
    activeSessions.push({
      label: 'Mock Exam in progress',
      detail: `${answered}/${total} answered · ${h}:${String(m).padStart(2,'0')} remaining`,
      route: { page: 'mock' },
      color: 'amber',
    });
  }

  // Weekly quizzes
  WEEK_NUMBERS.forEach(n => {
    const wq = state.weekQuiz[n];
    if (wq && Object.keys(wq.answers).length > 0 && !wq.finished) {
      const answered = Object.keys(wq.answers).length;
      const total = wq.questions.length;
      activeSessions.push({
        label: `Week ${n} Quiz`,
        detail: `${answered}/${total} completed`,
        route: { page: 'week', week: n, tab: 'quiz' },
        color: 'sky',
      });
    }
  });

  if (activeSessions.length === 0) return null;

  return (
    <div className={`rounded-2xl p-4 border-2 ${dm ? 'bg-stone-800 border-amber-500/30' : 'bg-amber-50 border-amber-200'} mb-6`}>
      <div className={`text-xs font-semibold uppercase tracking-widest mb-3 ${dm ? 'text-amber-400' : 'text-amber-700'}`}>Active Session</div>
      <div className="space-y-2">
        {activeSessions.map((s, i) => (
          <button key={i} onClick={() => navigate(s.route)}
            className={`w-full flex items-center justify-between p-3 rounded-xl transition-colors text-left ${dm ? 'bg-stone-700 hover:bg-stone-600' : 'bg-white hover:bg-amber-50 border border-amber-100'}`}>
            <div>
              <div className={`text-sm font-semibold ${dm ? 'text-stone-200' : 'text-stone-800'}`}>{s.label}</div>
              <div className={`text-xs ${dm ? 'text-stone-400' : 'text-stone-500'}`}>{s.detail}</div>
            </div>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className={dm ? 'text-stone-400' : 'text-stone-400'}><polyline points="9 18 15 12 9 6"/></svg>
          </button>
        ))}
      </div>
    </div>
  );
}

// ── Weakest LOs card ───────────────────────────────────────────
function WeakestLOs({ navigate, darkMode }) {
  const { state } = useApp();
  const dm = darkMode;

  const loStats = {};
  WEEK_NUMBERS.forEach(n => {
    const wq = state.weekQuiz[n];
    if (!wq) return;
    wq.questions.forEach(q => {
      if (!wq.answers[q.id]) return;
      q.los.forEach(lo => {
        if (!loStats[lo]) loStats[lo] = { correct: 0, total: 0 };
        loStats[lo].total++;
        if (wq.answers[q.id] === q.correct) loStats[lo].correct++;
      });
    });
  });

  const sorted = Object.entries(loStats)
    .filter(([, s]) => s.total >= 2)
    .map(([lo, s]) => ({ lo, pct: Math.round(s.correct / s.total * 100), ...s }))
    .sort((a, b) => a.pct - b.pct)
    .slice(0, 4);

  if (sorted.length === 0) return null;

  const loToWeeks = {};
  WEEK_NUMBERS.forEach(n => {
    const wq = state.weekQuiz[n];
    if (!wq) return;
    wq.questions.forEach(q => q.los.forEach(lo => {
      if (!loToWeeks[lo]) loToWeeks[lo] = new Set();
      loToWeeks[lo].add(n);
    }));
  });

  return (
    <div className={`rounded-2xl p-4 ${dm ? 'bg-stone-800' : 'bg-white'} shadow-sm mb-6`}>
      <div className={`text-xs font-semibold uppercase tracking-widest mb-3 ${dm ? 'text-stone-400' : 'text-stone-500'}`}>Weakest Learning Outcomes</div>
      <div className="space-y-3">
        {sorted.map(({ lo, pct, correct, total }) => (
          <div key={lo}>
            <div className="flex items-center justify-between mb-1">
              <span className={`text-xs font-mono font-bold ${dm ? 'text-sky-400' : 'text-sky-600'}`}>{lo}</span>
              <span className={`text-xs ${pct < 50 ? 'text-rose-500' : (dm ? 'text-stone-400' : 'text-stone-500')}`}>{correct}/{total} ({pct}%)</span>
            </div>
            <div className={`h-1.5 rounded-full ${dm ? 'bg-stone-700' : 'bg-stone-200'}`}>
              <div className={`h-1.5 rounded-full ${pct < 50 ? 'bg-rose-500' : 'bg-amber-400'}`} style={{ width: `${pct}%` }}></div>
            </div>
            {loToWeeks[lo] && (
              <div className="flex gap-1 mt-1 flex-wrap">
                {[...loToWeeks[lo]].map(wk => (
                  <button key={wk} onClick={() => navigate({ page: 'week', week: wk, tab: 'quiz' })}
                    className={`text-xs px-2 py-0.5 rounded font-medium transition-colors ${dm ? 'bg-stone-700 hover:bg-stone-600 text-stone-400' : 'bg-stone-100 hover:bg-stone-200 text-stone-500'}`}>
                    W{wk}
                  </button>
                ))}
              </div>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

// ── Bookmarks card ─────────────────────────────────────────────
function BookmarksCard({ navigate, darkMode, data }) {
  const { state } = useApp();
  const dm = darkMode;
  if (state.bookmarks.size === 0) return null;

  // Find bookmarked questions
  const bookmarkedQs = [];
  WEEK_NUMBERS.forEach(n => {
    const qs = data?.weeks[n]?.mcqsJson?.questions || [];
    qs.forEach(q => {
      if (state.bookmarks.has(q.id)) bookmarkedQs.push({ ...q, week: n });
    });
  });

  return (
    <div className={`rounded-2xl p-4 ${dm ? 'bg-stone-800' : 'bg-white'} shadow-sm mb-6`}>
      <div className={`text-xs font-semibold uppercase tracking-widest mb-3 ${dm ? 'text-stone-400' : 'text-stone-500'}`}>
        Bookmarked ({state.bookmarks.size})
      </div>
      <div className="space-y-2">
        {bookmarkedQs.slice(0, 5).map(q => (
          <button key={q.id} onClick={() => navigate({ page: 'week', week: q.week, tab: 'quiz' })}
            className={`w-full text-left p-3 rounded-xl text-xs transition-colors ${dm ? 'bg-stone-700 hover:bg-stone-600' : 'bg-stone-50 hover:bg-stone-100'}`}>
            <div className={`font-medium line-clamp-2 ${dm ? 'text-stone-200' : 'text-stone-700'}`}>{q.stem}</div>
            <div className={`mt-1 ${dm ? 'text-stone-500' : 'text-stone-400'}`}>Week {q.week}</div>
          </button>
        ))}
        {bookmarkedQs.length > 5 && (
          <div className={`text-xs text-center ${dm ? 'text-stone-500' : 'text-stone-400'}`}>+{bookmarkedQs.length - 5} more</div>
        )}
      </div>
    </div>
  );
}

// ── Homepage ───────────────────────────────────────────────────
function HomePage({ navigate, darkMode, data }) {
  const dm = darkMode;

  const layerGroups = [
    { label: 'Frame', weeks: [1], desc: 'Course introduction, 3-level model, 8 LOs' },
    { label: 'L1 Operations', weeks: [2, 4, 5, 6], desc: 'Data foundations, SQL, GenAI cleaning, architecture' },
    { label: 'L1 to L2 Bridge', weeks: [7], desc: 'Technical to managerial transition' },
    { label: 'L2 Governance', weeks: [8], desc: 'Roles, policies, controls, accountability' },
    { label: 'L3 Strategy', weeks: [9, 11, 12], desc: 'Data strategy, AI projects, responsible AI' },
  ];

  return (
    <div className="max-w-3xl mx-auto pb-12">
      {/* Hero */}
      <div className="mb-8">
        <div className={`text-xs font-semibold uppercase tracking-widest mb-2 ${dm ? 'text-stone-500' : 'text-stone-400'}`}>MIS41500 &nbsp;/&nbsp; UCD Business &nbsp;/&nbsp; Spring 2026</div>
        <h1 className={`text-3xl font-bold mb-2 ${dm ? 'text-white' : 'text-stone-900'}`}>Managing Data and AI</h1>
        <p className={`text-sm ${dm ? 'text-stone-400' : 'text-stone-500'}`}>50 questions, 5 options, closed book. Scoring: +2 correct, −1 wrong, 0 skipped.</p>
      </div>

      {/* Session resume */}
      <SessionCard navigate={navigate} darkMode={dm} />

      {/* Weakest LOs */}
      <WeakestLOs navigate={navigate} darkMode={dm} />



      {/* Quick links */}
      <div className="grid grid-cols-2 gap-3 mb-8">
        <button onClick={() => navigate({ page: 'mock' })}
          className={`p-4 rounded-xl text-left transition-all group ${dm ? 'bg-stone-800 hover:bg-stone-700 border border-stone-700' : 'bg-white hover:bg-stone-50 border border-stone-200'} shadow-sm`}>
          <div className="flex items-center gap-2 mb-2">
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" className={dm ? 'text-amber-400' : 'text-amber-500'}><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
            <span className={`text-xs font-semibold uppercase tracking-wide whitespace-nowrap ${dm ? 'text-amber-400' : 'text-amber-600'}`}>Mock Exam</span>
          </div>
          <div className={`text-sm font-medium ${dm ? 'text-stone-200' : 'text-stone-800'}`}>Full 50-question paper</div>
          <div className={`text-xs mt-0.5 ${dm ? 'text-stone-500' : 'text-stone-400'}`}>2 hours, exam conditions</div>
        </button>
        <button onClick={() => navigate({ page: 'review' })}
          className={`p-4 rounded-xl text-left transition-all group ${dm ? 'bg-stone-800 hover:bg-stone-700 border border-stone-700' : 'bg-white hover:bg-stone-50 border border-stone-200'} shadow-sm`}>
          <div className="flex items-center gap-2 mb-2">
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" className={dm ? 'text-rose-400' : 'text-rose-500'}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
            <span className={`text-xs font-semibold uppercase tracking-wide whitespace-nowrap ${dm ? 'text-rose-400' : 'text-rose-600'}`}>Exam-Ready Review</span>
          </div>
          <div className={`text-sm font-medium ${dm ? 'text-stone-200' : 'text-stone-800'}`}>Key concepts and traps</div>
          <div className={`text-xs mt-0.5 ${dm ? 'text-stone-500' : 'text-stone-400'}`}>Read the night before</div>
        </button>
      </div>

      {/* Week cards grouped by layer */}
      <div className="space-y-5 mb-8">
        {layerGroups.map(group => (
          <div key={group.label}>
            <div className="flex items-center gap-2 mb-2 overflow-hidden">
              <span className={`text-xs font-semibold uppercase tracking-widest whitespace-nowrap ${dm ? 'text-stone-500' : 'text-stone-400'}`}>{group.label}</span>
              <div className={`flex-1 h-px min-w-4 ${dm ? 'bg-stone-800' : 'bg-stone-100'}`}></div>
              <span className={`text-xs whitespace-nowrap hidden sm:block ${dm ? 'text-stone-600' : 'text-stone-400'}`}>{group.desc}</span>
            </div>
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
              {group.weeks.map(n => {
                const meta = WEEK_META[n];
                const qData = data?.weeks[n]?.mcqsJson;
                const qCount = qData?.questions?.length || 0;
                return (
                  <button key={n} onClick={() => navigate({ page: 'week', week: n, tab: 'quiz' })}
                    className={`p-3.5 rounded-xl text-left transition-all group ${dm ? 'bg-stone-800 hover:bg-stone-750 border border-stone-700/60' : 'bg-white hover:bg-stone-50 border border-stone-100'} shadow-sm`}>
                    <div className="flex items-center gap-3">
                      <span className={`text-xs font-bold w-7 h-7 rounded-lg flex items-center justify-center shrink-0 ${meta.color} text-white`}>{n}</span>
                      <div className="flex-1 min-w-0">
                        <div className={`font-medium text-sm ${dm ? 'text-stone-100' : 'text-stone-800'}`}>{meta.title}</div>
                        <div className={`text-xs mt-0.5 ${dm ? 'text-stone-500' : 'text-stone-400'}`}>{qCount} questions</div>
                      </div>
                      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className={`shrink-0 transition-transform group-hover:translate-x-0.5 ${dm ? 'text-stone-600' : 'text-stone-300'}`}><polyline points="9 18 15 12 9 6"/></svg>
                    </div>
                  </button>
                );
              })}
            </div>
          </div>
        ))}
      </div>

      {/* Band reference strip */}
      <div className={`rounded-xl p-4 ${dm ? 'bg-stone-800/60 border border-stone-700/40' : 'bg-stone-50 border border-stone-100'}`}>
        <div className={`text-xs font-semibold uppercase tracking-widest mb-3 ${dm ? 'text-stone-500' : 'text-stone-400'}`}>Question bands</div>
        <div className="space-y-2">
          {[
            { band: 'A', label: 'Foundational', pct: '20%', desc: 'Direct recall of definitions and model names.', col: dm ? 'text-emerald-400' : 'text-emerald-600' },
            { band: 'B', label: 'Applied', pct: '50%', desc: 'Scenario-based: pick the right concept for a given situation.', col: dm ? 'text-amber-400' : 'text-amber-600' },
            { band: 'C', label: 'Trap-zone', pct: '30%', desc: 'Subtle distractors, reversed relationships, right-area-wrong-question.', col: dm ? 'text-rose-400' : 'text-rose-600' },
          ].map(({ band, label, pct, desc, col }) => (
            <div key={band} className="flex items-baseline gap-3">
              <span className={`text-xs font-bold w-4 shrink-0 ${col}`}>{band}</span>
              <span className={`text-xs font-medium w-20 shrink-0 ${dm ? 'text-stone-300' : 'text-stone-700'}`}>{label}</span>
              <span className={`text-xs ${dm ? 'text-stone-500' : 'text-stone-400'}`}>{desc}</span>
              <span className={`text-xs font-mono ml-auto shrink-0 ${dm ? 'text-stone-600' : 'text-stone-400'}`}>{pct}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ── Week page ──────────────────────────────────────────────────
function WeekPage({ weekNum, initialTab, darkMode, data }) {
  const [tab, setTab] = useState(initialTab || 'mastery');
  const dm = darkMode;
  const meta = WEEK_META[weekNum];
  const weekData = data?.weeks[weekNum];

  useEffect(() => { setTab(initialTab || 'mastery'); }, [weekNum, initialTab]);

  const tabs = [
    { id: 'mastery', label: 'Mastery Sheet' },
    { id: 'quiz', label: 'Quiz' },
    { id: 'reading', label: 'MCQ Reading' },
  ];

  return (
    <div className="max-w-3xl mx-auto pb-12">
      {/* Header */}
      <div className="mb-6">
        <div className={`flex items-center gap-2 mb-2`}>
          <span className={`text-sm font-bold w-8 h-8 rounded-xl flex items-center justify-center ${meta.color} text-white`}>{weekNum}</span>
          <span className={`text-xs font-medium px-2 py-0.5 rounded-lg ${dm ? 'bg-stone-800 text-stone-400' : 'bg-stone-100 text-stone-500'}`}>{meta.layer}</span>
        </div>
        <h2 className={`text-2xl font-bold ${dm ? 'text-white' : 'text-stone-900'}`}>{meta.title}</h2>
      </div>

      {/* Tabs */}
      <div className={`flex gap-1 p-1 rounded-xl mb-6 ${dm ? 'bg-stone-800' : 'bg-stone-100'}`}>
        {tabs.map(t => (
          <button key={t.id} onClick={() => setTab(t.id)}
            className={`flex-1 py-2 px-3 rounded-lg text-sm font-medium transition-all ${tab === t.id
              ? (dm ? 'bg-stone-700 text-white shadow' : 'bg-white text-stone-900 shadow-sm')
              : (dm ? 'text-stone-400 hover:text-stone-200' : 'text-stone-500 hover:text-stone-700')}`}>
            {t.label}
          </button>
        ))}
      </div>

      {/* Content */}
      {tab === 'mastery' && weekData?.mastery && (
        <div className={`rounded-2xl p-8 ${dm ? 'bg-stone-900/60' : 'bg-white'} shadow-sm border ${dm ? 'border-stone-800' : 'border-stone-100'}`}>
          <MarkdownRenderer content={weekData.mastery} darkMode={dm} />
        </div>
      )}
      {tab === 'reading' && weekData?.mcqsMd && (
        <div className={`rounded-2xl p-8 ${dm ? 'bg-stone-900/60' : 'bg-white'} shadow-sm border ${dm ? 'border-stone-800' : 'border-stone-100'}`}>
          <MarkdownRenderer content={weekData.mcqsMd} darkMode={dm} />
        </div>
      )}
      {tab === 'quiz' && weekData?.mcqsJson && (
        <WeeklyQuiz weekNum={weekNum} quizData={weekData.mcqsJson} darkMode={dm} />
      )}
      {!weekData && (
        <div className={`text-center py-12 ${dm ? 'text-stone-500' : 'text-stone-400'}`}>Loading content…</div>
      )}
    </div>
  );
}

// ── Search bar ─────────────────────────────────────────────────
function SearchBar({ darkMode, navigate, data }) {
  const { state, dispatch } = useApp();
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');
  const ref = useRef(null);
  const dm = darkMode;

  const searchIndex = useMemo(() => buildSearchIndex(data), [data]);

  const results = useMemo(() => {
    if (!query || query.length < 2) return [];
    const q = query.toLowerCase();
    const out = [];
    const seen = new Set();
    for (const entry of searchIndex) {
      if (entry.snippet.toLowerCase().includes(q) || entry.heading.toLowerCase().includes(q)) {
        const key = `${entry.route.page}-${entry.route.week || ''}-${entry.heading}-${entry.lineIdx}`;
        if (!seen.has(key)) {
          seen.add(key);
          out.push(entry);
        }
        if (out.length >= 15) break;
      }
    }
    return out;
  }, [query, searchIndex]);

  useEffect(() => {
    const handler = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); setOpen(true); }
      if (e.key === 'Escape') setOpen(false);
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, []);

  if (!open) return (
    <button onClick={() => setOpen(true)}
      className={`flex items-center gap-2 px-3 py-1.5 rounded-xl text-sm transition-colors ${dm ? 'bg-stone-800 text-stone-400 hover:bg-stone-700' : 'bg-stone-100 text-stone-500 hover:bg-stone-200'}`}>
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
      <span>Search</span>
      <span className={`text-xs px-1.5 py-0.5 rounded font-mono ${dm ? 'bg-stone-700 text-stone-500' : 'bg-white text-stone-400 border border-stone-200'}`}>⌘K</span>
    </button>
  );

  return (
    <div className="fixed inset-0 z-50 flex items-start justify-center pt-24 px-4" style={{ background: 'rgba(0,0,0,0.5)' }}
      onClick={(e) => { if (e.target === e.currentTarget) setOpen(false); }}>
      <div className={`w-full max-w-lg rounded-2xl shadow-2xl overflow-hidden ${dm ? 'bg-stone-800' : 'bg-white'}`} ref={ref}>
        <div className={`flex items-center gap-3 px-4 py-3 border-b ${dm ? 'border-stone-700' : 'border-stone-200'}`}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className={dm ? 'text-stone-400' : 'text-stone-400'}><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
          <input
            autoFocus
            type="text"
            value={query}
            onChange={e => setQuery(e.target.value)}
            placeholder="Search mastery sheets, review…"
            className={`flex-1 bg-transparent text-sm outline-none ${dm ? 'text-stone-100 placeholder-stone-500' : 'text-stone-900 placeholder-stone-400'}`}
          />
          <button onClick={() => setOpen(false)} className={`text-xs px-2 py-1 rounded ${dm ? 'text-stone-500' : 'text-stone-400'}`}>Esc</button>
        </div>
        {results.length > 0 && (
          <div className="max-h-80 overflow-y-auto">
            {results.map((r, i) => (
              <button key={i} onClick={() => { navigate(r.route); setOpen(false); setQuery(''); }}
                className={`w-full text-left px-4 py-3 transition-colors border-b last:border-0 ${dm ? 'border-stone-700 hover:bg-stone-700' : 'border-stone-100 hover:bg-stone-50'}`}>
                <div className="flex items-start gap-2">
                  <span className={`text-xs px-1.5 py-0.5 rounded shrink-0 mt-0.5 ${dm ? 'bg-stone-700 text-stone-400' : 'bg-stone-100 text-stone-500'}`}>
                    {r.type === 'review-heading' ? 'Review' : `W${r.week}`}
                  </span>
                  <div>
                    <div className={`text-sm font-medium ${dm ? 'text-stone-200' : 'text-stone-800'}`}>{r.heading}</div>
                    {r.type === 'mastery-content' && r.snippet !== r.heading && (
                      <div className={`text-xs mt-0.5 line-clamp-1 ${dm ? 'text-stone-500' : 'text-stone-400'}`}>{r.snippet}</div>
                    )}
                  </div>
                </div>
              </button>
            ))}
          </div>
        )}
        {query.length >= 2 && results.length === 0 && (
          <div className={`px-4 py-6 text-center text-sm ${dm ? 'text-stone-500' : 'text-stone-400'}`}>No results found</div>
        )}
        {query.length < 2 && (
          <div className={`px-4 py-4 text-sm ${dm ? 'text-stone-500' : 'text-stone-400'}`}>Type at least 2 characters…</div>
        )}
      </div>
    </div>
  );
}

// ── Main app ───────────────────────────────────────────────────
function App({ data }) {
  const { state, dispatch, navigate } = useApp();
  const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
  const dm = state.darkMode;
  const route = state.route;

  const renderMain = () => {
    switch (route.page) {
      case 'home':
        return <HomePage navigate={navigate} darkMode={dm} data={data} />;
      case 'week':
        return <WeekPage weekNum={route.week} initialTab={route.tab} darkMode={dm} data={data} />;
      case 'mock':
        return <MockExam mockExamData={data?.mockExamJson} darkMode={dm} />;
      case 'review':
        return (
          <div className="max-w-3xl mx-auto pb-12">
            <h2 className={`text-2xl font-bold mb-6 ${dm ? 'text-white' : 'text-stone-900'}`}>Exam-Ready Review</h2>
            <div className={`rounded-2xl p-8 ${dm ? 'bg-stone-900/60 border border-stone-800' : 'bg-white border border-stone-100'} shadow-sm`}>
              <MarkdownRenderer content={data?.examReadyReview || ''} darkMode={dm} />
            </div>
          </div>
        );
      case 'index':
        return (
          <div className="max-w-3xl mx-auto pb-12">
            <h2 className={`text-2xl font-bold mb-6 ${dm ? 'text-white' : 'text-stone-900'}`}>Master Index</h2>
            <div className={`rounded-2xl p-8 ${dm ? 'bg-stone-900/60 border border-stone-800' : 'bg-white border border-stone-100'} shadow-sm`}>
              <MarkdownRenderer content={data?.masterIndex || ''} darkMode={dm} />
            </div>
          </div>
        );
      case 'matrix':
        return (
          <div className="max-w-3xl mx-auto pb-12">
            <h2 className={`text-2xl font-bold mb-6 ${dm ? 'text-white' : 'text-stone-900'}`}>Integration Matrix</h2>
            <div className={`rounded-2xl p-8 ${dm ? 'bg-stone-900/60 border border-stone-800' : 'bg-white border border-stone-100'} shadow-sm`}>
              <MarkdownRenderer content={data?.integrationMatrix || ''} darkMode={dm} />
            </div>
          </div>
        );
      default:
        return <HomePage navigate={navigate} darkMode={dm} data={data} />;
    }
  };

  return (
    <div className={`flex h-screen overflow-hidden ${dm ? 'bg-stone-950' : 'bg-stone-50'}`}>
      {/* Sidebar */}
      <Sidebar
        route={route}
        navigate={navigate}
        darkMode={dm}
        onToggleDark={() => dispatch({ type: 'TOGGLE_DARK' })}
        data={data}
        collapsed={sidebarCollapsed}
        onToggleCollapse={() => setSidebarCollapsed(c => !c)}
      />

      {/* Main */}
      <div className="flex-1 flex flex-col min-w-0 overflow-hidden">
        {/* Topbar */}
        <div className={`flex items-center justify-between px-6 py-3 border-b shrink-0 ${dm ? 'bg-stone-900 border-stone-800' : 'bg-white border-stone-200'}`}>
          <div className={`text-sm font-medium truncate ${dm ? 'text-stone-300' : 'text-stone-700'}`}>
            {route.page === 'home' && 'Dashboard'}
            {route.page === 'week' && `Week ${route.week}: ${WEEK_META[route.week]?.title}`}
            {route.page === 'mock' && 'Mock Exam'}
            {route.page === 'review' && 'Exam-Ready Review'}
            {route.page === 'index' && 'Master Index'}
            {route.page === 'matrix' && 'Integration Matrix'}
          </div>
          <SearchBar darkMode={dm} navigate={navigate} data={data} />
        </div>

        {/* Scrollable content */}
        <div className="flex-1 overflow-y-auto px-6 py-6">
          {renderMain()}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { App });
