/* global React, window, Vex */
// Exercise: hear a one-bar rhythm, pick the matching notation.
//
// Picks a random pattern in 4/4 (V2 stays in 4/4 for the rhythm-match
// quiz — 3/4 + 6/8 are exposed in the time-signature ID quiz, where
// distinguishing them is the actual question; here the time sig is
// fixed so the user can focus on the rhythm shape).
//
// 4 options are rendered as small VexFlow bars. One is the played
// rhythm; the other 3 are random distractors from the same time sig.

(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);
  }

  function renderOptionBar(containerEl, pattern) {
    if (!vexAvailable() || !containerEl) return;
    containerEl.innerHTML = '';
    try {
      var VF = window.Vex.Flow;
      var width = 240;
      var height = 100;
      var renderer = new VF.Renderer(containerEl, VF.Renderer.Backends.SVG);
      renderer.resize(width, height);
      var ctx = renderer.getContext();
      var stave = new VF.Stave(4, 8, width - 8);
      stave.addClef('treble').addTimeSignature('4/4');
      stave.setContext(ctx).draw();
      var vexNotes = pattern.events.map(function (e) {
        var info = window.PracticeLab.rhythm.lookup(e.value);
        if (!info) return null;
        return new VF.StaveNote({
          clef: 'treble',
          keys: ['b/4'],
          duration: info.vex,
          autoStem: true,
        });
      }).filter(function (n) { return n; });
      var voice = new VF.Voice({ num_beats: 4, beat_value: 4 });
      voice.setStrict(false);
      voice.addTickables(vexNotes);
      new VF.Formatter().joinVoices([voice]).format([voice], width - 60);
      voice.draw(ctx, stave);
    } catch (e) {}
  }

  function pickRound() {
    var rhythm = window.PracticeLab.rhythm;
    var all = rhythm.patternsForTimeSig('4/4');
    if (all.length < 4) return null;
    var correct = all[Math.floor(Math.random() * all.length)];
    var distractors = rhythm.distractorsFor(correct, '4/4', 3);
    var options = rhythm.shuffle([correct].concat(distractors));
    return { correct: correct, options: options };
  }

  var ExerciseRhythmMatch = function (props) {
    const onAttempt = props.onAttempt || function () {};
    const onNext = props.onNext || function () {};

    const [round, setRound] = React.useState(null);
    const [picked, setPicked] = React.useState(null);
    const [vexReady, setVexReady] = React.useState(vexAvailable());
    const optionRefs = React.useRef([]);
    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 (!round) setRound(pickRound());
    }, [round]);

    React.useEffect(function () {
      if (!vexReady || !round) return;
      for (var i = 0; i < round.options.length; i++) {
        renderOptionBar(optionRefs.current[i], round.options[i]);
      }
    }, [vexReady, round]);

    const handlePlay = React.useCallback(function () {
      if (!round) return Promise.resolve();
      var timeline = window.PracticeLab.rhythm.patternToTimeline(round.correct);
      return window.PracticeLab.audio.playRhythm(timeline, 90, { withMetronome: true });
    }, [round]);

    // Auto-play the rhythm once on mount of each round so the user
    // hears it without having to click first. (Browsers gate audio
    // behind a user gesture — if the practice lab's "Enable sound"
    // splash hasn't been clicked yet, this no-ops and the user can
    // still hit the Play button manually.)
    React.useEffect(function () {
      if (!round || !window.PracticeLab.audio.isReady()) return;
      var cancelled = false;
      var t = setTimeout(function () {
        if (cancelled) return;
        handlePlay();
      }, 250);
      return function () { cancelled = true; clearTimeout(t); };
    }, [round, handlePlay]);

    const handlePick = React.useCallback(function (option, idx) {
      if (picked !== null || !round) return;
      setPicked(idx);
      if (submittedRef.current) return;
      submittedRef.current = true;
      var wasCorrect = option.id === round.correct.id;
      onAttempt({
        exerciseType: 'rhythm_match',
        difficulty: props.difficulty || 'beginner',
        prompt: { timeSig: '4/4', correctPatternId: round.correct.id },
        userAnswer: option.id,
        correctAnswer: round.correct.id,
        wasCorrect: wasCorrect,
      });
    }, [picked, round, props.difficulty, onAttempt]);

    const handleNext = React.useCallback(function () {
      // Parent (practice-lab or curriculum runner) bumps the React key
      // on this component when onNext is called, which remounts us with
      // fresh state. Don't try to clear state locally — the remount does it.
      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 }}>
          Match the rhythm you hear
        </div>
        <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 14 }}>
          <button
            onClick={handlePlay}
            disabled={!round}
            style={{
              padding: '10px 18px',
              borderRadius: 10,
              border: '1px solid ' + PRIMARY,
              background: '#fff',
              color: PRIMARY,
              fontSize: 14,
              fontWeight: 700,
              cursor: round ? 'pointer' : 'default',
              fontFamily: "'Plus Jakarta Sans', sans-serif",
            }}
          >▶ Play rhythm again</button>
        </div>
        <div style={{
          display: 'grid',
          gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))',
          gap: 10,
        }}>
          {round && round.options.map(function (opt, idx) {
            var isPicked = picked === idx;
            var isCorrectOpt = opt.id === round.correct.id;
            var border = SURFACE_BD;
            var bg = '#fff';
            if (picked !== null) {
              if (isCorrectOpt) { border = SUCCESS; bg = 'oklch(96% 0.03 152)'; }
              else if (isPicked) { border = ERROR; bg = 'oklch(96% 0.03 25)'; }
            }
            return (
              <button
                key={opt.id + ':' + idx}
                onClick={function () { handlePick(opt, idx); }}
                disabled={picked !== null}
                style={{
                  border: '2px solid ' + border,
                  background: bg,
                  borderRadius: 12,
                  padding: 8,
                  cursor: picked === null ? 'pointer' : 'default',
                  fontFamily: "'Plus Jakarta Sans', sans-serif",
                  textAlign: 'left',
                  overflow: 'hidden',
                }}
              >
                <div ref={function (el) { optionRefs.current[idx] = el; }} style={{ display:'flex', justifyContent:'center' }} />
              </button>
            );
          })}
        </div>
        {picked !== null && (
          <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.ExerciseRhythmMatch = ExerciseRhythmMatch;
})();
