/* global React, window */
// Piano Lab — top-level container.
//
// Two modes:
//   - Lessons:   instructional pages with audible demos and labelled
//                keyboards. Pick a lesson from the sidebar.
//   - Practice:  random exercises (key-name, find-key, note-by-ear,
//                chord-id) with session HUD + lifetime stats footer +
//                feedback widget. Same shape as PracticeLab.
//
// Mounted by admin-dashboard.jsx as
// <window.PianoLab.ui.PianoLab />.

(function () {
  'use strict';
  window.PianoLab = window.PianoLab || {};
  window.PianoLab.ui = window.PianoLab.ui || {};

  const LESSONS = [
    { id: 'anatomy',        label: 'Keyboard anatomy',     comp: 'LessonAnatomy' },
    { id: 'note_names',     label: 'Naming the keys',      comp: 'LessonNoteNames' },
    { id: 'finger_numbers', label: 'Finger numbers',       comp: 'LessonFingerNumbers' },
    { id: 'c_major',        label: 'C major scale',        comp: 'LessonCMajor' },
    { id: 'triads',         label: 'Triads in C major',    comp: 'LessonTriads' },
    { id: 'hand_position',  label: 'Two-hand position',    comp: 'LessonHandPosition' },
  ];

  const EXERCISES = [
    { id: 'mixed',        label: 'Mixed' },
    { id: 'key_name',     label: 'Name the key' },
    { id: 'find_key',     label: 'Find the key' },
    { id: 'note_by_ear',  label: 'Note by ear' },
    { id: 'chord_id',     label: 'Chord by ear' },
  ];

  const DIFFICULTIES = [
    { id: 'beginner',     label: 'Beginner' },
    { id: 'intermediate', label: 'Intermediate' },
    { id: 'advanced',     label: 'Advanced' },
  ];

  const MIXED_POOL = ['key_name', 'find_key', 'note_by_ear', 'chord_id'];

  function pickNextExercise(currentExercise, lastInMixed) {
    if (currentExercise !== 'mixed') return currentExercise;
    const pool = MIXED_POOL.filter(function (id) { return id !== lastInMixed; });
    return pool[Math.floor(Math.random() * pool.length)];
  }

  const Pill = function (props) {
    const active = !!props.active;
    return (
      <button
        onClick={props.onClick}
        style={{
          padding: '8px 16px', borderRadius: 999,
          border: '1px solid ' + (active ? 'oklch(35% 0.16 265)' : 'oklch(88% 0.02 265)'),
          background: active ? 'oklch(35% 0.16 265)' : '#fff',
          color: active ? '#fff' : 'oklch(28% 0.05 265)',
          fontSize: 13, fontWeight: 600, cursor: 'pointer',
          fontFamily: "'Plus Jakarta Sans', sans-serif",
          transition: 'all 0.14s', whiteSpace: 'nowrap',
        }}
      >{props.children}</button>
    );
  };

  const StatTile = function (props) {
    return (
      <div style={{
        flex: 1, minWidth: 110, background: '#fff',
        border: '1px solid oklch(92% 0.012 265)', borderRadius: 12, padding: '14px 18px',
      }}>
        <div style={{ fontSize: 11, color: 'oklch(55% 0.04 265)', fontWeight: 600, letterSpacing: '0.04em', textTransform: 'uppercase', marginBottom: 6 }}>{props.label}</div>
        <div style={{ fontSize: 22, fontWeight: 700, color: 'oklch(18% 0.03 265)', lineHeight: 1.1 }}>{props.value}</div>
        {props.sub && <div style={{ fontSize: 11, color: 'oklch(55% 0.04 265)', marginTop: 4 }}>{props.sub}</div>}
      </div>
    );
  };

  const EnableSoundSplash = function (props) {
    return (
      <div style={{
        background: 'oklch(96% 0.02 80)', border: '1px solid oklch(85% 0.07 80)',
        borderRadius: 12, padding: '18px 20px', marginBottom: 18,
        display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap',
      }}>
        <svg aria-hidden="true" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="oklch(45% 0.13 80)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
          <path d="M15.54 8.46a5 5 0 0 1 0 7.07"/>
          <path d="M19.07 4.93a10 10 0 0 1 0 14.14"/>
        </svg>
        <div style={{ flex: 1, minWidth: 200 }}>
          <div style={{ fontSize: 14, fontWeight: 700, color: 'oklch(22% 0.06 265)', marginBottom: 3 }}>Enable sound</div>
          <div style={{ fontSize: 12.5, color: 'oklch(40% 0.04 265)' }}>Browsers require a click before playing audio. One tap and we’re set.</div>
        </div>
        <button
          onClick={props.onEnable}
          style={{
            padding: '10px 18px', borderRadius: 10, border: 'none',
            background: 'oklch(35% 0.16 265)', color: '#fff',
            fontSize: 13, fontWeight: 700, cursor: 'pointer',
            fontFamily: "'Plus Jakarta Sans', sans-serif",
          }}
        >Enable sound</button>
      </div>
    );
  };

  const LessonsView = function (props) {
    // activeLessonId is lifted to the parent PianoLab so the floating
    // FeedbackWidget can tag feedback rows with the lesson the user is
    // looking at (and use a value the piano_feedback CHECK constraint
    // actually accepts).
    const activeId = (props && props.activeLessonId) || 'anatomy';
    const setActiveId = (props && props.setActiveLessonId) || function () {};
    const lesson = LESSONS.find(function (l) { return l.id === activeId; });
    const LessonComp = lesson && window.PianoLab.ui[lesson.comp];

    return (
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(180px, 220px) 1fr', gap: 18, alignItems: 'start' }}>
        <aside>
          <div style={{ fontSize: 11, color: 'oklch(55% 0.04 265)', fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase', marginBottom: 10 }}>Lessons</div>
          <nav style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
            {LESSONS.map(function (l, i) {
              const active = l.id === activeId;
              return (
                <button
                  key={l.id}
                  onClick={function () { setActiveId(l.id); }}
                  style={{
                    textAlign: 'left',
                    padding: '10px 12px',
                    borderRadius: 10,
                    border: '1px solid ' + (active ? 'oklch(35% 0.16 265)' : 'transparent'),
                    background: active ? 'oklch(96% 0.04 265)' : 'transparent',
                    color: active ? 'oklch(20% 0.10 265)' : 'oklch(30% 0.04 265)',
                    fontSize: 13.5, fontWeight: active ? 700 : 500,
                    cursor: 'pointer',
                    fontFamily: "'Plus Jakarta Sans', sans-serif",
                    display: 'flex', alignItems: 'center', gap: 8,
                  }}
                >
                  <span style={{
                    display: 'inline-block', width: 22, height: 22, lineHeight: '22px', textAlign: 'center',
                    borderRadius: '50%', fontSize: 11, fontWeight: 700,
                    background: active ? 'oklch(60% 0.16 80)' : 'oklch(92% 0.012 265)',
                    color: active ? '#fff' : 'oklch(45% 0.04 265)',
                  }}>{i + 1}</span>
                  {l.label}
                </button>
              );
            })}
          </nav>
        </aside>

        <div style={{ background: '#fff', border: '1px solid oklch(92% 0.012 265)', borderRadius: 14, padding: 22, minWidth: 0 }}>
          {LessonComp ? <LessonComp /> : <div style={{ padding: 40, textAlign: 'center', color: 'oklch(55% 0.04 265)', fontSize: 13 }}>Loading lesson…</div>}
        </div>
      </div>
    );
  };

  const PracticeView = function (props) {
    const [difficulty, setDifficulty] = React.useState('beginner');
    const [exercise, setExercise] = React.useState('mixed');
    const [activeExercise, setActiveExercise] = React.useState(null);
    const [audioReady, setAudioReady] = React.useState(false);
    const [sessionScore, setSessionScore] = React.useState({ correct: 0, total: 0 });
    const [streak, setStreak] = React.useState(0);
    const [stats, setStats] = React.useState({ totalAttempts: 0, accuracy: 0, bestStreak: 0 });
    const [roundKey, setRoundKey] = React.useState(0);

    React.useEffect(function () {
      setActiveExercise(function (prev) { return pickNextExercise(exercise, prev); });
    }, [exercise, roundKey]);

    React.useEffect(function () {
      const id = setInterval(function () {
        try { setAudioReady(window.PianoLab.audio.isReady()); } catch (e) {}
      }, 500);
      return function () { clearInterval(id); };
    }, []);

    const refreshStats = React.useCallback(async function () {
      try {
        const s = await window.PianoLab.db.getLifetimeStats();
        setStats(s);
      } catch (e) { /* admin-only — ignore */ }
    }, []);

    React.useEffect(function () { refreshStats(); }, [refreshStats]);

    const enableSound = React.useCallback(async function () {
      try { await window.PianoLab.audio.resumeContext(); } catch (e) {}
      try { setAudioReady(window.PianoLab.audio.isReady()); } catch (e) {}
    }, []);

    const handleAttempt = React.useCallback(async function (attempt) {
      // Surface the most recent attempt to the parent so the floating
      // FeedbackWidget stores `exercise_context` for it.
      if (typeof props.setLastContext === 'function') {
        props.setLastContext(attempt);
      }
      setSessionScore(function (prev) {
        return {
          correct: prev.correct + (attempt.wasCorrect ? 1 : 0),
          total: prev.total + 1,
        };
      });
      setStreak(function (prev) { return attempt.wasCorrect ? prev + 1 : 0; });
      try { await window.PianoLab.db.recordAttempt(attempt); } catch (e) {}
      refreshStats();
      // Share latest exerciseType up so the FeedbackWidget tags
      // feedback with what the user just saw.
      if (typeof props.setLastExerciseType === 'function') {
        props.setLastExerciseType(attempt.exerciseType);
      }
    }, [refreshStats, props]);

    const handleNext = React.useCallback(function () {
      setRoundKey(function (k) { return k + 1; });
    }, []);

    const handlePickDifficulty = React.useCallback(function (d) {
      setDifficulty(d);
      setSessionScore({ correct: 0, total: 0 });
      setStreak(0);
      setRoundKey(function (k) { return k + 1; });
    }, []);

    const handlePickExercise = React.useCallback(function (e) {
      setExercise(e);
      setSessionScore({ correct: 0, total: 0 });
      setStreak(0);
      setRoundKey(function (k) { return k + 1; });
    }, []);

    const ExerciseComponent = (function () {
      switch (activeExercise) {
        case 'key_name':    return window.PianoLab.ui.ExerciseKeyName;
        case 'find_key':    return window.PianoLab.ui.ExerciseFindKey;
        case 'note_by_ear': return window.PianoLab.ui.ExerciseNoteByEar;
        case 'chord_id':    return window.PianoLab.ui.ExerciseChordId;
        default:            return null;
      }
    })();

    // Notify parent of activeExercise change too so FeedbackWidget tag
    // is up to date even before the first attempt.
    React.useEffect(function () {
      if (typeof props.setLastExerciseType === 'function' && activeExercise) {
        props.setLastExerciseType(activeExercise);
      }
    }, [activeExercise, props]);

    const showAudioSplash = !audioReady && (activeExercise === 'note_by_ear' || activeExercise === 'chord_id');

    return (
      <div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12, marginBottom: 18 }}>
          <div>
            <div style={{ fontSize: 11, color: 'oklch(55% 0.04 265)', fontWeight: 600, letterSpacing: '0.04em', textTransform: 'uppercase', marginBottom: 8 }}>Difficulty</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
              {DIFFICULTIES.map(function (d) {
                return <Pill key={d.id} active={difficulty === d.id} onClick={function () { handlePickDifficulty(d.id); }}>{d.label}</Pill>;
              })}
            </div>
          </div>
          <div>
            <div style={{ fontSize: 11, color: 'oklch(55% 0.04 265)', fontWeight: 600, letterSpacing: '0.04em', textTransform: 'uppercase', marginBottom: 8 }}>Exercise</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
              {EXERCISES.map(function (e) {
                return <Pill key={e.id} active={exercise === e.id} onClick={function () { handlePickExercise(e.id); }}>{e.label}</Pill>;
              })}
            </div>
          </div>
        </div>

        <div style={{ display: 'flex', gap: 10, marginBottom: 16, flexWrap: 'wrap' }}>
          <StatTile label="This session" value={sessionScore.total === 0 ? '0 / 0' : sessionScore.correct + ' / ' + sessionScore.total} sub={sessionScore.total === 0 ? 'No attempts yet' : Math.round((sessionScore.correct / sessionScore.total) * 100) + '% correct'} />
          <StatTile label="Current streak" value={String(streak)} sub={streak === 0 ? 'Get one right' : 'In a row'} />
        </div>

        {showAudioSplash && <EnableSoundSplash onEnable={enableSound} />}

        <div style={{ background: '#fff', border: '1px solid oklch(92% 0.012 265)', borderRadius: 14, padding: 22, minHeight: 320 }}>
          {!ExerciseComponent && (
            <div style={{ padding: 40, textAlign: 'center', color: 'oklch(55% 0.04 265)', fontSize: 13 }}>Loading exercise…</div>
          )}
          {ExerciseComponent && (
            <ExerciseComponent
              key={roundKey + ':' + activeExercise + ':' + difficulty}
              difficulty={difficulty}
              onAttempt={handleAttempt}
              onNext={handleNext}
            />
          )}
        </div>

        <div style={{
          marginTop: 22, padding: '14px 18px',
          background: 'oklch(98% 0.005 265)', border: '1px solid oklch(92% 0.012 265)', borderRadius: 12,
          display: 'flex', gap: 22, flexWrap: 'wrap',
        }}>
          <div style={{ fontSize: 11, color: 'oklch(55% 0.04 265)', fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase', alignSelf: 'center' }}>Lifetime</div>
          <div><strong style={{ fontWeight: 700 }}>{stats.totalAttempts}</strong> <span style={{ color: 'oklch(55% 0.04 265)', fontSize: 12 }}>attempts</span></div>
          <div><strong style={{ fontWeight: 700 }}>{stats.accuracy}%</strong> <span style={{ color: 'oklch(55% 0.04 265)', fontSize: 12 }}>accuracy</span></div>
          <div><strong style={{ fontWeight: 700 }}>{stats.bestStreak}</strong> <span style={{ color: 'oklch(55% 0.04 265)', fontSize: 12 }}>best streak</span></div>
        </div>
      </div>
    );
  };

  const PianoLab = function () {
    const [mode, setMode] = React.useState('lessons');
    const [lastExerciseType, setLastExerciseType] = React.useState(null);
    const [activeLessonId, setActiveLessonId] = React.useState('anatomy');
    // Most recent PracticeView attempt (or null). Held in a ref so a
    // re-render isn't triggered just because the user picked an answer —
    // it's only read inside getContext() when the feedback widget opens.
    const lastContextRef = React.useRef(null);
    function noteLastContext(ctx) {
      lastContextRef.current = ctx;
    }

    // exerciseType tag attached to feedback rows. Must match the
    // piano_feedback.exercise_type CHECK constraint values: the 4
    // practice exerciseType strings, or `lesson_<lessonId>` for the
    // 6 lesson ids. In lessons mode we send `lesson_<activeLessonId>`
    // (e.g. `lesson_anatomy`); in practice mode we send the most
    // recent attempt's exerciseType. Before the user has taken any
    // action in practice mode `lastExerciseType` is null and we fall
    // through with null (column allows null).
    function feedbackTag() {
      if (mode === 'lessons') return 'lesson_' + activeLessonId;
      return lastExerciseType;
    }

    return (
      <div style={{ fontFamily: "'Plus Jakarta Sans', sans-serif", maxWidth: 1100, margin: '0 auto', paddingBottom: 80 }}>
        {/* Beta banner */}
        <div style={{
          background: 'oklch(96% 0.04 265)', border: '1px solid oklch(85% 0.06 265)',
          color: 'oklch(28% 0.1 265)', borderRadius: 12, padding: '12px 16px',
          fontSize: 12.5, marginBottom: 16,
          display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap',
        }}>
          <strong style={{ fontWeight: 700 }}>Beta — admin only.</strong>
          <span style={{ opacity: 0.85 }}>Piano fundamentals: lessons + ear-training exercises. Built on Web Audio — no piano hardware required.</span>
        </div>

        {/* Mode toggle */}
        <div style={{ display: 'inline-flex', background: 'oklch(96% 0.01 265)', border: '1px solid oklch(90% 0.012 265)', borderRadius: 999, padding: 4, marginBottom: 18 }}>
          {[
            { id: 'lessons',  label: 'Lessons' },
            { id: 'practice', label: 'Practice' },
          ].map(function (m) {
            const active = m.id === mode;
            return (
              <button
                key={m.id}
                onClick={function () { setMode(m.id); }}
                style={{
                  padding: '8px 18px', borderRadius: 999, border: 'none',
                  background: active ? '#fff' : 'transparent',
                  color: active ? 'oklch(22% 0.06 265)' : 'oklch(50% 0.04 265)',
                  fontSize: 13, fontWeight: 700, cursor: 'pointer',
                  fontFamily: "'Plus Jakarta Sans', sans-serif",
                  boxShadow: active ? '0 1px 3px rgba(0,0,0,0.06)' : 'none',
                }}
              >{m.label}</button>
            );
          })}
        </div>

        {mode === 'lessons' && (
          <LessonsView
            activeLessonId={activeLessonId}
            setActiveLessonId={setActiveLessonId}
          />
        )}
        {mode === 'practice' && (
          <PracticeView
            setLastExerciseType={setLastExerciseType}
            setLastContext={noteLastContext}
          />
        )}

        {window.PianoLab.ui.FeedbackWidget && (
          <window.PianoLab.ui.FeedbackWidget
            exerciseType={feedbackTag()}
            getContext={function () { return lastContextRef.current; }}
          />
        )}
      </div>
    );
  };

  window.PianoLab.ui.PianoLab = PianoLab;
})();
