import React, { useEffect, useRef } from 'react';
import { Observable } from 'rxjs';

const maxPeakValue = 32_768;

interface Props {
  width: number;
  height: number;
  peaks: Observable<number[]>;
  channels: number;
  strokeStyle: string;
  fillStyle: string;
  alpha: number;
}

// Canvas is a generic component that renders a waveform to a canvas.
const WaveformCanvas: React.FC<Props> = React.memo((props: Props) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    (async function () {
      const canvas = canvasRef.current;
      if (canvas == null) {
        console.error('no canvas ref available');
        return;
      }

      const ctx = canvas.getContext('2d');
      if (ctx == null) {
        console.error('no 2d context available');
        return;
      }

      ctx.strokeStyle = props.strokeStyle;
      ctx.fillStyle = props.fillStyle;
      ctx.fillRect(0, 0, canvas.width, canvas.height);

      if (props.peaks == null) {
        return;
      }

      const chanHeight = canvas.height / props.channels;

      let frameIndex = 0;
      await props.peaks
        .forEach((peaks) => {
          for (let chanIndex = 0; chanIndex < peaks.length; chanIndex++) {
            const yOffset = chanHeight * chanIndex;
            const val = peaks[chanIndex];
            const height = Math.floor((val / maxPeakValue) * chanHeight);
            const y1 = (chanHeight - height) / 2 + yOffset;
            const y2 = y1 + height;
            ctx.beginPath();
            ctx.globalAlpha = props.alpha;
            ctx.moveTo(frameIndex, y1);
            ctx.lineTo(frameIndex, y2);
            ctx.stroke();
            ctx.globalAlpha = 1;
          }
          frameIndex++;
        })
        .catch(console.error);
    })();
  }, [props.peaks]);

  return (
    <>
      <canvas
        ref={canvasRef}
        className={`block absolute w-full h-full z-10`}
        width={props.width}
        height={props.height}
      ></canvas>
    </>
  );
});

WaveformCanvas.displayName = 'WaveformCanvas';
export { WaveformCanvas };
