/* eslint jsx-a11y/no-static-element-interactions: warn */
import { noop } from 'lodash-es';
import { observer } from 'mobx-react-lite';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useLocalStorage } from 'usehooks-ts';

import { useStores } from '@/app/(root)/AppProviders';
import { StemView } from '@/app/(root)/stems/StemsTypes';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import {
  ContextMenuItem,
  ContextMenuItemSubtext,
  ContextMenuTrigger,
} from '@/components/contextMenu/ContextMenu';
import {
  EditorPlaybackState,
  EditorPlaybackTrack,
  useEditorStatePlayer,
} from '@/components/edit2025/EditPlaybackContext';
import { StemTypeId } from '@/components/edit2025/StemsContext';
import { getPojoBuffer } from '@/components/edit2025/bufferStorage';
import downloadAsZip from '@/components/edit2025/downloadAsZip';
import { useDownbeatsQuery } from '@/components/edit2025/queryHooks/useEditTimingQuery';
import { useKeyQuery } from '@/components/edit2025/queryHooks/useKeyQuery';
import { ArrangedClip, EditTiming } from '@/components/edit2025/types';
import ImageWithFallback from '@/components/image/ImageWithFallback';
import Link from '@/components/link/Link';
import Modal from '@/components/modal/Modal';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import SelectorV2, {
  SelectorOption,
  SelectorV2Option,
} from '@/components/select/SelectorV2';
import { tagsToArray } from '@/components/song/songUtils';
import MagicStudioButton from '@/components/studio/MagicStudioButton';
import { useStudioProjectManagement } from '@/components/studio/StudioProjectManagementContext';
import createKnownTimingStudioClipSync from '@/components/studio/createKnownTimingStudioClipSync';
import createTrack from '@/components/studio/createTrack';
import DEFAULT_STATE from '@/components/studio/defaultState';
import getProjectTimingForClip from '@/components/studio/getProjectTimingForClip';
import { useClips } from '@/components/studio/hooks/useClips';
import { getAllUsedClipIds } from '@/components/studio/selectors';
import { StudioProjectState } from '@/components/studio/types';
import SpinnerSVG from '@/components/svg/SpinnerSVG';
import MusicStyleTags from '@/components/tag/MusicStyleTags';
import { toast } from '@/components/toast/Toast';
import { Tooltip } from '@/components/tooltip/Tooltip';
import { useModalContext } from '@/context/ModalContext';
import useClip from '@/hooks/useClip';
import useGenerate, {
  ModelTier,
  PromptType,
  ReferenceType,
} from '@/hooks/useGenerate';
import {
  MidiInstrumentSchema,
  getMidiForClip,
} from '@/hooks/useMidiTranscript';
import { useStreamingDownbeats } from '@/hooks/useStreamingDownbeats';
import {
  ArrowLeftIcon,
  DownloadIcon,
  InstrumentLeadVocalsIcon,
  MusicNoteIcon,
  PauseIcon,
  PlayIcon,
  SlidersIcon,
  StemsIcon,
  StudioIcon,
} from '@/icons';
import logWebUserEvent, {
  createTransactionLogger,
} from '@/logging/logWebUserEvent';
import { Clip } from '@/state/clipStore';
import { FeatureKey, PlanFeature } from '@/state/sessionStore';
import { getClipTitle } from '@/utils/clip';
import { NO_STYLE_FALLBACK, SMALL_IMAGE } from '@/utils/constants';
import { downloadClipAudio, getOrGenerateWavFileUrl } from '@/utils/download';
import downloadStemsAsZip from '@/utils/downloadStemsAsZip';
import jsonToMidi from '@/utils/midi';
import { isFeatureEnabledForPlan } from '@/utils/session';

import CreateAudioDisplay from '../create/createV2/componentsQ3/CreateAudioDisplay';
import { useUrlAudioSampler } from '../create/createV2/componentsQ3/useUrlAudioSampler';
import stemIconMap from './stemIconMap';

const getBGFromName = (name: string) => {
  const lowerName = name.toLowerCase();
  if (lowerName.includes('percussion')) return 'bg-slime-500';
  else if (lowerName.includes('backing')) return 'bg-dandelion-600';
  else if (lowerName.includes('vocal')) return 'bg-strawberry-500';
  else if (lowerName.includes('guitar')) return 'bg-pumpkin-400';
  else if (lowerName.includes('bass')) return 'bg-pumpkin-500';
  else if (lowerName.includes('keyboard')) return 'bg-amethyst-500';
  else if (lowerName.includes('synth')) return 'bg-blue-500';
  else return 'bg-slime-500';
};

const nameMap = {
  Vocals: 'Lead Vocals',
  Backing_Vocals: 'Backing Vocals',
  Drums: 'Drums',
  Bass: 'Bass',
  Guitar: 'Guitar',
  Keyboard: 'Keyboard',
  Percussion: 'Percussion',
  Strings: 'Strings',
  Synth: 'Synth',
  FX: 'Other',
  Brass: 'Brass',
  Woodwinds: 'Woodwinds',
};
const INITIAL_STEM_TYPE_SETTINGS = {
  FULL_SONG: {
    solo: false,
    mute: false,
  },
  Vocals: {
    solo: false,
    mute: false,
  },
  Backing_Vocals: {
    solo: false,
    mute: false,
  },
  Drums: {
    solo: false,
    mute: false,
  },
  Bass: {
    solo: false,
    mute: false,
  },
  Guitar: {
    solo: false,
    mute: false,
  },
  Keyboard: {
    solo: false,
    mute: false,
  },
  Percussion: {
    solo: false,
    mute: false,
  },
  Strings: {
    solo: false,
    mute: false,
  },
  Synth: {
    solo: false,
    mute: false,
  },
  FX: {
    solo: false,
    mute: false,
  },
  Brass: {
    solo: false,
    mute: false,
  },
  Woodwinds: {
    solo: false,
    mute: false,
  },
};

type MidiState =
  | { type: 'disabled' }
  | { type: 'loading' }
  | { type: 'available'; transcript: MidiInstrumentSchema[]; blob: Blob }
  | { type: 'unavailable' };

const getDownloadFormatOptions = (midiEnabled: boolean): SelectorV2Option[] => {
  const baseOptions: SelectorV2Option[] = [
    {
      value: 'mp3',
      title: 'MP3',
      isDefault: true,
      ListComponent: () => (
        <SelectorOption className='flex flex-col justify-start'>
          <div className='text-sm font-medium'>MP3 Audio</div>
          <div className='-mb-0.5 text-xs text-foreground-secondary'>
            Small files, fast download
          </div>
        </SelectorOption>
      ),
    },
    {
      value: 'wav',
      title: 'WAV',
      ListComponent: () => (
        <SelectorOption className='flex flex-col justify-start'>
          <div className='text-sm font-medium'>WAV Audio</div>
          <div className='-mb-0.5 text-xs text-foreground-secondary'>
            Large files, high quality
          </div>
        </SelectorOption>
      ),
    },
    {
      value: 'wav-tempo-locked',
      title: 'WAV (Tempo-Locked)',
      ListComponent: () => (
        <SelectorOption className='flex flex-col justify-start'>
          <div className='text-sm font-medium'>WAV (Tempo-Locked)</div>
          <div className='-mb-0.5 text-xs text-foreground-secondary'>
            Aligned to song tempo
          </div>
        </SelectorOption>
      ),
    },
  ];

  if (midiEnabled) {
    baseOptions.push(
      {
        value: 'midi',
        title: 'MIDI',
        ListComponent: () => (
          <SelectorOption className='flex flex-col justify-start'>
            <div className='text-sm font-medium'>MIDI Files</div>
            <div className='-mb-0.5 text-xs text-foreground-secondary'>
              Musical note data only
            </div>
          </SelectorOption>
        ),
      },
      {
        value: 'wav+midi',
        title: 'WAV+MIDI',
        ListComponent: () => (
          <SelectorOption className='flex flex-col justify-start'>
            <div className='text-sm font-medium'>WAV + MIDI Files</div>
            <div className='-mb-0.5 text-xs text-foreground-secondary'>
              Audio and MIDI together
            </div>
          </SelectorOption>
        ),
      }
    );
  }

  return baseOptions;
};

