/** @jsx jsx */
import { jsx } from '@emotion/core';
import styled from '@emotion/styled';
import { useRef, useEffect, useCallback, useContext } from 'react';
import { meterWidth as meterElementWidth } from '../styles/dimensions';
import { gray100, blue500 } from '../styles/colors_v2';
import useAnimationFrame from '../hooks/useAnimationFrame';
import { PlayerContext } from '../hooks/useProjectPlayer';

const MeterCanvas = styled.canvas``;

export default ({ analyser, height }: { analyser: AnalyserNode, height: number }) => {
  const rendererRef = useRef<HTMLCanvasElement>(null);
  const contextRef = useRef<CanvasRenderingContext2D | null>(null);
  const dataRef = useRef(new Uint8Array(analyser.fftSize));
  const lastMaxRef = useRef(-1);
  const { paused } = useContext(PlayerContext);
  const render = useCallback(
    (blank?: boolean) => {
      const canvas = rendererRef.current;
      if (!canvas) return;
      if (!contextRef.current) {
        contextRef.current = canvas.getContext('2d');
      }
      const context = contextRef.current;
      if (!context) return;
      if (blank) {
        context.fillStyle = gray100;
        context.fillRect(0, 0, meterElementWidth, canvas.height);
        return;
      }

      analyser.getByteTimeDomainData(dataRef.current);
      let max = 0;
      dataRef.current.forEach((d) => max = Math.max(Math.abs(d - 128), max));
      if (max !== lastMaxRef.current) {
        const barHeight = Math.round((max / 128) * canvas.height);
        context.fillStyle = gray100;
        context.fillRect(0, 0, meterElementWidth, canvas.height);
        context.fillStyle = blue500;
        context.fillRect(0, canvas.height - barHeight, meterElementWidth, barHeight);
      }
      lastMaxRef.current = max;
    },
    [analyser]
  );

  useAnimationFrame(render, !paused);

  useEffect(() => {
    if (paused) {
      setTimeout(() => render(true));
    }
  }, [paused, render]);

  return (
    <MeterCanvas ref={rendererRef} width={meterElementWidth} height={height} />
  );
};
