import { Dispatch, SetStateAction, useMemo, useRef } from 'react';
import { ParsedMIDIFile, Note, HighlightSpec } from './types';

const NOTE_HEIGHT = 2;

export type PlayingSpec = {
  channel: number;
  instrument: number;
  position: number;
  end: number;
};

const colors = [
  "#e60049",
  "#0bb4ff",
  "#50e991",
  "#e6d800",
  "#9b19f5",
  "#ffa300",
  "#dc0ab4",
  "#b3d4ff",
  "#00bfa0",
  "#fd7f6f",
  "#7eb0d5",
  "#b2e061",
  "#bd7ebe",
  "#ffb55a",
  "#ffee65",
  "#beb9db",
  "#fdcce5",
  "#8bd3c7",
];

const getChannelIndexColor = (i: number) => {
  return colors[i % colors.length];
};

const NoteLane = ({
  notes,
  end,
  highlights,
  channel,
  instrument,
  playing,
  setPlaying,
}: {
  notes: Note[];
  end: number;
  highlights: HighlightSpec[];
  channel: number;
  instrument: number;
  playing?: PlayingSpec;
  setPlaying?: Dispatch<SetStateAction<PlayingSpec>>;
}) => {
  const minPitch = useMemo(() => {
    let result = 128;
    notes.forEach((n) => {
      if (n.note < result) result = n.note;
    });
    return result;
  }, [notes]);
  const maxPitch = useMemo(() => {
    let result = 0;
    notes.forEach((n) => {
      if (n.note > result) result = n.note;
    });
    return result;
  }, [notes]);
  const laneHeight = (maxPitch - (minPitch - 1)) * NOTE_HEIGHT;

  const noteLaneRef = useRef<HTMLDivElement>(null);

  const mouseClickHandler = (e: React.MouseEvent<HTMLDivElement>) => {
    if (setPlaying) {
      const rect = noteLaneRef.current?.getBoundingClientRect();
      if (!rect) {
        return;
      }
      const u = (e.clientX - rect.x) / rect.width;
      for (let i = 0; i < highlights.length; i++) {
        const h = highlights[i];
        if (u >= h.start / end && u <= h.end / end) {
          setPlaying({ channel, instrument, position: h.start, end: h.end });
        }
      }
    }
  };

  const highlightThis = (h: HighlightSpec): boolean => {
    if (!playing) {
      return false;
    }
    if (playing.channel !== channel || playing.instrument != instrument) {
      return false;
    }
    return playing.position >= h.start && playing.position <= h.end;
  };

  return (
    <div
      ref={noteLaneRef}
      onClick={mouseClickHandler}
      className="relative overflow-hidden mt-1 bg-slate-950"
      style={{ height: laneHeight }}
    >
      {notes.map((n, i) => (
        <div
          className="absolute h-px"
          style={{
            left: `${(n.onBeat / end) * 100}%`,
            top: (maxPitch - n.note) * NOTE_HEIGHT,
            height: NOTE_HEIGHT,
            width: `${((n.offBeat - n.onBeat) / end) * 100}%`,
            backgroundColor: getChannelIndexColor(n.sourceTrack),
          }}
          key={i}
        >
          <div
            className="absolute w-px bg-inherit"
            style={{
              opacity: 0.1,
              top: -laneHeight,
              bottom: -laneHeight,
            }}
          />
        </div>
      ))}
      {highlights.map((h, i) => (
        <div
          key={i}
          className="absolute h-full border rounded"
          style={{
            backgroundColor: highlightThis(h)
              ? "rgba(255,128,128,0.2)"
              : "rgba(255,255,255,0.1)",
            left: `${(h.start / end) * 100}%`,
            width: `${((h.end - h.start) / end) * 100}%`,
          }}
        />
      ))}
    </div>
  );
};

export default NoteLane;
