// mastery-app.jsx — the REAL Syllabus Mastery Map mounted by mastery.html.
// Reads the public question catalogue (questions: subject/module/topic) and the
// signed-in user's own mastery rows (topic_mastery, RLS: own rows) and renders a
// per-module topic heat-map. No fabricated data — untouched topics show as such,
// and an empty map for a new student is the honest truth, not a mock.
//
// NOTE: this deliberately does NOT reuse ideas/idea-1-syllabus.jsx (SyllabusMap),
// which is a hardcoded design mock still used by the ideas gallery.

const MASTERY_SUBJECTS = [
  { key: 'biology',        label: 'Biology' },
  { key: 'chemistry',      label: 'Chemistry' },
  { key: 'physics',        label: 'Physics' },
  { key: 'maths-advanced', label: 'Maths Advanced' },
  { key: 'maths-standard', label: 'Maths Standard' },
  { key: 'maths-ext1',     label: 'Maths Ext 1' },
];

// topic_mastery.level is 0..3. We map (attempts, level) onto a 5-step scale so an
// attempted-but-weak topic reads differently from a never-touched one.
const MASTERY_STATE_CLS = ['untouched', 'shaky', 'learning', 'mastered', 'perfect'];
const MASTERY_STATE_LBL = ['Untouched', 'Shaky', 'Learning', 'Mastered', 'Locked-in'];

function masteryStateIdx(m) {
  if (!m || !m.attempts) return 0;          // never attempted
  return Math.min(4, (m.level || 0) + 1);   // level 0->shaky … level 3->locked-in
}

function prettyTopic(t) {
  return (t || '').replace(/-/g, ' ').replace(/\b\w/g, function (c) { return c.toUpperCase(); });
}

function masteryModuleLabel(modKey) {
  const n = (modKey || '').match(/(\d+)/);
  return n ? ('Module ' + n[1]) : (modKey || '—');
}

// The catalogue can exceed a single PostgREST page (e.g. biology ~1.7k rows), so
// page through it explicitly rather than risk a silently truncated select.
async function fetchAllQuestionTags(db, subject) {
  const PAGE = 1000;
  let from = 0;
  let all = [];
  for (;;) {
    const r = await db.from('questions').select('module,topic')
      .eq('subject', subject).not('excluded', 'is', true)
      .order('id', { ascending: true }).range(from, from + PAGE - 1);
    if (r.error) throw r.error;
    const rows = r.data || [];
    all = all.concat(rows);
    if (rows.length < PAGE) break;
    from += PAGE;
  }
  return all;
}