const FullSongTrack = ({
  clip,
  solo,
  effectivelyMuted,
  setSolo,
  getCurrentSeconds,
  seek,
  playing,
  setPlaying,
  loading,
}: {
  clip: Clip;
  solo: boolean;
  effectivelyMuted: boolean;
  setSolo: (solo: boolean, nonDestructive?: boolean) => void;
  getCurrentSeconds: () => number;
  seek: (seconds: number) => void;
  playing: boolean;
  setPlaying: (playing: boolean) => void;
  loading: boolean;
}) => {
  const { clips: clipsStore, edit: editStore, session } = useStores();
  const [downloading, setDownloading] = useState(false);
  const [isDragging, setIsDragging] = useState(false);
  const waveformRef = useRef<HTMLDivElement>(null);

  const handleMouseDown = (e: React.MouseEvent) => {
    if (!waveformRef.current) return;
    setIsDragging(true);
    const targetRect = waveformRef.current.getBoundingClientRect();
    const progress = (e.clientX - targetRect.left) / targetRect.width;
    const newSeconds = progress * (clip.metadata.duration || 8 * 60);
    seek(newSeconds);
  };

  const handleMouseMove = useCallback(
    (e: MouseEvent) => {
      if (!isDragging || !waveformRef.current) return;
      const targetRect = waveformRef.current.getBoundingClientRect();
      const progress = Math.max(
        0,
        Math.min(1, (e.clientX - targetRect.left) / targetRect.width)
      );
      const newSeconds = progress * (clip.metadata.duration || 8 * 60);
      seek(newSeconds);
    },
    [isDragging, clip.metadata.duration, seek]
  );

  const handleMouseUp = useCallback(() => {
    setIsDragging(false);
  }, []);

  useEffect(() => {
    if (isDragging) {
      document.addEventListener('mousemove', handleMouseMove);
      document.addEventListener('mouseup', handleMouseUp);
      return () => {
        document.removeEventListener('mousemove', handleMouseMove);
        document.removeEventListener('mouseup', handleMouseUp);
      };
    }
  }, [isDragging, handleMouseMove, handleMouseUp]);

  const sampleAudio = useUrlAudioSampler(clip.id, clip.status);
  const getCurrentProgress = useCallback(() => {
    return getCurrentSeconds() / (clip.metadata.duration || 8 * 60);
  }, [getCurrentSeconds, clip.metadata.duration]);
  const setCurrentProgress = useCallback(
    (progress: number) => {
      seek(progress * (clip.metadata.duration || 8 * 60));
    },
    [seek, clip.metadata.duration]
  );

  return (
    <div className='grid grid-cols-[40px_20px_1fr_46px] grid-rows-[20px_20px] gap-1 rounded-[10px] bg-white/5 p-1'>
      <Button
        variant={ButtonVariant.Tertiary}
        className='col-[1/2] row-[1/3] m-0 flex h-[45px] w-10 items-center justify-center p-0'
        icon={loading ? <SpinnerSVG /> : playing ? <PauseIcon /> : <PlayIcon />}
        onClick={() => setPlaying(!playing)}
      />
      <Tooltip label={`Solo this track`} placement='left'>
        <Button
          variant={solo ? ButtonVariant.Primary : ButtonVariant.Standard}
          className={`${solo ? '' : 'bg-white/5'} col-[2/3] row-[1/3] h-[45px] w-5`}
          size={ButtonSize.Micro}
          onClick={(e) => setSolo(!solo, e.shiftKey || e.metaKey || e.ctrlKey)}
        >
          S
        </Button>
      </Tooltip>
      <div
        className={`relative col-[3/4] row-[1/3] flex items-center ${effectivelyMuted ? 'opacity-25' : 'opacity-100'}`}
      >
        <div
          ref={waveformRef}
          className={`relative h-full w-full overflow-hidden rounded-[5px] bg-white/5 [&_.clip-name]:opacity-100 [&_.clip-name]:transition-opacity [&_.clip-name]:duration-200 [&_.clip-name]:ease-in-out hover:[&_.clip-name]:opacity-0 ${isDragging ? 'cursor-grabbing' : 'cursor-pointer'}`}
          onMouseDown={handleMouseDown}
        >
          <CreateAudioDisplay
            height={43}
            isPlaying={playing}
            sampleAudio={sampleAudio}
            getCurrentProgress={getCurrentProgress}
            setCurrentProgress={setCurrentProgress}
          />
          <div className='clip-name absolute top-0 left-0 flex h-full w-full items-center justify-start pl-2.5 text-xs font-medium select-none'>
            Full Song
          </div>
        </div>
      </div>
      <Tooltip label={downloading ? 'Downloading...' : ''}>
        <ContextMenuTrigger
          placement='bottom-right'
          ButtonComponent={(props) => (
            <Button
              variant={ButtonVariant.Tertiary}
              className='col-[4/5] row-[1/3] m-0 flex h-[45px] w-full items-center justify-center'
              icon={downloading ? <SpinnerSVG /> : <DownloadIcon />}
              disabled={downloading}
              {...props}
            />
          )}
          ContentsComponent={() => (
            <>
              <ContextMenuItem
                onClick={async () => {
                  setDownloading(true);
                  logWebUserEvent({
                    actionName: 'EditV3DownloadStem',
                    context: {
                      editSessionId:
                        editStore.editSessionId || 'MISSING_EDIT_SESSION_ID',
                      editingClipId: clip.id,
                      stemId: clip.id,
                      format: 'mp3',
                    },
                  });
                  await downloadClipAudio(
                    clipsStore.apiClient,
                    clip,
                    session,
                    'audio'
                  );
                  setDownloading(false);
                }}
              >
                MP3 Audio
                <ContextMenuItemSubtext>
                  Small files, fast download
                </ContextMenuItemSubtext>
              </ContextMenuItem>
              <ContextMenuItem
                onClick={async () => {
                  setDownloading(true);
                  logWebUserEvent({
                    actionName: 'EditV3DownloadStem',
                    context: {
                      editSessionId:
                        editStore.editSessionId || 'MISSING_EDIT_SESSION_ID',
                      editingClipId: clip.id,
                      stemId: clip.id,
                      format: 'wav',
                    },
                  });
                  await downloadClipAudio(
                    clipsStore.apiClient,
                    clip,
                    session,
                    'audio-wav',
                    await getOrGenerateWavFileUrl(clipsStore.apiClient, clip.id)
                  );
                  setDownloading(false);
                }}
              >
                WAV Audio
                <ContextMenuItemSubtext>
                  Large files, high quality
                </ContextMenuItemSubtext>
              </ContextMenuItem>
            </>
          )}
        />
      </Tooltip>
    </div>
  );
};

const StemTrackSkeleton = ({
  stemIndex,
  totalItems,
  midiEnabled,
}: {
  stemIndex: number;
  totalItems: number;
  midiEnabled: boolean;
}) => {
  // Calculate opacity with more dramatic falloff for vocals+instrumental (2 items)
  // For 2 items: 0.5 -> 0.2, for 4 items: 0.5 -> 0.35 -> 0.2 -> 0.1
  const falloffRate = totalItems === 2 ? 0.3 : 0.15;
  const opacity = Math.max(0.5 - stemIndex * falloffRate, 0.1);

  return (
    <div
      className={`grid rounded-[10px] bg-white/5 ${midiEnabled ? 'grid-cols-[40px_20px_1fr_46px_46px]' : 'grid-cols-[40px_20px_1fr_46px]'} grid-rows-[20px_20px] gap-1 p-1`}
      style={{ opacity }}
    >
      <div className='col-[1/2] row-[1/3] m-0 flex h-[45px] w-10 items-center justify-center rounded-[5px] bg-white/10 p-0'>
        <StemsIcon className='text-white/50' />
      </div>
      <div className='col-[2/3] row-[1/2] h-5 w-5 rounded-[3px] bg-white/10' />
      <div className='col-[2/3] row-[2/3] h-5 w-5 rounded-[3px] bg-white/10' />
      <div className='relative col-[3/4] row-[1/3] flex items-center'>
        <div className='relative flex h-full w-full items-center justify-center overflow-hidden rounded-[5px] bg-white/10'>
          <div className='flex items-center gap-2'>
            <SpinnerSVG className='h-4 w-4 text-white/50' />
            <div className='text-xs font-medium text-white/50'>
              Extracting stem ...
            </div>
          </div>
        </div>
      </div>
      {midiEnabled && (
        <div className='col-[4/5] row-[1/3] m-0 flex h-[45px] w-full items-center justify-center rounded-[5px] bg-white/10'>
          <MusicNoteIcon className='text-white/30' />
        </div>
      )}
      <div
        className={`m-0 flex h-[45px] w-full items-center justify-center ${midiEnabled ? 'col-[5/6]' : 'col-[4/5]'} row-[1/3] rounded-[5px] bg-white/10`}
      >
        <DownloadIcon className='text-white/30' />
      </div>
    </div>
  );
};

