import { pitchToMultiplier } from '@suno/studiokit/audioEngineeringUtils';
import { addSecondsToBeats } from '@suno/studiokit/timeMapping';
import { getWarpSecondsFromBeats } from '@suno/studiokit/warpUtils';

import getClipRelativePoint from '../getClipRelativePoint';
import { getDerivedTiming, getStudioClipsById } from '../selectors';
import { StudioProjectState } from '../types';
import updateClip from './updateClip';

export default function toggleClipWarp(
  studioClipId: string,
  warpEnabled?: boolean
) {
  return (state: StudioProjectState): StudioProjectState => {
    const withClipUpdated = updateClip(studioClipId, (studioClip) => {
      const newWarpEnabled = warpEnabled ?? !studioClip.warp.enabled;
      const timing = getDerivedTiming(state);
      const readEndBeats = getClipRelativePoint(
        timing,
        studioClip,
        studioClip.endBeats,
        true
      )[0];
      let newEndBeats = studioClip.endBeats;
      if (!newWarpEnabled) {
        const readEndSeconds = getWarpSecondsFromBeats(
          studioClip.warp,
          readEndBeats
        );
        const readStartSeconds = getWarpSecondsFromBeats(
          studioClip.warp,
          studioClip.readStartBeats
        );

        const contentDurationSeconds =
          (readEndSeconds - readStartSeconds) /
          pitchToMultiplier(studioClip.transposition);

        newEndBeats = addSecondsToBeats(
          contentDurationSeconds,
          studioClip.startBeats,
          timing
        );
      } else {
        const readEndSeconds = getWarpSecondsFromBeats(
          studioClip.warp,
          readEndBeats
        );
        const readStartSeconds = getWarpSecondsFromBeats(
          studioClip.warp,
          studioClip.readStartBeats
        );

        const contentDurationSeconds =
          (readEndSeconds - readStartSeconds) *
          pitchToMultiplier(studioClip.transposition);

        newEndBeats = addSecondsToBeats(
          contentDurationSeconds,
          studioClip.startBeats,
          timing
        );
      }
      return {
        ...studioClip,
        endBeats: newEndBeats,
        warp: {
          ...studioClip.warp,
          enabled: newWarpEnabled,
        },
      };
    })(state);
    const clip = getStudioClipsById(withClipUpdated)[studioClipId];
    if (!clip) {
      return withClipUpdated;
    }
    return {
      ...withClipUpdated,
      selection: {
        ...withClipUpdated.selection,
        focusBeats: clip.endBeats,
        anchorBeats: clip.startBeats,
      },
    };
  };
}
