import React, { useState, useEffect, useRef, useCallback } from 'react';
import * as Tone from 'tone';
import { state, updateModuleParam, emit } from '../engine/state.js';
import { setSequencerSignals, getAudioNode } from '../engine/audioEngine.js';

const NOTE_NAMES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];

function midiToFreq(midi) { return 440 * Math.pow(2, (midi - 69) / 12); }
function noteLabel(midi) { return NOTE_NAMES[midi % 12] + Math.floor(midi / 12 - 1); }

// Default notes: C minor pentatonic pattern
const DEFAULT_STEPS = [
  { midi: 60, gate: true },  { midi: 63, gate: true },  { midi: 65, gate: false }, { midi: 67, gate: true },
  { midi: 70, gate: true },  { midi: 67, gate: true },  { midi: 63, gate: false }, { midi: 60, gate: true },
  { midi: 58, gate: true },  { midi: 60, gate: true },  { midi: 63, gate: false }, { midi: 65, gate: true },
  { midi: 67, gate: true },  { midi: 72, gate: true },  { midi: 70, gate: false }, { midi: 67, gate: true },
];

export default function SequencerWidget({ moduleId }) {
  const mod = state.modules.find(m => m.id === moduleId);
  const [currentStep, setCurrentStep] = useState(-1);
  const seqRef = useRef(null);
  const stepsRef = useRef(null);

  // Init steps data
  const numSteps = parseInt(mod?.params?.steps || '16');
  if (!mod?.params?._steps) {
    const initial = DEFAULT_STEPS.slice(0, numSteps);
    while (initial.length < numSteps) initial.push({ midi: 60, gate: false });
    if (mod) {
      mod.params._steps = initial;
    }
  }
  const steps = mod?.params?._steps || DEFAULT_STEPS;
  stepsRef.current = steps;

  const bpm = mod?.params?.bpm ?? 140;

  // Start/stop sequencer when audio engine runs
  useEffect(() => {
    if (!state.isRunning) {
      if (seqRef.current) { seqRef.current.stop(); seqRef.current.dispose(); seqRef.current = null; }
      setCurrentStep(-1);
      return;
    }

    Tone.getTransport().bpm.value = bpm;

    const seq = new Tone.Sequence((time, stepIdx) => {
      const s = stepsRef.current[stepIdx];
      if (!s) return;
      setCurrentStep(stepIdx);

      if (s.gate) {
        setSequencerSignals(moduleId, midiToFreq(s.midi), true);
        Tone.getTransport().scheduleOnce(() => {
          setSequencerSignals(moduleId, midiToFreq(s.midi), false);
        }, time + Tone.Time('16n').toSeconds() * 0.8);
      } else {
        setSequencerSignals(moduleId, midiToFreq(s.midi), false);
      }
    }, Array.from({ length: numSteps }, (_, i) => i), '16n');

    seq.start(0);
    if (Tone.getTransport().state !== 'started') {
      Tone.getTransport().start();
    }
    seqRef.current = seq;

    return () => {
      if (seqRef.current) { seqRef.current.stop(); seqRef.current.dispose(); seqRef.current = null; }
    };
  }, [state.isRunning, moduleId, numSteps]);

  // Update BPM live
  useEffect(() => {
    if (state.isRunning) Tone.getTransport().bpm.value = bpm;
  }, [bpm]);

  const toggleGate = (idx) => {
    steps[idx] = { ...steps[idx], gate: !steps[idx].gate };
    updateModuleParam(moduleId, '_steps', [...steps]);
    stepsRef.current = steps;
  };

  const changeNote = (idx, delta) => {
    const newMidi = Math.max(36, Math.min(96, steps[idx].midi + delta));
    steps[idx] = { ...steps[idx], midi: newMidi };
    updateModuleParam(moduleId, '_steps', [...steps]);
    stepsRef.current = steps;
    emit();
  };

  const CELL_W = 18;
  const CELL_H = 50;
  const W = CELL_W * numSteps;
  const H = CELL_H + 16;

  return (
    <div style={{ width: W + 4, overflow: 'hidden' }}>
      <svg viewBox={`0 0 ${W} ${H}`} style={{ width: W, height: H, display: 'block' }}>
        {/* Steps */}
        {steps.slice(0, numSteps).map((s, i) => {
          const x = i * CELL_W;
          const isActive = i === currentStep;
          const barHeight = ((s.midi - 36) / 60) * (CELL_H - 4);

          return (
            <g key={i}>
              {/* Background */}
              <rect x={x + 1} y={0} width={CELL_W - 2} height={CELL_H}
                rx={2} fill={isActive ? '#1a2a40' : '#0c0c18'}
                stroke={isActive ? '#00e5ff' : '#222'} strokeWidth={isActive ? 1.5 : 0.5}
              />
              {/* Note bar */}
              {s.gate && (
                <rect x={x + 3} y={CELL_H - barHeight - 2} width={CELL_W - 6} height={barHeight}
                  rx={1}
                  fill={isActive ? '#00e5ff' : '#0088aa'}
                  opacity={0.9}
                />
              )}
              {/* Inactive marker */}
              {!s.gate && (
                <line x1={x + CELL_W / 2} y1={CELL_H / 2 - 3} x2={x + CELL_W / 2} y2={CELL_H / 2 + 3}
                  stroke="#333" strokeWidth={1.5} />
              )}
              {/* Note name */}
              <text x={x + CELL_W / 2} y={CELL_H + 10} textAnchor="middle"
                fontSize={6} fill={s.gate ? '#88ccff' : '#333'} fontFamily="monospace">
                {noteLabel(s.midi)}
              </text>
              {/* Click areas: top half = note up, bottom half = note down, middle = toggle gate */}
              <rect x={x} y={0} width={CELL_W} height={CELL_H / 3}
                fill="transparent" style={{ cursor: 'pointer' }}
                onClick={() => changeNote(i, 1)}
              />
              <rect x={x} y={CELL_H / 3} width={CELL_W} height={CELL_H / 3}
                fill="transparent" style={{ cursor: 'pointer' }}
                onClick={() => toggleGate(i)}
              />
              <rect x={x} y={CELL_H * 2 / 3} width={CELL_W} height={CELL_H / 3}
                fill="transparent" style={{ cursor: 'pointer' }}
                onClick={() => changeNote(i, -1)}
              />
            </g>
          );
        })}
        {/* Playhead line */}
        {currentStep >= 0 && (
          <line
            x1={currentStep * CELL_W + CELL_W / 2} y1={0}
            x2={currentStep * CELL_W + CELL_W / 2} y2={CELL_H}
            stroke="#00e5ff" strokeWidth={1} opacity={0.4}
          />
        )}
      </svg>
      <div style={{ fontSize: 8, color: '#555', textAlign: 'center', marginTop: 2 }}>
        ↑top/↓bot: pitch · mid: toggle
      </div>
    </div>
  );
}