const StemTrack = ({
  clip,
  solo,
  mute,
  effectivelyMuted,
  setSolo,
  setMute,
  getCurrentSeconds,
  seek,
  playing,
  downloadFormat,
  parentClipId,
  midiState,
  onGenerateMidi,
  parentDownbeats,
  parentKey,
}: {
  clip: Clip;
  solo: boolean;
  mute: boolean;
  effectivelyMuted: boolean;
  setSolo: (solo: boolean, nonDestructive?: boolean) => void;
  setMute: (mute: boolean) => void;
  getCurrentSeconds: () => number;
  seek: (seconds: number) => void;
  playing: boolean;
  downloadFormat: 'mp3' | 'wav' | 'midi' | 'wav+midi' | 'wav-tempo-locked';
  parentClipId: string;
  midiState: MidiState;
  onGenerateMidi: (clipId: string) => Promise<MidiInstrumentSchema[] | null>;
  parentDownbeats: [number, number][] | undefined;
  parentKey: string | null | undefined;
}) => {
  const { clips: clipsStore, edit: editStore, session } = useStores();
  const [downloading, setDownloading] = useState(false);
  const [isDragging, setIsDragging] = useState(false);
  const waveformRef = useRef<HTMLDivElement>(null);
  const [downloadingMidi, setDownloadingMidi] = useState(false);

  const handleMouseDown = useCallback(
    (e: React.MouseEvent) => {
      if (!waveformRef.current) return;
      setIsDragging(true);
      const targetRect = waveformRef.current.getBoundingClientRect();
      const progress = (e.clientX - targetRect.left) / targetRect.width;
      const newSeconds = progress * (clip.metadata.duration || 8 * 60);
      seek(newSeconds);
    },
    [clip.metadata.duration, seek]
  );

  const handleMouseMove = useCallback(
    (e: MouseEvent) => {
      if (!isDragging || !waveformRef.current) return;
      const targetRect = waveformRef.current.getBoundingClientRect();
      const progress = Math.max(
        0,
        Math.min(1, (e.clientX - targetRect.left) / targetRect.width)
      );
      const newSeconds = progress * (clip.metadata.duration || 8 * 60);
      seek(newSeconds);
    },
    [isDragging, clip.metadata.duration, seek]
  );

  const handleMouseUp = useCallback(() => {
    setIsDragging(false);
  }, []);

  useEffect(() => {
    if (isDragging) {
      document.addEventListener('mousemove', handleMouseMove);
      document.addEventListener('mouseup', handleMouseUp);
      return () => {
        document.removeEventListener('mousemove', handleMouseMove);
        document.removeEventListener('mouseup', handleMouseUp);
      };
    }
  }, [isDragging, handleMouseMove, handleMouseUp]);

  const sampleAudio = useUrlAudioSampler(clip.id, clip.status);
  const getCurrentProgress = useCallback(() => {
    return getCurrentSeconds() / (clip.metadata.duration || 8 * 60);
  }, [getCurrentSeconds, clip.metadata.duration]);
  const setCurrentProgress = useCallback(
    (progress: number) => {
      seek(progress * (clip.metadata.duration || 8 * 60));
    },
    [seek, clip.metadata.duration]
  );

  return (
    <div
      className={`grid rounded-[10px] bg-white/5 ${midiState.type !== 'disabled' ? 'grid-cols-[40px_20px_1fr_46px_46px]' : 'grid-cols-[40px_20px_1fr_46px]'} grid-rows-[20px_20px] gap-1 p-1`}
    >
      <Button
        variant={ButtonVariant.Tertiary}
        className='col-[1/2] row-[1/3] m-0 flex h-[45px] w-10 items-center justify-center p-0'
        icon={
          stemIconMap[
            clip.metadata.stem_type_group_name as keyof typeof stemIconMap
          ] ? (
            stemIconMap[
              clip.metadata.stem_type_group_name as keyof typeof stemIconMap
            ]()
          ) : (
            <StemsIcon />
          )
        }
      />
      <Tooltip
        label={`Solo this stem (Shift-click to select multiple)`}
        placement='left'
      >
        <Button
          variant={solo ? ButtonVariant.Primary : ButtonVariant.Standard}
          className={`${solo ? '' : 'bg-white/5'} col-[2/3] row-[1/2] h-5 w-5`}
          size={ButtonSize.Micro}
          onClick={(e) => setSolo(!solo, e.shiftKey || e.metaKey || e.ctrlKey)}
        >
          S
        </Button>
      </Tooltip>
      <Tooltip label={'Mute this stem'} placement='left'>
        <Button
          variant={mute ? ButtonVariant.Primary : ButtonVariant.Standard}
          className={`${mute ? '' : 'bg-white/5'} col-[2/3] row-[2/3] h-5 w-5`}
          size={ButtonSize.Micro}
          onClick={() => setMute(!mute)}
        >
          M
        </Button>
      </Tooltip>
      <div
        className={`relative col-[3/4] row-[1/3] flex items-center ${effectivelyMuted ? 'opacity-25' : 'opacity-100'}`}
      >
        {clip.status !== 'complete' && (
          <div className='absolute top-0 left-0 flex h-full w-full items-center justify-center'>
            <SpinnerSVG />
          </div>
        )}
        <div
          ref={waveformRef}
          className={`${getBGFromName(clip.title || '')} relative h-full w-full overflow-hidden rounded-[5px] [&_.clip-name]:opacity-100 [&_.clip-name]:transition-opacity [&_.clip-name]:duration-200 [&_.clip-name]:ease-in-out hover:[&_.clip-name]:opacity-0 ${clip.status === 'complete' ? 'opacity-100' : 'opacity-20'} ${isDragging ? 'cursor-grabbing' : 'cursor-pointer'}`}
          onMouseDown={handleMouseDown}
        >
          <CreateAudioDisplay
            height={43}
            isPlaying={playing}
            sampleAudio={sampleAudio}
            getCurrentProgress={getCurrentProgress}
            setCurrentProgress={setCurrentProgress}
          />

          <div className='clip-name absolute top-0 left-0 flex h-full w-full items-center justify-start pl-2.5 text-xs font-medium text-white select-none'>
            {nameMap[
              clip.metadata.stem_type_group_name as keyof typeof nameMap
            ] ?? clip.metadata.stem_type_group_name?.replace('_', ' ')}
          </div>
        </div>
      </div>
      {midiState.type !== 'disabled' && (
        <Tooltip
          label={
            downloadingMidi
              ? 'Generating and downloading MIDI...'
              : midiState.type === 'loading'
                ? 'MIDI transcript in progress...'
                : midiState.type === 'available'
                  ? 'Download MIDI transcript for this stem'
                  : clip.status !== 'complete'
                    ? 'MIDI available when stem is complete'
                    : 'Generate MIDI transcript for this stem'
          }
        >
          <Button
            variant={ButtonVariant.Tertiary}
            className='col-[4/5] row-[1/3] m-0 flex h-full w-full items-center justify-center'
            icon={
              downloadingMidi || midiState.type === 'loading' ? (
                <SpinnerSVG />
              ) : (
                <MusicNoteIcon />
              )
            }
            disabled={
              downloadingMidi ||
              midiState.type === 'loading' ||
              clip.status !== 'complete'
            }
            onClick={async () => {
              setDownloadingMidi(true);
              try {
                let blob: Blob;

                if (midiState.type === 'available') {
                  // Already generated, just download
                  blob = midiState.blob;
                } else {
                  // Generate MIDI on-demand
                  const transcript = await onGenerateMidi(clip.id);
                  if (
                    !transcript ||
                    transcript.length === 0 ||
                    !parentDownbeats
                  ) {
                    toast({
                      title: 'No MIDI data available',
                      description:
                        'This stem does not contain transcribable notes',
                      status: 'info',
                    });
                    return;
                  }

                  // Convert to MIDI blob
                  const midiBlob = jsonToMidi(
                    clip.title || null,
                    transcript,
                    parentDownbeats,
                    parentKey || null,
                    clip.metadata.stem_type_group_name || null
                  );

                  if (!midiBlob) {
                    toast({
                      title: 'Failed to generate MIDI',
                      description: 'Could not convert transcript to MIDI file',
                      status: 'error',
                    });
                    return;
                  }

                  blob = midiBlob;
                }

                // Download the MIDI file
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `${clip.title || 'stem'}.mid`;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);

                logWebUserEvent({
                  actionName: 'EditV3DownloadStem',
                  context: {
                    editSessionId:
                      editStore.editSessionId || 'MISSING_EDIT_SESSION_ID',
                    editingClipId: parentClipId,
                    stemId: clip.id,
                    format: 'midi',
                  },
                });
              } catch (error) {
                console.error('Failed to download MIDI:', error);
                toast({
                  title: 'Failed to download MIDI',
                  description:
                    'An error occurred while downloading the MIDI file',
                  status: 'error',
                });
              } finally {
                setDownloadingMidi(false);
              }
            }}
          />
        </Tooltip>
      )}
      <Tooltip
        label={
          downloading
            ? downloadFormat === 'wav' ||
              downloadFormat === 'wav+midi' ||
              downloadFormat === 'wav-tempo-locked'
              ? 'Downloading .WAV (this may take some time)'
              : 'Downloading .MP3...'
            : ''
        }
      >
        <Button
          variant={ButtonVariant.Tertiary}
          className={`m-0 flex h-full w-full items-center justify-center ${midiState.type !== 'disabled' ? 'col-[5/6]' : 'col-[4/5]'} row-[1/3]`}
          icon={downloading ? <SpinnerSVG /> : <DownloadIcon />}
          disabled={downloading}
          onClick={async () => {
            setDownloading(true);
            // Individual stem downloads use the audio format (not wav+midi or wav-tempo-locked)
            const audioFormat =
              downloadFormat === 'wav+midi' ||
              downloadFormat === 'wav' ||
              downloadFormat === 'wav-tempo-locked'
                ? 'wav'
                : downloadFormat === 'midi'
                  ? 'mp3'
                  : downloadFormat;
            logWebUserEvent({
              actionName: 'EditV3DownloadStem',
              context: {
                editSessionId:
                  editStore.editSessionId || 'MISSING_EDIT_SESSION_ID',
                editingClipId: parentClipId,
                stemId: clip.id,
                format: audioFormat,
              },
            });
            await downloadClipAudio(
              clipsStore.apiClient,
              clip,
              session,
              audioFormat === 'wav' ? 'audio-wav' : 'audio',
              audioFormat === 'wav'
                ? await getOrGenerateWavFileUrl(clipsStore.apiClient, clip.id)
                : undefined
            );
            setDownloading(false);
          }}
        />
      </Tooltip>
    </div>
  );
};

