/* global React, window, Vex */
// Exercise: identify a single natural note on the BASS clef.
//
// Same shape as window.PracticeLab.ui.ExerciseNoteStaff but locked to
// the bass clef and a sensible bass-range MIDI window. Distinct
// exercise_type so analytics can split treble vs bass.

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

  function vexAvailable() {
    return !!(typeof window.Vex !== 'undefined' && window.Vex && window.Vex.Flow);
  }

  // Bass-clef ranges by difficulty. Beginner: stay inside the staff
  // (G2 to A3). Intermediate adds one ledger line above + below.
  function rangeFor(difficulty) {
    if (difficulty === 'intermediate') return { minMidi: 41, maxMidi: 60 }; // F2 to C4
    if (difficulty === 'advanced')     return { minMidi: 36, maxMidi: 62 }; // C2 to D4
    return { minMidi: 43, maxMidi: 57 }; // G2 to A3 (in-staff)
  }

  function randInt(lo, hi) { return lo + Math.floor(Math.random() * (hi - lo + 1)); }

  function midiToNaturalLetter(midi) {
    var pc = ((midi % 12) + 12) % 12;
    var map = { 0:'C', 2:'D', 4:'E', 5:'F', 7:'G', 9:'A', 11:'B' };
    return map[pc] || null;
  }
  function midiToOctave(midi) { return Math.floor(midi / 12) - 1; }

  function pickRandomNatural(range) {
    var midi, letter;
    var attempts = 0;
    do {
      midi = randInt(range.minMidi, range.maxMidi);
      letter = midiToNaturalLetter(midi);
      attempts++;
      if (attempts > 20) {
        midi = 50; letter = 'D'; break;
      }
    } while (!letter);
    return { midi: midi, letter: letter, octave: midiToOctave(midi) };
  }

  function renderBassNote(containerEl, letter, octave) {
    if (!vexAvailable() || !containerEl) return;
    containerEl.innerHTML = '';
    try {
      var VF = window.Vex.Flow;
      var width = 260;
      var height = 140;
      var renderer = new VF.Renderer(containerEl, VF.Renderer.Backends.SVG);
      renderer.resize(width, height);
      var ctx = renderer.getContext();
      ctx.setFont('Plus Jakarta Sans', 11);
      var stave = new VF.Stave(10, 18, width - 20);
      stave.addClef('bass');
      stave.setContext(ctx).draw();
      var note = new VF.StaveNote({
        clef: 'bass',
        keys: [letter.toLowerCase() + '/' + octave],
        duration: 'w',
        autoStem: true,
      });
      var voice = new VF.Voice({ num_beats: 4, beat_value: 4 });
      voice.addTickables([note]);
      new VF.Formatter().joinVoices([voice]).format([voice], width - 80);
      voice.draw(ctx, stave);
    } catch (e) {
      try {
        containerEl.textContent = 'Staff failed to render — pick Next for a new question.';
        containerEl.style.padding = '24px';
        containerEl.style.textAlign = 'center';
        containerEl.style.color = '#999';
        containerEl.style.fontSize = '13px';
      } catch (e2) {}
    }
  }

  var ALL_LETTERS = ['C','D','E','F','G','A','B'];

  var ExerciseBassNote = function (props) {
    const difficulty = props.difficulty || 'beginner';
    const onAttempt = props.onAttempt || function () {};
    const onNext = props.onNext || function () {};

    // Memoize so re-renders during a single round don't create a fresh
    // object identity each time — otherwise the `[prompt, range]` effect
    // below re-fires on every render and risks repicking the prompt.
    const range = React.useMemo(function () { return rangeFor(difficulty); }, [difficulty]);
    const [prompt, setPrompt] = React.useState(null);
    const [picked, setPicked] = React.useState(null);
    const [vexReady, setVexReady] = React.useState(vexAvailable());
    const staffRef = React.useRef(null);
    const submittedRef = React.useRef(false);

    React.useEffect(function () {
      if (vexReady) return;
      const id = setInterval(function () {
        if (vexAvailable()) { setVexReady(true); clearInterval(id); }
      }, 100);
      return function () { clearInterval(id); };
    }, [vexReady]);

    React.useEffect(function () {
      if (!prompt) {
        setPrompt(pickRandomNatural(range));
      }
    }, [prompt, range]);

    React.useEffect(function () {
      if (!vexReady || !prompt) return;
      renderBassNote(staffRef.current, prompt.letter, prompt.octave);
    }, [vexReady, prompt]);

    const handlePick = React.useCallback(function (letter) {
      if (picked || !prompt) return;
      setPicked(letter);
      if (submittedRef.current) return;
      submittedRef.current = true;
      onAttempt({
        exerciseType: 'bass_note',
        difficulty: difficulty,
        prompt: { midi: prompt.midi, letter: prompt.letter, octave: prompt.octave, clef: 'bass' },
        userAnswer: letter,
        correctAnswer: prompt.letter,
        wasCorrect: letter === prompt.letter,
      });
    }, [picked, prompt, difficulty, onAttempt]);

    const handleNext = React.useCallback(function () {
      submittedRef.current = false;
      setPicked(null);
      setPrompt(null);
      onNext();
    }, [onNext]);

    const PRIMARY = 'oklch(35% 0.16 265)';
    const SUCCESS = 'oklch(48% 0.13 152)';
    const ERROR   = 'oklch(58% 0.18 25)';
    const SURFACE_BD = 'oklch(92% 0.012 265)';

    return (
      <div>
        <div style={{ fontSize: 12, color: 'oklch(55% 0.04 265)', fontWeight: 700, letterSpacing: '0.05em', textTransform: 'uppercase', marginBottom: 8 }}>
          Identify the note on the bass clef
        </div>
        <div ref={staffRef} style={{ display: 'flex', justifyContent: 'center', minHeight: 140 }} />
        <div style={{ marginTop: 14, display: 'flex', gap: 8, flexWrap: 'wrap', justifyContent: 'center' }}>
          {ALL_LETTERS.map(function (L) {
            var isCorrect = picked && L === prompt.letter;
            var isWrongPick = picked === L && L !== prompt.letter;
            var bg = '#fff', color = 'oklch(28% 0.05 265)', border = SURFACE_BD;
            if (isCorrect) { bg = SUCCESS; color = '#fff'; border = SUCCESS; }
            else if (isWrongPick) { bg = ERROR; color = '#fff'; border = ERROR; }
            return (
              <button
                key={L}
                onClick={function () { handlePick(L); }}
                disabled={!!picked}
                style={{
                  padding: '12px 18px',
                  borderRadius: 10,
                  border: '1px solid ' + border,
                  background: bg,
                  color: color,
                  fontSize: 16,
                  fontWeight: 700,
                  minWidth: 52,
                  cursor: picked ? 'default' : 'pointer',
                  fontFamily: "'Plus Jakarta Sans', sans-serif",
                }}
              >{L}</button>
            );
          })}
        </div>
        {picked && (
          <div style={{ marginTop: 18, display: 'flex', justifyContent: 'center' }}>
            <button
              onClick={handleNext}
              style={{
                padding: '11px 22px',
                borderRadius: 10,
                border: 'none',
                background: PRIMARY,
                color: '#fff',
                fontSize: 14,
                fontWeight: 700,
                cursor: 'pointer',
                fontFamily: "'Plus Jakarta Sans', sans-serif",
              }}
            >Next →</button>
          </div>
        )}
      </div>
    );
  };

  window.PracticeLab.ui.ExerciseBassNote = ExerciseBassNote;
})();
