import styled from '@emotion/styled';
import { useAnimationFrame } from 'framer-motion';
import { useCallback, useRef } from 'react';

import { useContextSelector } from '@/hooks/useContextSelector';

import StudioContext from './StudioContext';

const EndBar = styled.div`
  width: 2px;
  height: 12px;
  border-radius: 2px;
  background-color: #fff;
`;

const InnerBar = styled.div`
  width: 2px;
  height: 10px;
  border-radius: 2px;
  background-color: #fff;
`;

export default function Metronome() {
  const playing = useContextSelector(
    StudioContext,
    (ctx) => ctx.playbackController.playing
  );
  const getCurrentBeats = useContextSelector(
    StudioContext,
    (ctx) => ctx.playbackController.getCurrentBeats
  );
  const metronomeEnabled = useContextSelector(
    StudioContext,
    (ctx) => ctx.state.metronome.enabled
  );

  const metronomeWrapperRef = useRef<HTMLDivElement>(null);

  const lastOscillationPosition = useRef(0);
  const lastRising = useRef(false);
  const lastBar1TriggerTime = useRef(0);
  const lastBar2TriggerTime = useRef(0);
  const lastBar3TriggerTime = useRef(0);
  const lastBar4TriggerTime = useRef(0);
  const lastBar5TriggerTime = useRef(0);

  useAnimationFrame(
    useCallback(() => {
      const wrapper = metronomeWrapperRef.current;
      if (!wrapper) return;

      if (!metronomeEnabled || !playing) {
        wrapper.style.backgroundColor = '';
      }

      const baseOpacity = 0.35;
      wrapper.querySelectorAll('div').forEach((bar) => {
        bar.style.opacity = `${baseOpacity}`;
      });

      if (!metronomeEnabled) return;

      if (!playing) {
        return;
      }

      const currentBeat = getCurrentBeats();
      const positionInBeatPair = currentBeat % 2;
      const rising = positionInBeatPair <= 1;
      const oscillationPosition =
        positionInBeatPair > 1 ? 2 - positionInBeatPair : positionInBeatPair;
      const op = oscillationPosition;
      const lop = lastOscillationPosition.current;
      const bo = baseOpacity;
      const bor = 1 - baseOpacity;

      const bar1 = wrapper.querySelector('.bar-1') as HTMLDivElement;
      const bar2 = wrapper.querySelector('.bar-2') as HTMLDivElement;
      const bar3 = wrapper.querySelector('.bar-3') as HTMLDivElement;
      const bar4 = wrapper.querySelector('.bar-4') as HTMLDivElement;
      const bar5 = wrapper.querySelector('.bar-5') as HTMLDivElement;
      const now = Date.now();
      const fadeTime = 200;
      const getOpacity = (lastTriggerTime: number) => {
        const timeSinceLastTrigger = now - lastTriggerTime;
        if (timeSinceLastTrigger > fadeTime) {
          return `${baseOpacity}`;
        }
        return `${bo + bor * (1 - timeSinceLastTrigger / fadeTime)}`;
      };

      if (rising) {
        if (!lastRising.current) {
          lastRising.current = true;
          lastBar1TriggerTime.current = now;
        }

        if (op > 0.25 && lop < 0.25) {
          lastBar2TriggerTime.current = now;
        }

        if (op > 0.5 && lop < 0.5) {
          lastBar3TriggerTime.current = now;
        }

        if (op > 0.75 && lop < 0.75) {
          lastBar4TriggerTime.current = now;
        }
      } else {
        if (lastRising.current) {
          lastRising.current = false;
          lastBar5TriggerTime.current = now;
        }

        if (op < 0.75 && lop > 0.75) {
          lastBar4TriggerTime.current = now;
        }

        if (op < 0.5 && lop > 0.5) {
          lastBar3TriggerTime.current = now;
        }

        if (op < 0.25 && lop > 0.25) {
          lastBar2TriggerTime.current = now;
        }
      }

      lastOscillationPosition.current = op;
      bar1.style.opacity = getOpacity(lastBar1TriggerTime.current);
      bar2.style.opacity = getOpacity(lastBar2TriggerTime.current);
      bar3.style.opacity = getOpacity(lastBar3TriggerTime.current);
      bar4.style.opacity = getOpacity(lastBar4TriggerTime.current);
      bar5.style.opacity = getOpacity(lastBar5TriggerTime.current);
    }, [metronomeEnabled, getCurrentBeats, playing])
  );

  return (
    <div
      className='flex items-center gap-[2px]'
      style={{
        transition: 'none',
      }}
      ref={metronomeWrapperRef}
    >
      <EndBar className='bar-1' />
      <InnerBar className='bar-2' />
      <InnerBar className='bar-3' />
      <InnerBar className='bar-4' />
      <EndBar className='bar-5' />
    </div>
  );
}