export default observer(function StemsModal({
  clipId: _clipId,
  initialView: _initialView,
  onClose: _onClose,
}: {
  clipId?: string;
  initialView?: StemView;
  onClose?: () => void;
}) {
  const { closeModal, getModalData } = useModalContext();
  const {
    clips: clipsStore,
    edit: editStore,
    session,
    project,
    playbar,
    menus,
  } = useStores();
  const { createAndSaveNewStudioProject } = useStudioProjectManagement(
    null,
    noop
  );

  // Use the provided clipId and initialView, or get them from the modal data
  const modalData = getModalData(ModalTypes.STEMS);
  const clipId = _clipId || modalData?.clipId || '';
  const initialView = _initialView || modalData?.initialView || 'initial';
  const onClose =
    _onClose ||
    (() => {
      closeModal(ModalTypes.STEMS);
    });

  const { clip } = useClip(clipId);

  const isMidiTranscriptionEnabled = !!isFeatureEnabledForPlan(
    session,
    PlanFeature.Studio
  );

  const parentDownbeats = useDownbeatsQuery(clipId);
  const parentKey = useKeyQuery(isMidiTranscriptionEnabled ? clipId : null);

  // State of each stem type's solo and mute state
  const [stemTypeSettings, setStemTypeSettings] = useState<{
    [key: string]: {
      solo: boolean;
      mute: boolean;
    };
  }>(INITIAL_STEM_TYPE_SETTINGS);

  // State of 12-track stems
  const [twelveTrackStemBanks, setTwelveTrackStemBanks] = useLocalStorage<
    string[][]
  >(`clip-stem-banks-${clip?.id}-may-22-2025-v5`, []);
  // Index of the current 12-track stem bank
  const [twelveTrackBankIndex, setTwelveTrackBankIndex] =
    useLocalStorage<number>(
      `clip-stem-bank-index-${clip?.id}-may-22-2025-v5`,
      0
    );

  // State of vocals + instrumental stems
  const [vocalsInstrumentalStemBanks, setVocalsInstrumentalStemBanks] =
    useLocalStorage<string[][]>(
      `clip-vocals-instrumental-stem-banks-${clip?.id}-may-22-2025-v6`,
      []
    );
  // Index of the current vocals + instrumental stem bank
  const [vocalsInstrumentalBankIndex, setVocalsInstrumentalBankIndex] =
    useLocalStorage<number>(
      `clip-vocals-instrumental-bank-index-${clip?.id}-may-22-2025-v6`,
      0
    );

  const [currentView, setCurrentView] = useState<StemView>(initialView);

  // Clear solo/mute state when switching between stem views (not when going to/from initial)
  useEffect(() => {
    if (
      currentView === 'twelve-track' ||
      currentView === 'vocals-instrumental'
    ) {
      setStemTypeSettings(INITIAL_STEM_TYPE_SETTINGS);
    }
  }, [currentView]);

  // Get current stem bank based on view
  const currentStemBank = useMemo(() => {
    if (currentView === 'twelve-track') {
      return twelveTrackStemBanks[twelveTrackBankIndex] ?? [];
    } else if (currentView === 'vocals-instrumental') {
      return vocalsInstrumentalStemBanks[vocalsInstrumentalBankIndex] ?? [];
    }
    return [];
  }, [
    currentView,
    twelveTrackStemBanks,
    twelveTrackBankIndex,
    vocalsInstrumentalStemBanks,
    vocalsInstrumentalBankIndex,
  ]);

  // Preload all clips for the current view type to reduce loading times when switching between banks
  const allCurrentViewClipIds = useMemo(() => {
    if (currentView === 'twelve-track') {
      return twelveTrackStemBanks.flat();
    } else if (currentView === 'vocals-instrumental') {
      return vocalsInstrumentalStemBanks.flat();
    }
    return [];
  }, [currentView, twelveTrackStemBanks, vocalsInstrumentalStemBanks]);

  // Get all clips for current view type (preloaded)
  const { clips: allClipsById } = useClips(allCurrentViewClipIds);

  // Filter preloaded clips to current bank
  const clipsById = useMemo(() => {
    const filteredClips: { [key: string]: Clip } = {};
    currentStemBank.forEach((clipId) => {
      if (allClipsById[clipId]) {
        filteredClips[clipId] = allClipsById[clipId];
      }
    });
    return filteredClips;
  }, [currentStemBank, allClipsById]);

  // Prefetch audio buffers for all clips in current view type to enable instant playback
  useEffect(() => {
    if (allCurrentViewClipIds.length === 0) return;

    // Prefetch audio buffers for all clips in the current view
    // This runs in the background and populates the audio cache
    const prefetchAudioBuffers = async () => {
      // Filter to only completed clips
      const completedClipIds = allCurrentViewClipIds.filter((clipId) => {
        const clip = allClipsById[clipId];
        return clip?.status === 'complete';
      });

      if (completedClipIds.length === 0) return;

      // Use Promise.allSettled to continue even if some clips fail to load
      await Promise.allSettled(
        completedClipIds.map(async (clipId) => {
          try {
            await getPojoBuffer(clipId, 'mp3');
          } catch (error) {
            console.warn(
              `Failed to prefetch audio buffer for clip ${clipId}:`,
              error
            );
          }
        })
      );
    };

    prefetchAudioBuffers();
  }, [allCurrentViewClipIds, allClipsById]);

  //Get current stem bank clips with solo and mute state
  const currentResolvedStemBank = useMemo(() => {
    return currentStemBank
      .map((clipId) => {
        const clip = clipsById[clipId];
        if (!clip || clip.status !== 'complete') return null;
        const settings = clip.metadata.stem_type_group_name
          ? stemTypeSettings[clip.metadata.stem_type_group_name]
          : {
              solo: false,
              mute: false,
            };
        return {
          clip,
          ...settings,
        };
      })
      .filter(Boolean) as {
      clip: Clip;
      solo: boolean;
      mute: boolean;
    }[];
  }, [currentStemBank, stemTypeSettings, clipsById]);

  const currentNonEmptyStemBank = useMemo(() => {
    return currentResolvedStemBank.filter(
      ({ clip }) => !clip.metadata.is_loudness_under_threshold
    );
  }, [currentResolvedStemBank]);

  // Track which stems have MIDI generation in progress or completed
  const [midiGenerationStates, setMidiGenerationStates] = useState<
    Record<string, 'idle' | 'loading' | 'complete' | 'error'>
  >({});
  const [midiTranscriptCache, setMidiTranscriptCache] = useState<
    Record<string, MidiInstrumentSchema[]>
  >({});

  // Function to generate MIDI for a specific clip
  const generateMidiForClip = useCallback(
    async (clipId: string): Promise<MidiInstrumentSchema[] | null> => {
      if (midiGenerationStates[clipId] === 'complete') {
        return midiTranscriptCache[clipId] || null;
      }

      setMidiGenerationStates((prev) => ({ ...prev, [clipId]: 'loading' }));
      try {
        const transcript = await getMidiForClip(clipsStore.apiClient, clipId);
        setMidiTranscriptCache((prev) => ({ ...prev, [clipId]: transcript }));
        setMidiGenerationStates((prev) => ({ ...prev, [clipId]: 'complete' }));
        return transcript;
      } catch (error) {
        console.error('Failed to generate MIDI:', error);
        setMidiGenerationStates((prev) => ({ ...prev, [clipId]: 'error' }));
        return null;
      }
    },
    [midiGenerationStates, midiTranscriptCache, clipsStore.apiClient]
  );

  const midiStates = useMemo(() => {
    return currentNonEmptyStemBank.reduce<Record<string, MidiState>>(
      (acc, { clip }) => {
        if (!isMidiTranscriptionEnabled || currentView !== 'twelve-track') {
          return { ...acc, [clip.id]: { type: 'disabled' } };
        }

        const generationState = midiGenerationStates[clip.id] || 'idle';

        if (
          generationState === 'loading' ||
          parentDownbeats.isLoading ||
          parentKey.isLoading
        ) {
          return { ...acc, [clip.id]: { type: 'loading' } };
        }

        if (
          generationState === 'complete' &&
          midiTranscriptCache[clip.id] &&
          parentDownbeats.data
        ) {
          const transcript = midiTranscriptCache[clip.id];
          return {
            ...acc,
            [clip.id]: {
              type: 'available',
              transcript,
              blob: jsonToMidi(
                clip.title || null,
                transcript,
                parentDownbeats.data!,
                parentKey.data || null,
                clip.metadata.stem_type_group_name || null
              )!,
            },
          };
        }

        return { ...acc, [clip.id]: { type: 'unavailable' } };
      },
      {}
    );
  }, [
    currentView,
    currentNonEmptyStemBank,
    midiGenerationStates,
    midiTranscriptCache,
    parentDownbeats.data,
    parentKey.data,
    parentDownbeats.isLoading,
    parentKey.isLoading,
    isMidiTranscriptionEnabled,
  ]);

  // Ensure all stem types in current bank have entries in stemTypeSettings
  useEffect(() => {
    const missingStems: { [key: string]: { solo: boolean; mute: boolean } } =
      {};
    let hasMissing = false;

    currentResolvedStemBank.forEach(({ clip }) => {
      const stemType = clip.metadata.stem_type_group_name;
      if (stemType && !stemTypeSettings[stemType]) {
        missingStems[stemType] = { solo: false, mute: false };
        hasMissing = true;
      }
    });

    if (hasMissing) {
      setStemTypeSettings((prev) => ({ ...prev, ...missingStems }));
    }
  }, [currentResolvedStemBank, stemTypeSettings]);

  // Build EditorPlaybackState
  const editorPlaybackState = useMemo<EditorPlaybackState>(() => {
    const tracks: EditorPlaybackTrack[] = [];

    // Check if any track that exists in the current bank is soloed
    const anyCurrentBankTrackSolo =
      stemTypeSettings.FULL_SONG?.solo ||
      currentResolvedStemBank.some(({ solo }) => solo);

    // Always include the full song track if clip exists
    if (clip) {
      const fullSongSettings = stemTypeSettings.FULL_SONG || {
        solo: false,
        mute: false,
      };
      // Auto-mute full song when stems exist, unless soloed
      const autoMute = currentStemBank.length > 0 && !fullSongSettings.solo;
      const effectiveAmplitude = autoMute || fullSongSettings.mute ? 0 : 1;

      const arrangedClip: ArrangedClip = {
        id: `full-song-arrangement-${clip.id}`,
        clipId: clip.id,
        title: clip.title || 'Full Song',
        contentSeconds: clip.metadata.duration || 0,
        startSeconds: 0,
        endSeconds: clip.metadata.duration || 0,
        readStartSeconds: 0,
      };

      tracks.push({
        id: `full-song-${clip.id}`,
        amplitude: effectiveAmplitude,
        balance: 0,
        clips: [arrangedClip],
      });
    }

    // Add stem tracks if they exist
    if (currentResolvedStemBank) {
      currentResolvedStemBank
        .filter(({ clip }) => clip?.status === 'complete')
        .forEach(({ clip, mute, solo }) => {
          // Calculate effective amplitude - only consider tracks that exist in current bank for solo logic
          let effectiveAmplitude = 1;
          if (mute) {
            effectiveAmplitude = 0;
          } else if (anyCurrentBankTrackSolo && !solo) {
            effectiveAmplitude = 0;
          }

          const arrangedClip: ArrangedClip = {
            id: `stem-arrangement-${clip.id}`,
            clipId: clip.id,
            title: clip.title || 'Stem',
            contentSeconds: clip.metadata.duration || 0,
            startSeconds: 0,
            endSeconds: clip.metadata.duration || 0,
            readStartSeconds: 0,
          };

          tracks.push({
            id: clip.id,
            amplitude: effectiveAmplitude,
            balance: 0,
            clips: [arrangedClip],
          });
        });
    }

    const songEndSeconds = Math.max(
      ...tracks.flatMap((t) => t.clips.map((c) => c.endSeconds)),
      0
    );

    // Create a simple timing object - assuming 2 BPS (120 BPM)
    const timing: EditTiming = {
      bps: 2,
      bpsAutomation: [],
      firstBeatSeconds: 0,
    };

    return {
      tracks,
      skipTimeStart: 0,
      skipTimeEnd: 0,
      amplitudeAutomation: [
        {
          beats: 0,
          value: 1,
          curve: 0,
        },
      ],
      songEndSeconds,
      playbackEndSeconds: songEndSeconds,
      timing,
    };
  }, [currentResolvedStemBank, clip, stemTypeSettings, currentStemBank]);

  const [playbackQueued, setPlaybackQueued] = useState(false);

  const {
    playing,
    play: editorPlay,
    stop: editorStop,
    getCurrentTime,
    seek,
    setTrackAmplitude,
  } = useEditorStatePlayer(editorPlaybackState);

  const loading = playbackQueued && !playing;

  const play = useCallback(() => {
    // Stop the main playbar if it's currently playing
    if (playbar.isPlaying) {
      playbar.togglePlay(false);
    }

    editorPlay();
    setPlaybackQueued(true);
  }, [editorPlay, playbar]);

  const stop = useCallback(() => {
    editorStop();
    setPlaybackQueued(false);
  }, [editorStop]);

  useEffect(() => {
    if (playing) {
      setPlaybackQueued(false);
    }
  }, [playing]);

  // Handle restarting playback when switching banks
  const [shouldRestartPlayback, setShouldRestartPlayback] = useState(false);

  // Track completed clips count to restart playback when new clips complete
  const completedClipsCount = useMemo(() => {
    return currentResolvedStemBank.filter(
      ({ clip }) => clip?.status === 'complete'
    ).length;
  }, [currentResolvedStemBank]);

  const [prevCompletedClipsCount, setPrevCompletedClipsCount] =
    useState(completedClipsCount);

  useEffect(() => {
    if (shouldRestartPlayback) {
      // Check if we have stems to play
      const completedStemsCount = currentResolvedStemBank.filter(
        ({ clip }) => clip?.status === 'complete'
      ).length;
      if (completedStemsCount > 0) {
        play();
      }
      setShouldRestartPlayback(false);
    }
  }, [shouldRestartPlayback, currentResolvedStemBank, play]);

  // Restart playback when new clips complete during playback
  useEffect(() => {
    if (
      playing &&
      completedClipsCount > prevCompletedClipsCount &&
      prevCompletedClipsCount > 0 // Only restart if we already had some completed clips
    ) {
      // New clips have completed during playback, restart to include them
      stop();
      setShouldRestartPlayback(true);
    }
    setPrevCompletedClipsCount(completedClipsCount);
  }, [completedClipsCount, prevCompletedClipsCount, playing, stop]);

  // Real-time updates for solo/mute changes during playback
  useEffect(() => {
    if (!clip) return;

    // Update full song track amplitude
    const fullSongSettings = stemTypeSettings.FULL_SONG || {
      solo: false,
      mute: false,
    };
    const autoMute = currentStemBank.length > 0 && !fullSongSettings.solo;
    const effectiveAmplitude = autoMute || fullSongSettings.mute ? 0 : 1;

    setTrackAmplitude(`full-song-${clip.id}`, effectiveAmplitude);
  }, [
    stemTypeSettings.FULL_SONG,
    currentStemBank.length,
    clip,
    setTrackAmplitude,
  ]);

  useEffect(() => {
    // Update stem track amplitudes
    // Check if any track is soloed - calculate directly from stemTypeSettings to avoid timing issues
    const anyStemSoloed = currentResolvedStemBank.some(({ clip }) => {
      const stemType = clip.metadata.stem_type_group_name;
      return stemType && stemTypeSettings[stemType]?.solo;
    });
    const anyCurrentBankTrackSolo =
      stemTypeSettings.FULL_SONG?.solo || anyStemSoloed;

    currentResolvedStemBank.forEach(({ clip, mute }) => {
      const stemType = clip.metadata.stem_type_group_name;
      const solo = stemType ? stemTypeSettings[stemType]?.solo : false;

      // Calculate effective amplitude - only consider tracks that exist in current bank for solo logic
      let effectiveAmplitude = 1;
      if (mute) {
        effectiveAmplitude = 0;
      } else if (anyCurrentBankTrackSolo && !solo) {
        effectiveAmplitude = 0;
      }

      setTrackAmplitude(clip.id, effectiveAmplitude);
    });
  }, [currentResolvedStemBank, stemTypeSettings, setTrackAmplitude]);

  const generate = useGenerate();

  const [generatingTwelveTrack, setGeneratingTwelveTrack] = useState(false);
  const [generatingVocalsInstrumental, setGeneratingVocalsInstrumental] =
    useState(false);

  // Consolidated extraction logic
  const handleExtractStems = useCallback(
    async (
      stemTypeGroup: 'Twelve' | 'Two',
      stemTask: 'twelve' | 'two',
      chunkSize: number,
      setBanks: React.Dispatch<React.SetStateAction<string[][]>>,
      viewType: StemView,
      setGeneratingState: React.Dispatch<React.SetStateAction<boolean>>
    ) => {
      setGeneratingState(true);
      try {
        const result = await generate(createTransactionLogger(), {
          prompt: {
            title: clip?.title,
            type: PromptType.Custom,
          },
          modelTier: ModelTier.V4_5,
          references: [
            {
              type: ReferenceType.GenStem,
              clipId: clipId,
              stemType: StemTypeId.FX,
              stemTypeGroup,
              stemTask,
            },
          ],
          projectId: project.currentProjectId,
        });

        if (result) {
          // Split the data into banks of specified size
          const banks: string[][] = [];
          for (let i = 0; i < result.length; i += chunkSize) {
            const bank = result
              .slice(i, i + chunkSize)
              .map((clip: Clip) => clip.id);
            banks.push(bank);
          }
          setBanks((prev) => [...prev, ...banks]);
          setCurrentView(viewType);
        }
      } finally {
        setGeneratingState(false);
      }
    },
    [clipId, clip?.title, generate, setCurrentView, project.currentProjectId]
  );

  const handleExtractTwelveTrackStems = useCallback(async () => {
    await handleExtractStems(
      'Twelve',
      'twelve',
      12,
      setTwelveTrackStemBanks,
      'twelve-track',
      setGeneratingTwelveTrack
    );
  }, [handleExtractStems, setTwelveTrackStemBanks]);

  const handleExtractVocalsInstrumental = useCallback(async () => {
    await handleExtractStems(
      'Two',
      'two',
      2,
      setVocalsInstrumentalStemBanks,
      'vocals-instrumental',
      setGeneratingVocalsInstrumental
    );
  }, [handleExtractStems, setVocalsInstrumentalStemBanks]);

  const [hasInitialized, setHasInitialized] = useState(false);

  useEffect(() => {
    if (clipId && !hasInitialized) {
      setHasInitialized(true);
    }
  }, [clipId, hasInitialized]);

  // Add spacebar play/pause functionality
  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === ' ' || event.code === 'Space') {
        event.preventDefault();
        event.stopPropagation();
        event.stopImmediatePropagation();

        // Determine if we can play based on current mode
        const isFullSongSoloed = stemTypeSettings.FULL_SONG?.solo || false;
        const canPlay = isFullSongSoloed
          ? !!clip // If full song is soloed, we need a clip
          : currentResolvedStemBank.length > 0 || // If stems mode, we need stems
            (!!clip && currentView === 'initial'); // If initial view, we need a clip (basically, solo don't matter)

        if (canPlay) {
          if (playing) stop();
          else play();
        }
      }
    };

    document.addEventListener('keydown', handleKeyDown, true);
    return () => {
      document.removeEventListener('keydown', handleKeyDown, true);
    };
  }, [
    playing,
    stop,
    play,
    currentResolvedStemBank.length,
    clip,
    stemTypeSettings.FULL_SONG?.solo,
    currentView,
  ]);

  const [downloadFormat, setDownloadFormat] = useLocalStorage<
    'mp3' | 'wav' | 'midi' | 'wav+midi' | 'wav-tempo-locked'
  >(`stem-download-format-june-2-2025`, 'mp3');
  const [downloadingZip, setDownloadingZip] = useState(false);
  const [waitingToDownloadZip, setWaitingToDownloadZip] = useState(false);
  const [downloadZipBeforeComplete, setDownloadZipBeforeComplete] =
    useState(false);

  const allClipsFinal =
    currentStemBank.length > 0 &&
    currentStemBank.every(
      (clipId) =>
        !clipsById[clipId] ||
        !['queued', 'submitted', 'streaming'].includes(
          clipsById[clipId].status || ''
        )
    );

  const canDownloadZip =
    downloadFormat === 'midi' || downloadFormat === 'wav+midi'
      ? allClipsFinal
      : allClipsFinal;

  // Effect to trigger download when waiting and all conditions are met
  useEffect(() => {
    if (waitingToDownloadZip && (canDownloadZip || downloadZipBeforeComplete)) {
      setWaitingToDownloadZip(false);
      setDownloadingZip(true);
      setDownloadZipBeforeComplete(false);

      // Start the download
      (async () => {
        try {
          // For MIDI or WAV+MIDI downloads, generate all MIDIs first
          let midiFiles: {
            clipId: string;
            midiBlob: Blob;
            fileName: string;
          }[] = [];

          if (downloadFormat === 'midi' || downloadFormat === 'wav+midi') {
            // Generate MIDI for all stems that don't have it yet
            const midiPromises = currentNonEmptyStemBank.map(
              async ({ clip }) => {
                try {
                  // Check if we already have the MIDI
                  const existingState = midiStates[clip.id];
                  if (existingState?.type === 'available') {
                    return {
                      clipId: clip.id,
                      midiBlob: existingState.blob,
                      fileName: clip.title || 'stem',
                    };
                  }

                  // Generate MIDI on-demand
                  const transcript = await generateMidiForClip(clip.id);
                  if (
                    !transcript ||
                    transcript.length === 0 ||
                    !parentDownbeats.data
                  ) {
                    return null;
                  }

                  // Convert to MIDI blob
                  const midiBlob = jsonToMidi(
                    clip.title || null,
                    transcript,
                    parentDownbeats.data,
                    parentKey.data || null,
                    clip.metadata.stem_type_group_name || null
                  );

                  if (!midiBlob) {
                    return null;
                  }

                  return {
                    clipId: clip.id,
                    midiBlob,
                    fileName: clip.title || 'stem',
                  };
                } catch (error) {
                  console.error(
                    `Failed to generate MIDI for clip ${clip.id}:`,
                    error
                  );
                  return null;
                }
              }
            );

            const midiResults = await Promise.all(midiPromises);
            midiFiles = midiResults.filter((x) => x !== null) as {
              clipId: string;
              midiBlob: Blob;
              fileName: string;
            }[];
          }

          if (downloadFormat === 'midi') {
            // MIDI-only download
            await downloadAsZip(
              clipsStore.apiClient,
              [],
              clip?.title ? `${clip?.title} MIDI` : 'MIDI',
              'mp3', // Format doesn't matter for MIDI-only downloads
              midiFiles
            );
          } else if (downloadFormat === 'wav+midi') {
            // WAV+MIDI download - use legacy zip download with both audio and MIDI
            await downloadAsZip(
              clipsStore.apiClient,
              currentNonEmptyStemBank.map(({ clip }) => clipsById[clip.id]),
              clip?.title ? `${clip?.title} Stems` : 'Stems',
              'wav',
              midiFiles
            );
          } else {
            // Determine whether to pass downbeats and use tempo-locked mode
            const useTempoLocked = downloadFormat === 'wav-tempo-locked';

            await downloadStemsAsZip({
              apiClient: clipsStore.apiClient,
              rootClipName: `${getClipTitle(clip) || 'Untitled Clip'} Stems`,
              clips: currentNonEmptyStemBank.map(({ clip }) => clip),
              durationSeconds: clip?.metadata.duration || 8 * 60,
              downbeats: parentDownbeats.data,
              format: (downloadFormat === 'wav-tempo-locked'
                ? 'wav'
                : downloadFormat) as 'mp3' | 'wav',
              useTempoLocked,
            });
          }
        } finally {
          setDownloadingZip(false);
        }
      })();
    }
  }, [
    waitingToDownloadZip,
    canDownloadZip,
    currentNonEmptyStemBank,
    midiStates,
    clipsById,
    downloadFormat,
    downloadZipBeforeComplete,
    clip,
    generateMidiForClip,
    parentDownbeats.data,
    parentKey.data,
    clipsStore.apiClient,
  ]);

  // Helper functions for full song state management
  const fullSongSettings = stemTypeSettings.FULL_SONG || {
    solo: false,
    mute: false,
  };

  const setFullSongSolo = (solo: boolean, nonDestructive = false) => {
    setStemTypeSettings((prev) => {
      const updatedSettings = { ...prev };

      Object.keys(updatedSettings).forEach((key) => {
        if (key === 'FULL_SONG') {
          // Set full song solo state directly
          updatedSettings[key] = { ...updatedSettings[key], solo };
        } else {
          // Handle stem tracks
          let newSoloState: boolean;
          if (solo) {
            // When full song is being soloed, always unsolo all stems
            newSoloState = false;
          } else if (nonDestructive) {
            // Keep current solo state unchanged
            newSoloState = updatedSettings[key].solo;
          } else {
            // Destructive mode: unsolo this stem
            newSoloState = false;
          }

          updatedSettings[key] = {
            ...updatedSettings[key],
            solo: newSoloState,
          };
        }
      });

      return updatedSettings;
    });
  };

  const [creatingStudioProject, setCreatingStudioProject] = useState(false);

  // Check if stems exist for each type
  const hasTwelveTrackStems = twelveTrackStemBanks.length > 0;
  const hasVocalsInstrumentalStems = vocalsInstrumentalStemBanks.length > 0;

  // Permission check
  const hasStemsAccess = !!isFeatureEnabledForPlan(
    session,
    PlanFeature.GetStems
  );
  const hasStudio = session.flags && Boolean(session.flags['studio']);

  const fullSongPlaying = playing && fullSongSettings.solo;
  const stemsPlaying = playing && !fullSongSettings.solo;

  const { streamDownbeatsForClip } = useStreamingDownbeats();

  // Don't render modal if we don't have a clipId
  if (!clipId) {
    return null;
  }

  return (
    <Modal
      onClose={() => {
        onClose();
        logWebUserEvent({
          actionName: 'EditV3StemsModalClosed',
          context: {
            clipId,
          },
        });
      }}
      width={800}
      wrapperClasses='min-h-[400px] max-h-[90vh] flex flex-col'
      closeButtonClasses='right-1.5'
    >
      <div className='flex h-full min-h-0 flex-col gap-2.5'>
        <div className='flex items-center gap-2 px-2'>
          {currentView !== 'initial' && (
            <Button
              variant={ButtonVariant.Tertiary}
              size={ButtonSize.Medium}
              icon={<ArrowLeftIcon />}
              onClick={() => setCurrentView('initial')}
            />
          )}
          <div className='text-2xl font-medium'>Extract Stems</div>
        </div>

        {!hasInitialized && (
          <div className='flex flex-col items-center justify-center gap-2'>
            <SpinnerSVG />
          </div>
        )}

        {/* Always show full song card */}
        {hasInitialized && clip && (
          <div className='rounded-xl bg-white/5 p-2.5'>
            <div className='mb-4 flex flex-row items-center gap-3'>
              <div className='h-20 w-14 shrink-0 overflow-hidden rounded-lg'>
                <ImageWithFallback
                  imageSize={SMALL_IMAGE}
                  className='h-full w-full object-cover'
                  src={
                    clip.image_url || 'https://cdn-o.suno.com/auras/Aura-13.jpg'
                  }
                  alt={`Album art for ${getClipTitle(clip) || 'Untitled'}`}
                />
              </div>
              <div className='min-w-0 flex-1'>
                <div className='mb-1 overflow-hidden text-lg font-medium text-ellipsis whitespace-nowrap'>
                  <Link
                    href={`/song/${clip.id}`}
                    title={getClipTitle(clip) || 'Untitled'}
                    className='hover:underline'
                  >
                    {getClipTitle(clip) || 'Untitled'}
                  </Link>
                </div>
                <div className='text-sm text-gray-400'>
                  <MusicStyleTags
                    className='line-clamp-1 text-sm text-foreground-secondary'
                    tags={tagsToArray(clip.metadata?.tags || '')}
                    title={clip.metadata?.tags || NO_STYLE_FALLBACK}
                  />
                </div>
              </div>
            </div>

            {/* Full Song Track inside the same card */}
            <FullSongTrack
              clip={clip}
              solo={fullSongSettings.solo}
              effectivelyMuted={
                currentStemBank.length > 0 && !fullSongSettings.solo
              }
              loading={fullSongSettings.solo && playbackQueued && !playing}
              setSolo={setFullSongSolo}
              getCurrentSeconds={getCurrentTime}
              seek={seek}
              playing={currentView === 'initial' ? playing : fullSongPlaying}
              setPlaying={(newIsPlaying: boolean) => {
                if (newIsPlaying) {
                  if (currentView !== 'initial') setFullSongSolo(true);
                  play();
                } else {
                  stop();
                }
              }}
            />
          </div>
        )}

        {/* Initial view with extraction options */}
        {currentView === 'initial' && hasInitialized && (
          <div className='flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto'>
            {/* Extraction Options - full width */}
            <div className='flex flex-row gap-4'>
              <div className='flex flex-1 flex-col items-center justify-center gap-4 rounded-xl bg-white/5 p-6 px-15'>
                <div className='flex h-12 w-12 items-center justify-center'>
                  <SlidersIcon className='h-8 w-8' />
                </div>
                <div className='flex flex-col items-center gap-2'>
                  <div className='text-center text-xl font-medium'>
                    All Detected Stems
                  </div>
                  <div className='text-center text-sm text-gray-400'>
                    Get up to 12 separated
                    {isMidiTranscriptionEnabled
                      ? ' instruments, vocal, and MIDI tracks'
                      : ' instrument and vocals stems'}
                    .
                  </div>
                </div>
                <div className='flex w-full flex-col items-center gap-3'>
                  <Tooltip
                    label={
                      !hasStemsAccess ? 'Subscribe to extract!' : undefined
                    }
                    placement='top'
                  >
                    <div className='flex w-full justify-center'>
                      <Button
                        disabled={
                          !hasStemsAccess ||
                          generatingTwelveTrack ||
                          generatingVocalsInstrumental
                        }
                        size={ButtonSize.Medium}
                        variant={ButtonVariant.Aura}
                        shape={ButtonShape.Pill}
                        icon={
                          generatingTwelveTrack ? <SpinnerSVG /> : undefined
                        }
                        onClick={() => {
                          if (hasStemsAccess) {
                            handleExtractTwelveTrackStems();
                          }
                          logWebUserEvent({
                            actionName: 'EditV3ExtractAllDetectedStemsClicked',
                            context: {
                              clipId,
                            },
                          });
                        }}
                        className='px-4'
                      >
                        {hasTwelveTrackStems
                          ? 'Extract Again (50 Credits)'
                          : 'Extract (50 Credits)'}
                      </Button>
                    </div>
                  </Tooltip>
                  {hasTwelveTrackStems && hasStemsAccess && (
                    <div className='flex w-full justify-center'>
                      <Button
                        size={ButtonSize.Medium}
                        variant={ButtonVariant.Tertiary}
                        shape={ButtonShape.Pill}
                        onClick={() => {
                          setCurrentView('twelve-track');
                          logWebUserEvent({
                            actionName: 'EditV3SeeExtractedStemsClicked',
                            context: {
                              clipId,
                              mode: 'twelve-track',
                            },
                          });
                        }}
                        className='px-4'
                      >
                        See Extracted Stems
                      </Button>
                    </div>
                  )}
                </div>
              </div>

              <div className='flex flex-1 flex-col items-center justify-center gap-4 rounded-xl bg-white/5 p-6 px-15'>
                <div className='flex h-12 w-12 items-center justify-center'>
                  <InstrumentLeadVocalsIcon className='h-8 w-8' />
                </div>
                <div className='flex flex-col items-center gap-2'>
                  <div className='text-center text-xl font-medium'>
                    Vocals + Instrumental
                  </div>
                  <div className='text-center text-sm text-gray-400'>
                    Get an isolated vocal track and an instrumental track.
                  </div>
                </div>
                <div className='flex w-full flex-col items-center gap-3'>
                  <Tooltip
                    label={
                      !hasStemsAccess ? 'Subscribe to extract!' : undefined
                    }
                    placement='top'
                  >
                    <div className='flex w-full justify-center'>
                      <Button
                        disabled={
                          !hasStemsAccess ||
                          generatingTwelveTrack ||
                          generatingVocalsInstrumental
                        }
                        size={ButtonSize.Medium}
                        variant={ButtonVariant.Aura}
                        shape={ButtonShape.Pill}
                        icon={
                          generatingVocalsInstrumental ? (
                            <SpinnerSVG />
                          ) : undefined
                        }
                        onClick={() => {
                          if (hasStemsAccess) {
                            handleExtractVocalsInstrumental();
                          }

                          logWebUserEvent({
                            actionName:
                              'EditV3ExtractVocalsInstrumentalClicked',
                            context: {
                              clipId,
                            },
                          });
                        }}
                        className='px-4'
                      >
                        {hasVocalsInstrumentalStems
                          ? 'Extract Again (10 Credits)'
                          : 'Extract (10 Credits)'}
                      </Button>
                    </div>
                  </Tooltip>
                  {hasVocalsInstrumentalStems && hasStemsAccess && (
                    <div className='flex w-full justify-center'>
                      <Button
                        size={ButtonSize.Medium}
                        variant={ButtonVariant.Tertiary}
                        shape={ButtonShape.Pill}
                        onClick={() => {
                          setCurrentView('vocals-instrumental');
                          logWebUserEvent({
                            actionName: 'EditV3SeeExtractedStemsClicked',
                            context: {
                              clipId,
                              mode: 'vocals-instrumental',
                            },
                          });
                        }}
                        className='px-4'
                      >
                        See Extracted Stems
                      </Button>
                    </div>
                  )}
                </div>
              </div>
            </div>

            {/* Upsell box - only show when user doesn't have access */}
            {!hasStemsAccess && (
              <div className='flex items-center justify-center gap-4 rounded-xl bg-white/5 px-6 py-5'>
                <div className='text-lg text-white'>
                  Subscribe to extract Stems
                </div>
                <Button
                  href='/account'
                  variant={ButtonVariant.Primary}
                  shape={ButtonShape.Pill}
                >
                  Subscribe
                </Button>
              </div>
            )}

            {/* Bottom Text - no background */}
            {window.location.pathname.includes('/edit/') && (
              <div className='px-2 py-1'>
                <div className='space-y-1 text-center'>
                  <div className='text-sm text-foreground-secondary'>
                    Stems will be extracted from the original song. If
                    you&apos;ve made any edits, save it as a new song first.
                  </div>
                </div>
              </div>
            )}
          </div>
        )}

        {/* Stems view (both 12-track and vocals+instrumental) */}
        {(currentView === 'twelve-track' ||
          currentView === 'vocals-instrumental') &&
          hasInitialized && (
            <div className='grid min-h-0 flex-1 grid-rows-[40px_auto_1fr] gap-2.5 overflow-auto rounded-[10px] bg-white/5 py-2.5'>
              <div className='flex justify-between px-2.5'>
                <div className='flex items-center gap-1'>
                  <Button
                    disabled={
                      !currentResolvedStemBank.filter(
                        ({ clip }) => clip?.status === 'complete'
                      ).length
                    }
                    size={ButtonSize.Medium}
                    variant={ButtonVariant.Tertiary}
                    shape={ButtonShape.Pill}
                    icon={
                      loading ? (
                        <SpinnerSVG />
                      ) : stemsPlaying ? (
                        <PauseIcon />
                      ) : (
                        <PlayIcon />
                      )
                    }
                    onClick={() => {
                      if (stemsPlaying) {
                        stop();
                      } else {
                        if (fullSongSettings.solo) setFullSongSolo(false);
                        play();
                      }
                    }}
                  />
                  {currentResolvedStemBank.length === 0 && (
                    <SpinnerSVG className='h-4 w-4' />
                  )}
                  Detected Stems
                </div>
                <div className='flex items-center gap-1'>
                  <Tooltip
                    label={
                      currentView === 'twelve-track'
                        ? '50 Credits'
                        : '10 Credits'
                    }
                  >
                    <Button
                      disabled={
                        generatingTwelveTrack || generatingVocalsInstrumental
                      }
                      shape={ButtonShape.Pill}
                      variant={ButtonVariant.Tertiary}
                      icon={
                        (currentView === 'twelve-track' &&
                          generatingTwelveTrack) ||
                        (currentView === 'vocals-instrumental' &&
                          generatingVocalsInstrumental) ? (
                          <SpinnerSVG />
                        ) : (
                          <StemsIcon />
                        )
                      }
                      onClick={() => {
                        if (currentView === 'twelve-track') {
                          handleExtractTwelveTrackStems();
                        } else {
                          handleExtractVocalsInstrumental();
                        }
                        logWebUserEvent({
                          actionName: 'EditV3RegenerateStemsClicked',
                          context: {
                            clipId,
                            mode: currentView,
                          },
                        });
                      }}
                    >
                      Regenerate
                    </Button>
                  </Tooltip>

                  <Tooltip
                    label={
                      downloadingZip
                        ? downloadFormat === 'wav' ||
                          downloadFormat === 'wav-tempo-locked'
                          ? 'Preparing .WAV Zip (this may take some time)'
                          : downloadFormat === 'midi'
                            ? 'Generating MIDI and preparing Zip...'
                            : downloadFormat === 'wav+midi'
                              ? 'Generating MIDI and preparing .WAV+MIDI Zip (this may take some time)'
                              : 'Preparing .MP3 Zip'
                        : waitingToDownloadZip
                          ? downloadZipBeforeComplete
                            ? 'Preparing...'
                            : 'Waiting for stems to complete (click again to download anyway)'
                          : ''
                    }
                  >
                    <Button
                      variant={ButtonVariant.Tertiary}
                      shape={ButtonShape.Pill}
                      disabled={downloadingZip || downloadZipBeforeComplete}
                      icon={
                        downloadingZip || waitingToDownloadZip ? (
                          <SpinnerSVG />
                        ) : (
                          <DownloadIcon />
                        )
                      }
                      onClick={async () => {
                        logWebUserEvent({
                          actionName: 'EditV3DownloadStemZip',
                          context: {
                            editSessionId:
                              editStore.editSessionId ||
                              'MISSING_EDIT_SESSION_ID',
                            editingClipId: clipId,
                            stemIds: currentResolvedStemBank.map(
                              ({ clip }) => clip.id
                            ),
                            format: downloadFormat,
                          },
                        });
                        if (waitingToDownloadZip) {
                          setDownloadZipBeforeComplete(true);
                        } else {
                          setWaitingToDownloadZip(true);
                        }
                      }}
                    >
                      {downloadingZip
                        ? 'Preparing (may take awhile)'
                        : waitingToDownloadZip
                          ? 'Waiting for completion...'
                          : 'Download All'}
                    </Button>
                  </Tooltip>

                  <SelectorV2
                    value={downloadFormat}
                    onSetValue={(newFormat) =>
                      setDownloadFormat(
                        newFormat as
                          | 'mp3'
                          | 'wav'
                          | 'midi'
                          | 'wav+midi'
                          | 'wav-tempo-locked'
                      )
                    }
                    options={getDownloadFormatOptions(
                      isMidiTranscriptionEnabled &&
                        currentView === 'twelve-track'
                    )}
                    className='bg-white/5'
                    menuClassName='z-100001'
                  />
                </div>
              </div>
              <div className='flex flex-wrap gap-1 px-3'>
                {(currentView === 'twelve-track'
                  ? (twelveTrackStemBanks ?? [])
                  : (vocalsInstrumentalStemBanks ?? [])
                ).map((b, index) => (
                  <Button
                    key={index}
                    size={ButtonSize.Mini}
                    variant={
                      index ===
                      (currentView === 'twelve-track'
                        ? twelveTrackBankIndex
                        : vocalsInstrumentalBankIndex)
                        ? ButtonVariant.Primary
                        : ButtonVariant.Secondary
                    }
                    shape={ButtonShape.Pill}
                    onClick={() => {
                      // Remember if we were playing
                      const wasPlaying = playing;

                      // Pause audio when switching versions so player can update
                      stop();

                      // Switch to the new bank index
                      if (currentView === 'twelve-track') {
                        setTwelveTrackBankIndex(index);
                      } else {
                        setVocalsInstrumentalBankIndex(index);
                      }

                      // If we were playing, trigger restart after tracks load
                      if (wasPlaying) {
                        setShouldRestartPlayback(true);
                      }
                    }}
                  >
                    Version {index + 1}
                  </Button>
                ))}
              </div>
              <div className='flex min-h-0 flex-col gap-1.5 overflow-y-auto px-2.5'>
                {currentResolvedStemBank.length === 0 && (
                  <>
                    {Array.from({
                      length: currentView === 'twelve-track' ? 4 : 2,
                    }).map((_, index) => (
                      <StemTrackSkeleton
                        key={index}
                        stemIndex={index}
                        totalItems={currentView === 'twelve-track' ? 4 : 2}
                        midiEnabled={
                          isMidiTranscriptionEnabled &&
                          currentView === 'twelve-track'
                        }
                      />
                    ))}
                  </>
                )}
                {currentNonEmptyStemBank.map((entry) => {
                  // Check if any track that exists in the current bank is soloed
                  const anyCurrentBankTrackSolo =
                    stemTypeSettings.FULL_SONG?.solo ||
                    currentResolvedStemBank.some(({ solo }) => solo);

                  // Calculate if this track is effectively muted
                  const effectivelyMuted =
                    entry.mute || (anyCurrentBankTrackSolo && !entry.solo);

                  return (
                    <StemTrack
                      parentClipId={clipId}
                      downloadFormat={downloadFormat}
                      seek={seek}
                      playing={playing}
                      getCurrentSeconds={getCurrentTime}
                      key={entry.clip.id}
                      clip={entry.clip}
                      solo={entry.solo}
                      mute={entry.mute}
                      effectivelyMuted={effectivelyMuted}
                      midiState={
                        midiStates[entry.clip.id] || { type: 'disabled' }
                      }
                      onGenerateMidi={generateMidiForClip}
                      parentDownbeats={parentDownbeats.data || undefined}
                      parentKey={parentKey.data || undefined}
                      setSolo={(solo, nonDestructive = false) => {
                        setStemTypeSettings((prev) => {
                          const targetStemType =
                            entry.clip.metadata.stem_type_group_name!;
                          const updated = { ...prev };

                          Object.keys(updated).forEach((key) => {
                            if (key === targetStemType) {
                              // Always set the target stem to the desired solo state
                              updated[key] = { ...updated[key], solo };
                            } else if (
                              key === 'FULL_SONG' &&
                              solo &&
                              nonDestructive
                            ) {
                              // When adding a stem to solo selection (non-destructive), unsolo full song
                              updated[key] = { ...updated[key], solo: false };
                            } else if (!nonDestructive) {
                              // If destructive mode, unsolo all other stems
                              updated[key] = { ...updated[key], solo: false };
                            }
                            // In non-destructive mode, keep other stems' current solo state unchanged
                          });

                          return updated;
                        });
                      }}
                      setMute={(mute) => {
                        setStemTypeSettings((prev) => ({
                          ...prev,
                          [entry.clip.metadata.stem_type_group_name!]: {
                            ...prev[entry.clip.metadata.stem_type_group_name!],
                            mute,
                          },
                        }));
                      }}
                    />
                  );
                })}
              </div>
            </div>
          )}
      </div>
      {(currentView === 'twelve-track' ||
        currentView === 'vocals-instrumental') &&
        hasStudio &&
        hasInitialized && (
          <div className='flex justify-end pt-2'>
            <MagicStudioButton
              disabled={
                !clip ||
                creatingStudioProject ||
                currentResolvedStemBank.length === 0 ||
                currentResolvedStemBank.some(
                  ({ clip }) => clip.status !== 'complete'
                )
              }
              icon={
                creatingStudioProject ? (
                  <SpinnerSVG className='h-6 w-6' />
                ) : (
                  <StudioIcon className='h-6 w-6' />
                )
              }
              onClick={async () => {
                if (!clip) return;
                if (!isFeatureEnabledForPlan(session, PlanFeature.Studio)) {
                  menus.setCurrentUpsellFeature(FeatureKey.STUDIO);
                  menus.openModal(ModalTypes.UPSELL_MODAL);
                  return;
                }
                setCreatingStudioProject(true);
                try {
                  const rootClipDownbeats = await new Promise<
                    [number, number][]
                  >((resolve, reject) => {
                    try {
                      streamDownbeatsForClip(
                        clip.id,
                        ({ downbeats, final }) => {
                          if (final) {
                            resolve(downbeats);
                          }
                        }
                      );
                    } catch (e) {
                      reject(e);
                    }
                  });
                  const stemStudioClips = currentResolvedStemBank
                    .filter(
                      ({ clip }) => !clip.metadata?.is_loudness_under_threshold
                    )
                    .map(({ clip }) => ({
                      ...createKnownTimingStudioClipSync(
                        clip,
                        rootClipDownbeats
                      ),
                      name:
                        clip.metadata.stem_type_group_name?.replace('_', ' ') ??
                        getClipTitle(clip),
                    }));
                  const rootStudioClip = createKnownTimingStudioClipSync(
                    clip,
                    rootClipDownbeats
                  );
                  const state: StudioProjectState = {
                    ...DEFAULT_STATE,
                    title: getClipTitle(clip) || 'Untitled',
                    tracks: [
                      {
                        ...createTrack(),
                        name: getClipTitle(clip) || 'Untitled',
                        clips: [
                          {
                            ...rootStudioClip,
                            startBeats: rootStudioClip.readStartBeats,
                          },
                        ],
                        mute: true,
                      },
                      ...stemStudioClips.map((clip) => ({
                        ...createTrack(),
                        name: clip.name,
                        clips: [
                          {
                            ...clip,
                            startBeats: clip.readStartBeats,
                          },
                        ],
                      })),
                    ],
                  };
                  const firstTrackId = state.tracks[0]?.id;
                  if (!firstTrackId) {
                    throw new Error('No track ID found');
                  }
                  state.timing = getProjectTimingForClip(
                    rootStudioClip,
                    firstTrackId
                  );
                  const id = await createAndSaveNewStudioProject(state);
                  logWebUserEvent({
                    actionName: 'CreatedNewStudioProject',
                    context: {
                      studioProjectId: id,
                      clipIds: getAllUsedClipIds(state),
                      trigger: 'stems_modal_send_to_studio',
                    },
                  });
                  window.location.href = `/studio?initial_project_id=${id}`;
                  logWebUserEvent({
                    actionName: 'NavigatedToStudio',
                    context: {
                      trigger: 'stems_modal',
                    },
                  });
                } catch (e) {
                  console.error(e);
                  toast({
                    title: 'Error creating studio project',
                    description: 'Please try again later.',
                    status: 'error',
                  });
                  setCreatingStudioProject(false);
                }
              }}
            >
              Edit in Studio
            </MagicStudioButton>
          </div>
        )}
    </Modal>
  );
});
