import { v4 as uuidv4 } from 'uuid';

import { stemColors } from '@/components/edit2025/StemsContext';
import { Clip } from '@/state/clipStore';
import { getClipTitle } from '@/utils/clip';

import createKnownTimingStudioClipSync from '../createKnownTimingStudioClipSync';
import createTrack from '../createTrack';
import getProjectTimingForClip from '../getProjectTimingForClip';
import insertAfterFocusedTrack from '../insertAfterFocusedTrack';
import insertClipsToList from '../insertClipsToList';
import { getDerivedTiming, getFocusedTrackClips } from '../selectors';
import { StudioProjectState } from '../types';

export default function autoArrangeStem(
  clip: Clip,
  parentDownbeats: [number, number][],
  parentDurationSeconds: number,
  arrangementMatchClipId: string | null | undefined = clip.metadata.stem_from_id
) {
  return (state: StudioProjectState): StudioProjectState => {
    const timing = getDerivedTiming(state);
    const focusedTrackId = state.selection.focusedTrackId;
    const focusedTrackClips = getFocusedTrackClips(state);
    const studioClip = createKnownTimingStudioClipSync(
      clip,
      parentDownbeats,
      parentDurationSeconds
    );

    const clipsOnFocusedTrack = arrangementMatchClipId
      ? focusedTrackClips.filter((c) => c.clipId === arrangementMatchClipId)
      : [];

    const newTrack = createTrack();
    const stemGroupId = clip.metadata.stem_type_group_name;
    newTrack.instrument = ['Vocals', 'Backing_Vocals'].includes(
      stemGroupId ?? ''
    )
      ? {
          type: 'vocalPreset',
          prompt: stemGroupId!,
        }
      : stemGroupId
        ? {
            type: 'nonVocalPreset',
            prompt: stemGroupId,
          }
        : {
            type: 'song',
          };
    newTrack.name = stemGroupId ?? getClipTitle(clip);
    clipsOnFocusedTrack?.forEach((referenceStudioClip) => {
      newTrack.clips = insertClipsToList(
        timing,
        [
          {
            ...studioClip,
            id: uuidv4(),
            color:
              stemColors[
                clip.metadata.stem_type_group_name as keyof typeof stemColors
              ] ?? studioClip.color,
            transposition: referenceStudioClip.transposition,
            startBeats: referenceStudioClip.startBeats,
            endBeats: referenceStudioClip.endBeats,
            readStartBeats: referenceStudioClip.readStartBeats,
            warp: { ...referenceStudioClip.warp },
            loop: { ...referenceStudioClip.loop },
          },
        ],
        newTrack.clips
      );
    });
    if (newTrack.clips.length === 0) {
      newTrack.clips.push({
        ...studioClip,
        id: uuidv4(),
        startBeats: studioClip.readStartBeats,
        endBeats:
          studioClip.endBeats +
          (studioClip.readStartBeats - studioClip.startBeats),
      });
    }
    let oldTracks = state.tracks;
    if (clipsOnFocusedTrack.length > 0) {
      oldTracks = oldTracks.map((t) =>
        t.id === focusedTrackId ? { ...t, mute: true } : t
      );
    }
    return {
      ...state,
      tracks: insertAfterFocusedTrack(
        oldTracks,
        state.selection.focusedTrackId,
        newTrack
      ),
      timing:
        state.tracks.length === 0
          ? getProjectTimingForClip(studioClip, newTrack.id)
          : state.timing,
    };
  };
}