function MasteryMap() {
  const [subject, setSubject]   = React.useState('biology');
  const [status, setStatus]     = React.useState('loading'); // loading|ready|signedout|error
  const [modules, setModules]   = React.useState([]);
  const [totals, setTotals]     = React.useState({ mastered: 0, total: 0, attempted: 0 });
  const [selected, setSelected] = React.useState(null);      // { moduleLabel, topic, m }
  const [attempts, setAttempts] = React.useState(null);      // recent rows for selected topic

  React.useEffect(function () {
    let alive = true;
    const db   = window.HSC && window.HSC.supabase;
    const auth = window.HSC && window.HSC.auth;
    if (!db || !auth || !auth.ready) { setStatus('error'); return; }

    setStatus('loading');
    setSelected(null);
    setAttempts(null);

    auth.ready.then(async function () {
      if (!alive) return;
      const user = auth.getUser && auth.getUser();
      if (!user) { setStatus('signedout'); return; }
      try {
        const [catRows, mast] = await Promise.all([
          fetchAllQuestionTags(db, subject),
          db.from('topic_mastery').select('topic,level,attempts,correct').eq('subject', subject),
        ]);
        if (!alive) return;

        const byTopic = {};
        (mast.data || []).forEach(function (r) { byTopic[r.topic] = r; });

        const modMap = new Map();
        catRows.forEach(function (q) {
          if (!q.module || !q.topic) return;
          if (!modMap.has(q.module)) modMap.set(q.module, new Map());
          const tset = modMap.get(q.module);
          if (!tset.has(q.topic)) tset.set(q.topic, byTopic[q.topic] || null);
        });

        let mastered = 0, total = 0, attempted = 0;
        const mods = Array.from(modMap.entries())
          .sort(function (a, b) { return a[0].localeCompare(b[0], undefined, { numeric: true }); })
          .map(function (entry) {
            const topics = Array.from(entry[1].entries())
              .sort(function (a, b) { return a[0].localeCompare(b[0]); })
              .map(function (te) {
                const m = te[1];
                total++;
                if (m && m.attempts) attempted++;
                if (m && (m.level || 0) >= 2) mastered++;
                return { topic: te[0], m: m, state: masteryStateIdx(m) };
              });
            return { key: entry[0], label: masteryModuleLabel(entry[0]), topics: topics };
          });

        setModules(mods);
        setTotals({ mastered: mastered, total: total, attempted: attempted });
        setStatus('ready');
      } catch (e) {
        console.warn('[HSC] mastery load failed', e);
        if (alive) setStatus('error');
      }
    });

    return function () { alive = false; };
  }, [subject]);

  const openTopic = function (moduleLabel, topic, m) {
    setSelected({ moduleLabel: moduleLabel, topic: topic, m: m });
    setAttempts(null);
    const db = window.HSC && window.HSC.supabase;
    if (!db) return;
    db.from('question_attempts')
      .select('correct,created_at')
      .eq('subject', subject).eq('topic', topic)
      .order('created_at', { ascending: false }).limit(6)
      .then(function (r) { setAttempts(r.data || []); });
  };

  // ---- non-ready states -------------------------------------------------
  if (status === 'signedout') {
    return (
      <div className="sm-wrap">
        <div className="sm-board" style={{ textAlign: 'center', padding: '64px 24px' }}>
          <h2 style={{ marginBottom: 8 }}>Your mastery map</h2>
          <p style={{ color: 'var(--adv-muted)', maxWidth: 420, margin: '0 auto 20px' }}>
            Log in to see which syllabus topics you've mastered and where you're still shaky —
            built from your real quiz attempts.
          </p>
          <a className="sm-cta primary" href="auth/login.html" style={{ display: 'inline-flex', textDecoration: 'none' }}>
            <Icon name="play"/><div>Log in to view your map</div>
          </a>
        </div>
      </div>
    );
  }
  if (status === 'error') {
    return (
      <div className="sm-wrap">
        <div className="sm-board" style={{ textAlign: 'center', padding: '64px 24px' }}>
          <p style={{ color: 'var(--adv-muted)' }}>Couldn't load your mastery map right now. Please refresh.</p>
        </div>
      </div>
    );
  }

  const masteredPctOf = function (topics, pred) {
    if (!topics.length) return 0;
    return topics.filter(pred).length / topics.length * 100;
  };

  return (
    <div className="sm-wrap">
      {/* left nav: subjects */}
      <nav className="sm-nav">
        <div className="sm-nav-section">
          <div className="sm-nav-title">Subjects</div>
          {MASTERY_SUBJECTS.map(function (s) {
            return (
              <div key={s.key}
                className={'sm-nav-item ' + (s.key === subject ? 'active' : '')}
                onClick={function () { setSubject(s.key); }}
                style={{ cursor: 'pointer' }}>
                <span>{s.label}</span>
                {s.key === subject
                  ? <span className="sm-nav-count">{totals.mastered}/{totals.total}</span>
                  : <span className="sm-nav-count">›</span>}
              </div>
            );
          })}
        </div>
        <div className="sm-nav-section">
          <div className="sm-nav-title">How it works</div>
          <p style={{ fontSize: 12, color: 'var(--adv-muted)', lineHeight: 1.5, padding: '0 4px' }}>
            Each tile is a syllabus topic. Answer questions in quizzes and games and the tile
            warms up as your accuracy climbs. Click a tile to see your recent attempts.
          </p>
        </div>
      </nav>

      {/* main board */}
      <div className="sm-board">
        <div className="sm-board-head">
          <h2>
            <small>Mastery map · {(MASTERY_SUBJECTS.find(function (s) { return s.key === subject; }) || {}).label}</small>
            Your topic coverage
          </h2>
          <div style={{ textAlign: 'right' }}>
            <div className="sm-board-stat">{totals.mastered}<small> / {totals.total}</small></div>
            <div style={{ fontSize: 11, color: 'var(--adv-muted)', fontWeight: 700, letterSpacing: 0.4, textTransform: 'uppercase' }}>
              topics mastered
            </div>
          </div>
        </div>

        <div className="sm-legend">
          <span className="sm-legend-sw sw-untouched"><i/>Untouched</span>
          <span className="sm-legend-sw sw-shaky"><i/>Shaky</span>
          <span className="sm-legend-sw sw-learning"><i/>Learning</span>
          <span className="sm-legend-sw sw-mastered"><i/>Mastered</span>
          <span className="sm-legend-sw sw-perfect"><i/>Locked-in</span>
        </div>

        {status === 'loading' && (
          <p style={{ color: 'var(--adv-muted)', padding: '24px 4px' }}>Loading your mastery…</p>
        )}

        {status === 'ready' && totals.attempted === 0 && (
          <p style={{ color: 'var(--adv-muted)', padding: '8px 4px 20px' }}>
            Nothing tracked here yet — every tile is untouched. Answer some {(MASTERY_SUBJECTS.find(function (s) { return s.key === subject; }) || {}).label} questions
            in a quiz or game and they'll start warming up.
          </p>
        )}

        {status === 'ready' && modules.map(function (mod) {
          return (
            <div key={mod.key} className="sm-module">
              <div className="sm-module-head">
                <div className="sm-module-title">{mod.label} <em>{mod.topics.length} topics</em></div>
                <div className="sm-module-bar">
                  <i style={{ width: masteredPctOf(mod.topics, function (t) { return t.state >= 3; }) + '%', background: '#6b9b7c' }}/>
                  <i style={{ width: masteredPctOf(mod.topics, function (t) { return t.state === 2; }) + '%', background: '#d6a85f' }}/>
                  <i style={{ width: masteredPctOf(mod.topics, function (t) { return t.state === 1; }) + '%', background: '#c47b8a' }}/>
                  <i style={{ width: masteredPctOf(mod.topics, function (t) { return t.state === 0; }) + '%', background: '#e5dccb' }}/>
                </div>
              </div>
              <div className="sm-grid">
                {mod.topics.map(function (t) {
                  const isSel = selected && selected.topic === t.topic && selected.moduleLabel === mod.label;
                  return (
                    <div key={t.topic}
                      className={'sm-dot ' + MASTERY_STATE_CLS[t.state] + (isSel ? ' selected' : '')}
                      title={prettyTopic(t.topic) + ' · ' + MASTERY_STATE_LBL[t.state]}
                      onClick={function () { openTopic(mod.label, t.topic, t.m); }}
                      style={{ cursor: 'pointer' }}/>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>

      {/* detail rail */}
      <aside className="sm-detail">
        {!selected ? (
          <div style={{ color: 'var(--adv-muted)', fontSize: 13, lineHeight: 1.6 }}>
            <div className="sm-detail-eye">SELECTED TOPIC</div>
            <p>Click any tile to see your mastery level and recent attempts for that topic.</p>
          </div>
        ) : (
          <React.Fragment>
            <div className="sm-detail-eye">SELECTED TOPIC</div>
            <div className="sm-detail-id">{selected.moduleLabel}</div>
            <div className="sm-detail-quote">{prettyTopic(selected.topic)}</div>

            <div className="sm-detail-mastery">
              <div className="sm-detail-mast-row">
                <span>Your mastery</span>
                <strong style={{ color: 'var(--adv-rose-deep)', fontFamily: 'Outfit', fontWeight: 800 }}>
                  {MASTERY_STATE_LBL[masteryStateIdx(selected.m)]}
                  {selected.m && selected.m.attempts
                    ? ' · ' + selected.m.correct + '/' + selected.m.attempts + ' correct'
                    : ' · no attempts yet'}
                </strong>
              </div>
              <div className="sm-detail-mast-bar">
                <i style={{ width: (selected.m ? Math.round((selected.m.level || 0) / 3 * 100) : 0) + '%' }}/>
              </div>
            </div>

            <div className="sm-attempts">
              <h5>Your last attempts</h5>
              {attempts === null && <p style={{ fontSize: 12, color: 'var(--adv-muted)' }}>Loading…</p>}
              {attempts !== null && attempts.length === 0 &&
                <p style={{ fontSize: 12, color: 'var(--adv-muted)' }}>No attempts recorded for this topic yet.</p>}
              {(attempts || []).map(function (a, i) {
                return (
                  <div key={i} className="sm-attempt">
                    <div className={'sm-attempt-mark ' + (a.correct ? 'ok' : 'no')}>
                      <Icon name={a.correct ? 'check' : 'x'}/>
                    </div>
                    <div className="sm-attempt-q">{a.correct ? 'Correct' : 'Incorrect'}</div>
                    <div className="sm-attempt-date">
                      {a.created_at ? new Date(a.created_at).toLocaleDateString('en-AU', { day: 'numeric', month: 'short' }) : ''}
                    </div>
                  </div>
                );
              })}
            </div>

            <div className="sm-detail-ctas">
              <a className="sm-cta primary" href={'/subjects/' + subject + '/index.html'} style={{ textDecoration: 'none' }}>
                <Icon name="play"/>
                <div>Go to {(MASTERY_SUBJECTS.find(function (s) { return s.key === subject; }) || {}).label} lessons</div>
              </a>
            </div>
          </React.Fragment>
        )}
      </aside>
    </div>
  );
}

window.MasteryMap = MasteryMap;
