import { getWarpBeatsFromSeconds } from '@suno/studiokit/warpUtils';

import { fetchClip } from '@/hooks/useClip';
import { ClipsStore } from '@/state/clipStore';
import { getClipTitle } from '@/utils/clip';
import { getOrGenerateOpusFileUrl } from '@/utils/download';
import snap from '@/utils/snap';

import fetchRefinedAlignedLyrics from '../edit2025/fetchers/fetchRefinedAlignedLyrics';
import getSections from '../edit2025/getSections';
import { fetchAndPollDownbeats } from '../edit2025/queryHooks/useEditTimingQuery';
import clearTimeFromClipList from './clearTimeFromClipList';
import createStudioClipSync from './createStudioClipSync';
import createTrack from './createTrack';
import DEFAULT_STATE from './defaultState';
import getProjectTimingForClip from './getProjectTimingForClip';
import { StudioProjectState } from './types';

export default async function getEditModeStateForClip(
  clipsStore: ClipsStore,
  clipId: string,
  splitSections: boolean = true
): Promise<StudioProjectState> {
  const clip = await fetchClip(clipsStore, clipId, true);

  if (clip.status !== 'complete') {
    throw new Error('Clip is not complete');
  }

  // make sure we have an opus url before proceeding
  await getOrGenerateOpusFileUrl(clipsStore.apiClient, clipId);

  const [downbeats, alignedLyrics] = await Promise.all([
    fetchAndPollDownbeats(clipsStore.apiClient, clipId),
    clip.metadata.prompt
      ? fetchRefinedAlignedLyrics(
          clipsStore.apiClient,
          clipId,
          clip.metadata.prompt
        )
      : [],
  ]);

  const track = createTrack(true);
  track.name = getClipTitle(clip) || 'New Track';

  const { clip: studioClip, timing } = createStudioClipSync(clip, downbeats);

  track.clips.push(studioClip);

  const sectionsBySeconds = getSections(alignedLyrics);
  const sectionsByBeats = Object.entries(sectionsBySeconds)
    .sort((a, b) => Number(a[0]) - Number(b[0]))
    .map(([seconds, section], index) => [
      snap(
        getWarpBeatsFromSeconds(studioClip.warp, Number(seconds)),
        index === 0 ? 0 : 1,
        'floor'
      ),
      {
        name: section.name,
        color: section.color,
      },
    ]) as [number, { name: string; color: string }][];

  if (splitSections) {
    sectionsByBeats.forEach(([beats, { name, color }]) => {
      track.clips = clearTimeFromClipList(timing, beats, beats, track.clips);
      const clip = track.clips.find((c) => c.startBeats === beats);
      if (clip) {
        clip.name = name;
        clip.color = color;
      }
    });
  }

  const baseState: StudioProjectState = {
    ...DEFAULT_STATE,
    title: getClipTitle(clip),
    caption: clip.caption || undefined,
    styleSummary: clip.display_tags || undefined,
    editClipId: clip.id,
    loop: {
      startBeats: 0,
      endBeats: 0,
      enabled: false,
    },
    metronome: {
      enabled: false,
      amplitude: 1.0,
    },
    timing: getProjectTimingForClip(studioClip, track.id),
    tracks: [track],
    selection: {
      anchorBeats: 0,
      focusBeats: 0,
      trackIds: [track.id],
      focusedTrackId: track.id,
      focusedArea: 'timeline',
    },
    songFadeInBeats: 0,
    songFadeOutBeats: 0,
  };

  return baseState;
}
