/* global React, window, Vex */
// Lesson 2.1 — Note values: whole, half, quarter, eighth.
// Body-only.

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

  // Render one isolated note of the given duration on a treble staff.
  // We pick C5 as the pitch for all four so the visual focus is on the
  // stem / head shape, not the pitch.
  function renderSingleNote(containerEl, vexDuration) {
    if (!vexAvailable() || !containerEl) return;
    containerEl.innerHTML = '';
    try {
      var VF = window.Vex.Flow;
      var width = 130;
      var height = 110;
      var renderer = new VF.Renderer(containerEl, VF.Renderer.Backends.SVG);
      renderer.resize(width, height);
      var ctx = renderer.getContext();
      var stave = new VF.Stave(6, 12, width - 12);
      stave.addClef('treble');
      stave.setContext(ctx).draw();
      var note = new VF.StaveNote({
        clef: 'treble',
        keys: ['b/4'],
        duration: vexDuration,
        autoStem: true,
      });
      var voice = new VF.Voice({ num_beats: 4, beat_value: 4 });
      voice.setStrict(false);
      voice.addTickables([note]);
      new VF.Formatter().joinVoices([voice]).format([voice], width - 60);
      voice.draw(ctx, stave);
    } catch (e) {}
  }

  // Render a "side-by-side" comparison bar showing how many of each note
  // fits in one bar of 4/4. We use rests to pad rather than chaining
  // multiple identical notes — for the visual comparison the count is
  // what matters, not the playback.
  function renderRelativeBar(containerEl, vexDur, count) {
    if (!vexAvailable() || !containerEl) return;
    containerEl.innerHTML = '';
    try {
      var VF = window.Vex.Flow;
      var width = 220;
      var height = 110;
      var renderer = new VF.Renderer(containerEl, VF.Renderer.Backends.SVG);
      renderer.resize(width, height);
      var ctx = renderer.getContext();
      var stave = new VF.Stave(6, 12, width - 12);
      stave.addClef('treble').addTimeSignature('4/4');
      stave.setContext(ctx).draw();
      var notes = [];
      for (var i = 0; i < count; i++) {
        notes.push(new VF.StaveNote({
          clef: 'treble',
          keys: ['b/4'],
          duration: vexDur,
          autoStem: true,
        }));
      }
      var voice = new VF.Voice({ num_beats: 4, beat_value: 4 });
      voice.setStrict(false);
      voice.addTickables(notes);
      new VF.Formatter().joinVoices([voice]).format([voice], width - 80);
      voice.draw(ctx, stave);
    } catch (e) {}
  }

  var LessonRhythmBasics = function () {
    const Bits = window.PracticeLab.ui.LessonBits;
    if (!Bits) return null;
    const Section = Bits.Section;
    const DemoBox = Bits.DemoBox;
    const PlayButton = Bits.PlayButton;
    const audio = window.PracticeLab.audio;
    const rhythm = window.PracticeLab.rhythm;

    const wholeRef   = React.useRef(null);
    const halfRef    = React.useRef(null);
    const quarterRef = React.useRef(null);
    const eighthRef  = React.useRef(null);

    const wholeBarRef   = React.useRef(null);
    const halfBarRef    = React.useRef(null);
    const quarterBarRef = React.useRef(null);
    const eighthBarRef  = React.useRef(null);

    const [vexReady, setVexReady] = React.useState(vexAvailable());

    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 (!vexReady) return;
      renderSingleNote(wholeRef.current,   'w');
      renderSingleNote(halfRef.current,    'h');
      renderSingleNote(quarterRef.current, 'q');
      renderSingleNote(eighthRef.current,  '8');

      renderRelativeBar(wholeBarRef.current,   'w', 1);
      renderRelativeBar(halfBarRef.current,    'h', 2);
      renderRelativeBar(quarterBarRef.current, 'q', 4);
      renderRelativeBar(eighthBarRef.current,  '8', 8);
    }, [vexReady]);

    const playValue = React.useCallback(async function (qu, label) {
      // Play `count` clicks across `qu` quarter-note units at 90 BPM,
      // matching how a quarter note feels at that tempo.
      var pattern = { events: [{ value: label }] };
      var timeline = rhythm.patternToTimeline(pattern);
      return audio.playRhythm(timeline, 90, { withMetronome: false });
    }, [audio, rhythm]);

    return (
      <div>
        <Section heading="A note tells you two things">
          Every written note tells you <strong>which pitch</strong> to play (its position on the staff) and <strong>how long</strong> to hold it (its shape). The shape — open or filled head, stem, flags — is the <em>duration</em>. We'll cover the four most common shapes first.
        </Section>

        <Section heading="The four basic note values">
          <DemoBox label="Whole note · 4 beats">
            <div ref={wholeRef} />
            <div style={{ marginTop: 8 }}>
              <PlayButton label="Hear a whole note" onPlay={function () { return playValue(4, 'whole'); }} />
            </div>
            <div style={{ marginTop: 8, fontSize: 13, color: 'oklch(40% 0.04 265)' }}>Open head, no stem. Held for four beats. Counts: <strong>1 – 2 – 3 – 4</strong>.</div>
          </DemoBox>
          <DemoBox label="Half note · 2 beats">
            <div ref={halfRef} />
            <div style={{ marginTop: 8 }}>
              <PlayButton label="Hear a half note" onPlay={function () { return playValue(2, 'half'); }} />
            </div>
            <div style={{ marginTop: 8, fontSize: 13, color: 'oklch(40% 0.04 265)' }}>Open head with a stem. Held for two beats. Counts: <strong>1 – 2</strong>.</div>
          </DemoBox>
          <DemoBox label="Quarter note · 1 beat">
            <div ref={quarterRef} />
            <div style={{ marginTop: 8 }}>
              <PlayButton label="Hear a quarter note" onPlay={function () { return playValue(1, 'quarter'); }} />
            </div>
            <div style={{ marginTop: 8, fontSize: 13, color: 'oklch(40% 0.04 265)' }}>Filled head with a stem. One beat. The "default" tap.</div>
          </DemoBox>
          <DemoBox label="Eighth note · ½ beat">
            <div ref={eighthRef} />
            <div style={{ marginTop: 8 }}>
              <PlayButton label="Hear an eighth note" onPlay={function () { return playValue(0.5, 'eighth'); }} />
            </div>
            <div style={{ marginTop: 8, fontSize: 13, color: 'oklch(40% 0.04 265)' }}>Filled head + flag (or a beam if two or more are next to each other). Half a beat. Two eighths fit in one quarter — say <strong>"1-and-2-and"</strong>.</div>
          </DemoBox>
        </Section>

        <Section heading="How they fit in a bar of 4/4">
          A bar of <strong>4/4</strong> holds <strong>four beats</strong>. So one bar can fit:
          <DemoBox label="1 whole">
            <div ref={wholeBarRef} />
          </DemoBox>
          <DemoBox label="2 halves">
            <div ref={halfBarRef} />
          </DemoBox>
          <DemoBox label="4 quarters">
            <div ref={quarterBarRef} />
          </DemoBox>
          <DemoBox label="8 eighths">
            <div ref={eighthBarRef} />
          </DemoBox>
        </Section>

        <Section heading="The relationship" last>
          1 whole = 2 halves = 4 quarters = 8 eighths. Each step down the chain is twice as fast. If you remember this one chain you can convert any duration in your head.
        </Section>
      </div>
    );
  };

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