import { getValueAtBeatsCached } from '@suno/studiokit/timeMapping';
import { useAnimationFrame } from 'framer-motion';
import { useMemo, useRef } from 'react';

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

import StudioContext from './StudioContext';
import {
  getDerivedTiming,
  getSongEndBeats,
  getSongStartBeats,
} from './selectors';

export default function CurrentBPM() {
  const ref = useRef<HTMLSpanElement>(null);
  const lastBPMRef = useRef(120);
  const getCurrentBeats = useContextSelector(
    StudioContext,
    (ctx) => ctx.playbackController.getCurrentBeats
  );
  const derivedTiming = useContextSelector(StudioContext, (ctx) =>
    getDerivedTiming(ctx.state)
  );
  const songStartBeats = useContextSelector(StudioContext, (ctx) =>
    getSongStartBeats(ctx.state)
  );
  const songEndBeats = useContextSelector(StudioContext, (ctx) =>
    getSongEndBeats(ctx.state)
  );
  const boundedAutomationPoints = useMemo(() => {
    return [
      {
        beats: songStartBeats,
        value: derivedTiming.bpsAutomation[0]?.value ?? derivedTiming.bps,
        curve: 0,
      },
      ...derivedTiming.bpsAutomation,
      {
        beats: songEndBeats,
        value:
          derivedTiming.bpsAutomation[derivedTiming.bpsAutomation.length - 1]
            ?.value ?? derivedTiming.bps,
        curve: 0,
      },
    ];
  }, [derivedTiming.bps, derivedTiming.bpsAutomation]);

  useAnimationFrame(() => {
    if (!ref.current) return;

    const currentBeats = getCurrentBeats();
    const currentBPM = boundedAutomationPoints.length
      ? getValueAtBeatsCached(currentBeats, boundedAutomationPoints)[0] * 60
      : derivedTiming.bps * 60;
    const newBPM = Math.round(currentBPM);

    if (newBPM !== lastBPMRef.current) {
      lastBPMRef.current = newBPM;
      ref.current.textContent = newBPM.toString();
    }
  });

  return <span ref={ref}>{lastBPMRef.current}</span>;
}
