import styled from '@emotion/styled';
import { useGateValue, useStatsigClient } from '@statsig/react-bindings';
import { noop } from 'lodash-es';
import { observer } from 'mobx-react-lite';
import { usePathname, useRouter } from 'next/navigation';
import { useCallback, useMemo } from 'react';
import { twMerge } from 'tailwind-merge';

import { useStores } from '@/app/(root)/AppProviders';
import { OrpheusLogo } from '@/app/(root)/chat/OrpheusLogo';
import { useOrpheusExperimentGroup } from '@/app/(root)/chat/hooks/useOrpheusExperimentGroup';
import { ConditionalTooltip } from '@/app/(root)/create/createV2/ConditionalTooltip';
import CreateFormContext, {
  AddConditionType,
} from '@/app/(root)/create/v2/CreateFormContext';
import { CreateModes } from '@/app/(root)/create/v2/types';
import useClipAction from '@/app/(root)/create/v2/useClipAction';
import { useClipPlaybackContext } from '@/components/clipBrowser/useClipPlayback';
import {
  ModalTypes,
  StemsModalSource,
} from '@/components/modal/constants/ModalTypes';
import { useMenuContext } from '@/components/song/newActions/MenuContext';
import { isSunoShort } from '@/components/song/songUtils';
import Tag, { TagVariant } from '@/components/tag/Tag';
import { toast } from '@/components/toast/Toast';
import { useModalContext } from '@/context/ModalContext';
import { usePlaylistActions } from '@/context/PlaylistActionsContext';
import { useStemUpsell } from '@/hooks/upsells';
import { useBreakpointMd } from '@/hooks/useBreakpoint';
import { useContextSelector } from '@/hooks/useContextSelector';
import usePublishClip from '@/hooks/usePublishClip';
import {
  BugIcon,
  CommentIcon,
  CoverCreateIcon,
  CreateIcon,
  CycleIcon,
  DownRightArrowIcon,
  EditUndoIcon,
  ExtendRightIcon,
  FlagIcon,
  FrownIcon,
  GlobeIcon,
  GlobeSlashIcon,
  HeadphoneIcon,
  HooksIcon,
  InfoIcon,
  LinkIcon,
  LyricsIcon,
  MinusIcon,
  PersonaCreateIcon,
  PinIcon,
  PlusIcon,
  ProhibitionIcon,
  QueueIcon,
  RadioBroadcastIcon,
  RemixIcon,
  ScissorsIcon,
  SectionIcon,
  SendIcon,
  ShareArrowIcon,
  SkullIcon,
  SlidersIcon,
  SpeedIcon,
  StemAddIcon,
  StemsIcon,
  StudioIcon,
  TicketIcon,
  TrashIcon,
  UserGroupIcon,
  VideoIcon,
  VinylIcon,
} from '@/icons';
import { SparklesIcon } from '@/icons';
import { useApiClient } from '@/lib/apiClient';
import logWebUserEvent, { withWebUserEvent } from '@/logging/logWebUserEvent';
import {
  Clip,
  ClipsStore,
  canAddInstrumental,
  canAddVocal,
} from '@/state/clipStore';
import { MenusStore } from '@/state/menusStore';
import { FeatureKey, PlanFeature, SessionStore } from '@/state/sessionStore';
import { isUnpublishableUploadClip, isValidModelVersion } from '@/utils/clip';
import {
  downloadClipAudio,
  downloadClipVideo,
  downloadSamplePack,
  initDownloadClipWav,
  isDownloadDisabled,
  logDownloadToBilling,
} from '@/utils/download';
import { ModalRenderer, processDownloadGating } from '@/utils/downloadGating';
import { isProd } from '@/utils/environment';
import { handlePinOrConfirm } from '@/utils/pinnedClips';
import {
  isFeatureEnabledForPlan,
  isProjectsFeatureEnabled,
  isStaff,
} from '@/utils/session';
import { canUseModel, isWavDownloadAvailable } from '@/utils/utils';

import { Props as ButtonProps, ButtonVariant } from '../button/Button';
import { ContextMenuItem } from '../contextMenu/ContextMenu';
import { useClips } from '../studio/hooks/useClips';
import { useExpandCreatePanel } from '../studio/useStudioLayoutManager';
import Switch from '../switch/Switch';
import ToastWithUndo from '../toast/ToastWithUndo';
import { Tooltip } from '../tooltip/Tooltip';
import { useClipContext, useNullableClipContext } from './ClipContext';
import MultiSelectContext from './MultiSelectContext';
import adjustClipSpeed from './actions/adjustClipSpeed';
import overpaintClip from './actions/overpaintClip';
import reusePrompt from './actions/reusePrompt';
import underpaintClip from './actions/underpaintClip';
import applyPersona from './actions/usePersona';
import { useIsOwnClip } from './clipHelpers';
import { ClipBrowserRegistryContext } from './useClipBrowserRegistry';
import useClipIsComplete from './useClipIsComplete';
import useDeletePermanently from './useDeletePermanently';
import useModalTrigger from './useModalTrigger';
import useShareClip from './useShareClip';
import useTrashActions from './useTrashActions';

// Styled components for legacy modals that still use them
const DownloadModalContent = styled.div`
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1rem;
  text-align: center;
`;

const DownloadModalText = styled.span``;

const DownloadModalBoldText = styled.span`
  font-weight: bold;
`;

const DownloadModalLink = styled.a`
  text-decoration: underline;
`;

const canUsePersona = (props: { clip: Clip; session: SessionStore }) => {
  const { clip, session } = props;
  return (
    clip?.persona &&
    // TODO persona.is_public isn't available on SimplePersonaSchema
    ((clip.persona.is_public && clip.is_public) ||
      clip.user_id === session?.userId)
  );
};

export const isValidClipForPersona = (props: {
  clip: Clip;
  session: SessionStore;
}) => {
  const { clip, session } = props;

  return (
    isValidModelVersion(clip) &&
    (canUsePersona(props) || clip?.user_id === session?.userId)
  );
};

export const openDownloadConfirmModal = async (
  clip: Clip,
  menus: MenusStore,
  session: SessionStore,
  clips: ClipsStore,
  router: ReturnType<typeof useRouter>,
  statsigClient: any,
  apiClient: any,
  confirmFn: () => void
) => {
  const modalRenderer: ModalRenderer = {
    renderRemixModal: (onDownloadAnyway: () => void) => {
      menus.openConfirmationModal({
        title: 'You do not have commercial\nrights to this song',
        renderMessage: () => {
          return (
            <DownloadModalContent>
              <DownloadModalText>
                Creating a Remix of another user&apos;s song does not grant
                commercial rights to that output. Please see our{' '}
                <DownloadModalBoldText>Terms of Service</DownloadModalBoldText>{' '}
                for more information.
              </DownloadModalText>
              <DownloadModalText>
                <DownloadModalLink href='/legal/terms' target='_blank'>
                  Terms of Service
                </DownloadModalLink>
              </DownloadModalText>
            </DownloadModalContent>
          );
        },
        onConfirmFn: () => {},
        onActionFn: () => {
          onDownloadAnyway();
        },
        onCloseFn: () => {},
        confirmButtonText: 'Cancel',
        actionButtonText: 'Download Anyway',
        actionButtonClassName:
          'bg-none before:bg-none bg-accent-brand before:bg-accent-brand text-gray-50',
        icon: RemixIcon,
      });
    },
    renderUpgradeModal: (
      onDownload: () => void,
      onUpgrade: () => void,
      onClose: () => void
    ) => {
      menus.openConfirmationModal({
        title: 'Need commercial rights?',
        renderMessage: () => {
          return (
            <DownloadModalContent>
              <DownloadModalText>
                Only <DownloadModalBoldText>Pro</DownloadModalBoldText> and{' '}
                <DownloadModalBoldText>Premier</DownloadModalBoldText> songs are
                eligible for commercial use.
              </DownloadModalText>
              <DownloadModalText>
                <DownloadModalBoldText>Upgrade now</DownloadModalBoldText> and
                this song will be upgraded too.
              </DownloadModalText>
              <DownloadModalText>
                <DownloadModalLink
                  href='https://help.suno.com/en/categories/550145-rights-ownership'
                  target='_blank'
                >
                  Rights and Ownership FAQs
                </DownloadModalLink>
              </DownloadModalText>
            </DownloadModalContent>
          );
        },
        onConfirmFn: onDownload,
        onActionFn: onUpgrade,
        onCloseFn: onClose,
        confirmButtonText: 'Download Anyway',
        actionButtonText: 'Upgrade',
      });
    },
  };

  await processDownloadGating(
    clip,
    menus,
    session,
    clips,
    router,
    statsigClient,
    apiClient,
    confirmFn,
    modalRenderer
  );
};

// must be rendered in a ClipContext
export const ClipMenuItem = ({
  keepMenusOpen,
  enableForIncompleteClips,
  renderTags,
  children,
  ...props
}: ButtonProps & {
  keepMenusOpen?: boolean;
  enableForIncompleteClips?: boolean;
  renderTags?: () => React.ReactNode;
}) => {
  const clip = useNullableClipContext();
  if (!clip) throw new Error('ClipMenuItem must be rendered in a ClipContext');

  const isComplete = useClipIsComplete();
  const disabled = props.disabled || (!enableForIncompleteClips && !isComplete);

  if (!props.onClick && !props.href) {
    return (
      <Tooltip label='Not yet implemented!'>
        <ContextMenuItem
          keepMenusOpen={keepMenusOpen}
          {...props}
          className={`w-full flex-grow-1 py-2 pr-4 pl-2.5 text-accent-error-on-primary ${props.className} context-menu-button`}
          disabled={disabled}
        >
          <div className='flex w-full items-center justify-between'>
            <span className='truncate'>{children}</span>
            {renderTags && renderTags()}
          </div>
        </ContextMenuItem>
      </Tooltip>
    );
  }

  return (
    <ContextMenuItem
      keepMenusOpen={keepMenusOpen}
      variant={ButtonVariant.Tertiary}
      {...props}
      aria-label={typeof children === 'string' ? children : undefined}
      className={twMerge(
        'w-full flex-grow-1 !bg-transparent py-2 pr-4 pl-2.5 hover:bg-background-secondary',
        props.className,
        'context-menu-button'
      )}
      disabled={disabled}
    >
      {renderTags ? (
        <div className='flex w-full items-center justify-between'>
          <span className='truncate'>{children}</span>
          {renderTags()}
        </div>
      ) : (
        children
      )}
    </ContextMenuItem>
  );
};

export const OpenInEditorItem = () => {
  const clip = useClipContext();
  const { session, menus, edit } = useStores();
  const router = useRouter();
  const pathname = usePathname();
  const isMobile = !useBreakpointMd();

  const isValid =
    !clip?.is_trashed &&
    (session.isStaff || session.user?.id === clip?.user_id) &&
    !isMobile;

  const handleClick = () => {
    if (!isFeatureEnabledForPlan(session, PlanFeature.EditMode)) {
      menus.setCurrentUpsellFeature(FeatureKey.SONG_EDITOR);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }

    edit.setExitEditModeCallback(() => {
      router.push(pathname);
    });

    if (isProjectsFeatureEnabled(session)) {
      window.location.href = `/edit/${clip.id}?wid=${clip.project?.id || 'default'}`;
    } else {
      window.location.href = `/edit/${clip.id}`;
    }
  };

  if (!isValid) return null;

  return (
    <ClipMenuItem
      icon={<SlidersIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuEditClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
      aria-label='Open in Editor'
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Pro}>
          Pro
        </Tag>
      )}
    >
      Open in Editor
    </ClipMenuItem>
  );
};

export const OpenInStudioItem = () => {
  const clip = useClipContext();
  const { session, menus } = useStores();
  const hasStudio = session.flags && Boolean(session.flags['studio']);
  const isMobile = !useBreakpointMd();

  if (!hasStudio || isMobile) return null;
  const handleClick = () => {
    if (!isFeatureEnabledForPlan(session, PlanFeature.Studio)) {
      menus.setCurrentUpsellFeature(FeatureKey.STUDIO);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }
    window.location.href = `/studio?for_clip_id=${clip.id}`;
    logWebUserEvent({
      actionName: 'NavigatedToStudio',
      context: {
        trigger: 'song_menu_edit_in_studio',
      },
    });
  };

  return (
    <ClipMenuItem
      icon={<StudioIcon />}
      onClick={handleClick}
      aria-label='Open in Studio'
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.New}>
          New
        </Tag>
      )}
    >
      Open in Studio
    </ClipMenuItem>
  );
};

export const OpenInChatItem = () => {
  const clip = useClipContext();
  const [, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );
  const { session } = useStores();
  const router = useRouter();
  const pathname = usePathname();
  const { isControlGroup: isChatExpControlGroup } = useOrpheusExperimentGroup();
  const isChatExpEnabled = !isChatExpControlGroup;

  const handleClick = useCallback(() => {
    router.push(`/create?mode=chat&ref_id=${clip.id}&ref_type=clip`);
  }, [setMode, session.flags, clip, pathname, router]);

  if (!isChatExpEnabled) {
    return null;
  }

  return (
    <ClipMenuItem
      icon={<OrpheusLogo />}
      onClick={handleClick}
      aria-label='Open in Chat'
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.New}>
          New
        </Tag>
      )}
    >
      Open in Chat
    </ClipMenuItem>
  );
};

export const CoverItem = () => {
  const clip = useClipContext();
  const { genForm, project } = useStores();
  const router = useRouter();
  const pathname = usePathname();
  const expandCreatePanel = useExpandCreatePanel();
  const [mode, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );

  const addCondition = useContextSelector(
    CreateFormContext,
    (context) => context.addCondition
  );

  const handleCoverClick = useCallback(async () => {
    await project.setCurrentProjectToClipProject(clip);

    if (pathname !== '/create' && pathname !== '/studio') {
      if (mode === CreateModes.CHAT) {
        setMode(CreateModes.CUSTOM);
      }
      router.push('/create?remix_clip=' + clip.id + '&remix_type=cover');
    } else if (pathname === '/create' && mode === CreateModes.CHAT) {
      setMode(CreateModes.CUSTOM);
    }
    genForm.shouldOpenMobileCreate = true;

    // Use unified addCondition - it will handle the modal logic
    await addCondition(clip.id, AddConditionType.COVER);
    expandCreatePanel();
  }, [
    clip,
    expandCreatePanel,
    addCondition,
    genForm,
    pathname,
    project,
    router,
    mode,
    setMode,
  ]);

  return (
    <ClipMenuItem
      icon={<CoverCreateIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuRemixCoverClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleCoverClick
      )}
      aria-label='Cover song'
    >
      Cover
    </ClipMenuItem>
  );
};

export const ExtendItem = () => {
  const clip = useClipContext();
  const { genForm, project } = useStores();
  const router = useRouter();
  const pathname = usePathname();
  const expandCreatePanel = useExpandCreatePanel();
  const [mode, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );

  const addCondition = useContextSelector(
    CreateFormContext,
    (context) => context.addCondition
  );

  const handleExtendClick = useCallback(async () => {
    await project.setCurrentProjectToClipProject(clip);

    if (pathname !== '/create' && pathname !== '/studio') {
      if (mode === CreateModes.CHAT) {
        setMode(CreateModes.CUSTOM);
      }
      router.push('/create?remix_clip=' + clip.id + '&remix_type=extend');
    } else if (pathname === '/create' && mode === CreateModes.CHAT) {
      setMode(CreateModes.CUSTOM);
    }
    genForm.shouldOpenMobileCreate = true;

    // Use unified addCondition - it will handle the modal logic
    await addCondition(clip.id, AddConditionType.EXTEND);
    expandCreatePanel();
  }, [
    clip,
    expandCreatePanel,
    addCondition,
    genForm,
    pathname,
    project,
    router,
    mode,
    setMode,
  ]);

  return (
    <ClipMenuItem
      icon={<ExtendRightIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuRemixExtendClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleExtendClick
      )}
      aria-label='Extend'
    >
      Extend
    </ClipMenuItem>
  );
};

export const CropItem = () => {
  const clip = useClipContext();
  const { session, menus } = useStores();
  const router = useRouter();
  const isMobile = !useBreakpointMd();

  const handleClick = () => {
    if (!isFeatureEnabledForPlan(session, PlanFeature.EditMode)) {
      menus.setCurrentUpsellFeature(FeatureKey.CROP_FADE);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }

    router.push(`/edit/${clip.id}`);
  };

  if (isMobile) return null;

  return (
    <ClipMenuItem
      icon={<ScissorsIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuCropSongClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Pro}>
          Pro
        </Tag>
      )}
    >
      Crop
    </ClipMenuItem>
  );
};

export const ReplaceSectionItem = () => {
  const clip = useClipContext();
  const { session, menus } = useStores();
  const router = useRouter();
  const isMobile = !useBreakpointMd();

  const handleClick = () => {
    if (!isFeatureEnabledForPlan(session, PlanFeature.EditMode)) {
      menus.setCurrentUpsellFeature(FeatureKey.REPLACE_SECTION);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }

    router.push(`/edit/${clip.id}`);
  };

  if (isMobile) return null;

  return (
    <ClipMenuItem
      icon={<SectionIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuReplaceSectionClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Pro}>
          Pro
        </Tag>
      )}
      disabled={!clip?.metadata?.duration}
    >
      Replace Section
    </ClipMenuItem>
  );
};

export const ReuseStylesLyricsItem = () => {
  const clip = useClipContext();
  const { genForm } = useStores();
  const router = useRouter();
  const pathname = usePathname();
  const reuseAction = useClipAction(reusePrompt);
  const expandCreatePanel = useExpandCreatePanel();
  const [mode, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );

  const handleReuseStylesLyricsClick = () => {
    if (pathname !== '/create' && pathname !== '/studio') {
      if (mode === CreateModes.CHAT) {
        setMode(CreateModes.CUSTOM);
      }
      router.push('/create?remix_clip=' + clip.id + '&remix_type=reuse');
    } else if (pathname === '/create' && mode === CreateModes.CHAT) {
      setMode(CreateModes.CUSTOM);
    }
    genForm.shouldOpenMobileCreate = true;
    reuseAction();
    expandCreatePanel();
  };

  return (
    <ClipMenuItem
      icon={<LyricsIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuRemixUseStylesLyricsClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleReuseStylesLyricsClick
      )}
      aria-label='Reuse styles and lyrics'
      enableForIncompleteClips
    >
      Use Styles & Lyrics
    </ClipMenuItem>
  );
};

export const GetFullSongItem = () => {
  const clip = useClipContext();
  const { clips, project, session } = useStores();
  const clipCreated = useContextSelector(
    ClipBrowserRegistryContext,
    (ctx) => ctx.clipCreated
  );
  const pathname = usePathname();
  const [mode, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );

  const handleClick = useCallback(async () => {
    if (isProjectsFeatureEnabled(session)) {
      await project.setCurrentProjectToClipProject(clip);
    }
    if (pathname === '/create' && mode === CreateModes.CHAT) {
      setMode(CreateModes.CUSTOM);
    }

    const concatClip = await clips.runConcat(clip.id, !!clip.metadata?.infill, {
      editSessionId: clip.metadata?.edit_session_id,
    });

    if (concatClip) clipCreated(concatClip);
  }, [clip, clips, project, session, clipCreated]);

  const isInvalidModel = !isValidModelVersion(clip);
  const isNotOwner = session?.user?.id !== clip?.user_id;
  const hasNoHistory = !clip?.metadata?.history;
  const isInfill = Boolean(clip?.metadata?.infill);
  const isStem = clip?.metadata?.type === 'stem';

  const isHidden = Boolean(
    isInvalidModel || isNotOwner || hasNoHistory || isInfill || isStem
  );

  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<VinylIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuGetWholeSongClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
      aria-label='Get full song'
      enableForIncompleteClips
    >
      Get Full Song
    </ClipMenuItem>
  );
};

export const ConfirmSectionItem = () => {
  const clip = useClipContext();
  const { clips, project, session } = useStores();
  const pathname = usePathname();
  const clipCreated = useContextSelector(
    ClipBrowserRegistryContext,
    (ctx) => ctx.clipCreated
  );
  const [mode, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );

  const isComplete = useClipIsComplete();

  const handleClick = useCallback(async () => {
    if (!isComplete) return;
    await project.setCurrentProjectToClipProject(clip);

    if (pathname === '/create' && mode === CreateModes.CHAT) {
      setMode(CreateModes.CUSTOM);
    }

    const concatClip = await clips.runConcat(clip.id, !!clip.metadata?.infill, {
      editSessionId: clip.metadata?.edit_session_id,
    });

    if (concatClip) clipCreated(concatClip);
  }, [clip, clips, project, clipCreated, isComplete]);

  const isOwner = clip?.user_id === session?.userId;
  const isInfill = clip?.metadata?.infill;

  if (!isInfill || !isOwner) return null;

  return (
    <ClipMenuItem
      icon={<SectionIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuConfirmSectionClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
      aria-label='Confirm section'
      enableForIncompleteClips
    >
      Confirm Section
    </ClipMenuItem>
  );
};

export const AddVocalItem = () => {
  const clip = useClipContext();
  const { session, menus, genForm } = useStores();
  const router = useRouter();
  const pathname = usePathname();
  const addVocalAction = useClipAction(overpaintClip);
  const expandCreatePanel = useExpandCreatePanel();
  const [mode, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );

  const handleClick = () => {
    if (!isFeatureEnabledForPlan(session, PlanFeature.PLAYLIST_CONDITION)) {
      menus.setCurrentUpsellFeature(FeatureKey.VOCALS);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }
    addVocalAction();
    if (pathname !== '/create' && pathname !== '/studio') {
      if (mode === CreateModes.CHAT) {
        setMode(CreateModes.CUSTOM);
      }
      router.push('/create?remix_clip=' + clip.id + '&remix_type=add_vocal');
    } else if (pathname === '/create' && mode === CreateModes.CHAT) {
      setMode(CreateModes.CUSTOM);
    }
    genForm.shouldOpenMobileCreate = true;
    expandCreatePanel();
  };
  const isHidden =
    !session.flags?.['under-over-painting'] ||
    !canAddVocal(clip) ||
    !canUseModel(session.billingModels, 'chirp-bluejay');
  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<StemAddIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'RemixEditOverpaintingClicked',
          context: {
            clipId: clip?.id,
            isOwner: clip?.user_id === session?.userId,
          },
        },
        handleClick
      )}
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Pro}>
          Pro
        </Tag>
      )}
    >
      Add Vocal
    </ClipMenuItem>
  );
};

export const AddInstrumentalItem = () => {
  const clip = useClipContext();
  const { session, menus, genForm } = useStores();
  const router = useRouter();
  const pathname = usePathname();
  const addInstrumentalAction = useClipAction(underpaintClip);
  const expandCreatePanel = useExpandCreatePanel();
  const [mode, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );

  const handleClick = () => {
    if (!isFeatureEnabledForPlan(session, PlanFeature.PLAYLIST_CONDITION)) {
      menus.setCurrentUpsellFeature(FeatureKey.VOCALS);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }
    addInstrumentalAction();
    expandCreatePanel();
    if (pathname !== '/create' && pathname !== '/studio') {
      if (mode === CreateModes.CHAT) {
        setMode(CreateModes.CUSTOM);
      }
      router.push(
        '/create?remix_clip=' + clip.id + '&remix_type=add_instrumental'
      );
    } else if (pathname === '/create' && mode === CreateModes.CHAT) {
      setMode(CreateModes.CUSTOM);
    }
    genForm.shouldOpenMobileCreate = true;
  };

  const isHidden =
    !session.flags?.['under-over-painting'] ||
    !canAddInstrumental(clip) ||
    !canUseModel(session.billingModels, 'chirp-bluejay');

  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<StemAddIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'RemixEditUnderpaintingClicked',
          context: {
            clipId: clip?.id,
            isOwner: clip?.user_id === session?.userId,
          },
        },
        handleClick
      )}
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Pro}>
          Pro
        </Tag>
      )}
    >
      Add Instrumental
    </ClipMenuItem>
  );
};

export const GetStemsItem = () => {
  const { openModalWithData } = useModalContext();
  const clip = useClipContext();
  const upsell = useStemUpsell();
  const { session } = useStores();
  const isMidiTranscriptionEnabled = !!isFeatureEnabledForPlan(
    session,
    PlanFeature.Studio
  );
  const handleClick = useCallback(() => {
    return (
      upsell() ||
      openModalWithData(
        ModalTypes.STEMS,
        {
          clipId: clip.id,
          initialView: 'initial',
        },
        StemsModalSource.SONG_MENU
      )
    );
  }, [clip.id, upsell, openModalWithData]);

  // Hide if not owner, trashed, or not complete
  const isOwner = clip.user_id === session.user?.id;
  if (!isOwner || clip.is_trashed) return null;

  const isDisabled = clip.status !== 'complete' || isSunoShort(clip);

  return (
    <ClipMenuItem
      icon={<StemAddIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuGetStemsClicked',
          context: {
            clipId: clip.id,
          },
        },
        handleClick
      )}
      aria-label={
        isMidiTranscriptionEnabled
          ? 'Extract MIDI from this song'
          : 'Get stems for this song'
      }
      disabled={isDisabled}
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Pro}>
          Pro
        </Tag>
      )}
    >
      {isMidiTranscriptionEnabled ? 'Get Stems / MIDI' : 'Get Stems'}
    </ClipMenuItem>
  );
};

export const AddToQueueItem = () => {
  const clip = useClipContext();
  const { queue, session } = useStores();

  const handleClick = useCallback(() => {
    queue.addToQueue(clip);
    toast({
      title: 'Added to song queue',
      status: 'info',
      duration: 2000,
      isClosable: true,
    });
  }, [queue, clip]);

  if (clip.is_trashed) return null;

  return (
    <ClipMenuItem
      icon={<QueueIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuAddToPlaylistClicked',
          context: {
            clipId: clip?.id,
            isUserSongOwner:
              session?.userId !== undefined &&
              clip?.user_id === session?.userId,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Add to Queue
    </ClipMenuItem>
  );
};

export const MultiSelectAddToQueueItem = () => {
  const multiSelectClipIds = useContextSelector(
    MultiSelectContext,
    (ctx) => ctx.selectedClipIds
  );
  const clearMultiSelect = useContextSelector(
    MultiSelectContext,
    (ctx) => ctx.clear
  );

  const { clips: multiSelectClipsById } = useClips(multiSelectClipIds);

  const { queue, session } = useStores();

  const handleClick = useCallback(() => {
    const clips = multiSelectClipIds
      .map((clipId) => multiSelectClipsById[clipId])
      .filter(Boolean);
    clips.forEach((clip) => {
      queue.addToQueue(clip);
    });
    toast({
      title: `Added ${clips.length} songs to queue`,
      status: 'info',
      duration: 2000,
      isClosable: true,
    });
    clearMultiSelect();
  }, [queue, multiSelectClipIds, multiSelectClipsById, clearMultiSelect]);

  return (
    <ClipMenuItem
      icon={<QueueIcon />}
      enableForIncompleteClips
      onClick={withWebUserEvent(() => {
        const clips = multiSelectClipIds
          .map((clipId) => multiSelectClipsById[clipId])
          .filter(Boolean);
        return {
          actionName: 'SongMenuAddToPlaylistClicked',
          context: {
            clipId: clips[0]?.id, // Log the first clip's ID
            isUserSongOwner:
              session?.userId !== undefined &&
              clips[0]?.user_id === session?.userId,
          },
        };
      }, handleClick)}
    >
      Add to Queue
    </ClipMenuItem>
  );
};

export const AddToPlaylistItem = () => {
  const clip = useClipContext();
  const { menus, session } = useStores();
  const { openModal } = useModalContext();
  const arrayContainingClipId = useMemo(() => [clip.id], [clip.id]);
  const selectedClipIds = useContextSelector(MultiSelectContext, (ctx) =>
    ctx.selectedClipIds.length === 0
      ? arrayContainingClipId
      : ctx.selectedClipIds
  );
  const handleClick = useCallback(() => {
    menus.setSelected(new Set(selectedClipIds));
    openModal(ModalTypes.ADD_TO_PLAYLIST, 'SongMenu');
  }, [menus, selectedClipIds, openModal]);

  if (clip.is_trashed || !session.user?.id) return null;

  return (
    <ClipMenuItem
      icon={<PlusIcon />}
      enableForIncompleteClips
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuAddToPlaylistClicked',
          context: {
            clipId: clip?.id,
            isUserSongOwner:
              session?.userId !== undefined &&
              clip?.user_id === session?.userId,
          },
        },
        handleClick
      )}
    >
      Add to Playlist
    </ClipMenuItem>
  );
};

export const MoveToWorkspaceItem = () => {
  const clip = useClipContext();
  const { menus, clips, session } = useStores();
  const addToProject = useModalTrigger(ModalTypes.ADD_TO_PROJECT);
  const arrayContainingClipId = useMemo(() => [clip.id], [clip.id]);
  const selectedClipIds = useContextSelector(MultiSelectContext, (ctx) =>
    ctx.selectedClipIds.length === 0
      ? arrayContainingClipId
      : ctx.selectedClipIds
  );
  const handleClick = useCallback(() => {
    menus.setSelected(new Set(selectedClipIds));
    addToProject();
  }, [menus, selectedClipIds, addToProject]);

  const allSelectedClipsOwnedByUser = selectedClipIds.every((id) => {
    const c = clips.clipById[id];
    return c?.user_id === session.user?.id;
  });
  const isHidden = clip?.is_trashed || !allSelectedClipsOwnedByUser;
  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<DownRightArrowIcon />}
      enableForIncompleteClips
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuMoveToWorkspaceClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
    >
      Move to Workspace
    </ClipMenuItem>
  );
};

export const PublishItem = () => {
  const clip = useClipContext();
  const { session } = useStores();
  const { togglePublishClicked, isPublished } = usePublishClip(clip);
  const isComplete = useClipIsComplete();

  const isOwner = session.user?.id === clip?.user_id;
  const isTrashed = !!clip?.is_trashed;
  const isUploadClip = isUnpublishableUploadClip(clip);

  if (!isComplete || !isOwner || isTrashed || isUploadClip) return null;

  const handleClick = () => {
    togglePublishClicked();
  };

  return (
    <ClipMenuItem
      icon={isPublished ? <GlobeSlashIcon /> : <GlobeIcon />}
      onClick={withWebUserEvent(
        {
          actionName: isPublished
            ? 'SongMenuUnpublishClicked'
            : 'SongMenuPublishClicked',
          context: {
            clipId: clip.id,
          },
        },
        handleClick
      )}
    >
      {isPublished ? 'Unpublish' : 'Publish'}
    </ClipMenuItem>
  );
};

export const SongDetailsItem = () => {
  const { library, session } = useStores();
  const { openModal } = useModalContext();
  const clip = useClipContext();
  const isComplete = useClipIsComplete();
  const handleClick = useCallback(() => {
    library.setActiveClip(clip);
    openModal(ModalTypes.UPDATE_CLIP_METADATA, 'SongMenu');
  }, [library, clip, openModal]);

  const isHidden =
    session.user?.id !== clip?.user_id || !!clip?.is_trashed || !isComplete;

  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<InfoIcon />}
      onClick={handleClick}
      enableForIncompleteClips
    >
      Song Details
    </ClipMenuItem>
  );
};

export const GenerateCoverArtItem = () => {
  const clip = useClipContext();
  const { session } = useStores();
  const enableGenerateCovers = useGateValue('gen-video-covers');
  const { openModalWithData } = useModalContext();

  const isComplete = useClipIsComplete();

  const handleClick = useCallback(() => {
    openModalWithData(
      ModalTypes.GENERATE_COVER_ART,
      { clipId: clip.id, useClipCoverImage: false },
      'SongMenu'
    );
  }, [openModalWithData, clip]);

  if (!enableGenerateCovers) return null;

  const isHidden =
    session.user?.id !== clip?.user_id || !!clip?.is_trashed || !isComplete;

  if (isHidden) return null;
  return (
    <ClipMenuItem icon={<SparklesIcon />} onClick={handleClick}>
      Generate Cover Art
    </ClipMenuItem>
  );
};

export const CopyLinkItem = () => {
  const clip = useClipContext();
  const { session } = useStores();
  const isUserSongOwner = useIsOwnClip(clip);
  const shareClip = useShareClip();
  const handleClick = useCallback(() => {
    shareClip(clip);
  }, [clip, shareClip]);
  return (
    <ClipMenuItem
      icon={<LinkIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuCopyLinkClicked',
          context: {
            clipId: clip.id,
            isUserSongOwner: session?.userId !== undefined && isUserSongOwner,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Copy Link
    </ClipMenuItem>
  );
};

export const CopyLinkAtCurrentTimeItem = () => {
  const clip = useClipContext();
  const isUserSongOwner = useIsOwnClip(clip);
  const shareClip = useShareClip();
  const { playbar, session } = useStores();
  const { isLoadedIntoPlayer } = useClipPlaybackContext();

  const handleClick = useCallback(() => {
    const timestamp = Math.round(
      playbar.getCurrentTime() ?? playbar.currentTime ?? 0
    );
    shareClip(clip, timestamp);
  }, [clip, shareClip, playbar]);

  if (!isLoadedIntoPlayer) return null;

  return (
    <ClipMenuItem
      icon={<LinkIcon />}
      onClick={withWebUserEvent(() => {
        const timestamp = Math.round(
          playbar.getCurrentTime() ?? playbar.currentTime ?? 0
        );
        return {
          actionName: 'TimestampURLCopiedSongMenu',
          context: {
            clipId: clip?.id,
            isUserSongOwner: session?.userId !== undefined && isUserSongOwner,
            timestamp,
          },
        };
      }, handleClick)}
      enableForIncompleteClips
    >
      Copy Link at Current Time
    </ClipMenuItem>
  );
};

export const ReportInappropriateItem = () => {
  const clip = useClipContext();
  const apiClient = useApiClient();
  const isUserSongOwner = useIsOwnClip(clip);
  const { session } = useStores();

  const handleClick = useCallback(async () => {
    try {
      const { data } = await apiClient.POST(
        '/api/gen/{gen_id}/update_flag_state/',
        {
          params: { path: { gen_id: clip.id } },
          body: {
            flagged: true,
            flagged_reason: 'flag_inappropriate',
          },
        }
      );

      if (data) {
        toast({
          title: 'Song flagged.',
          description: 'This song has been flagged for review.',
          status: 'warning',
          duration: 4000,
          isClosable: true,
        });
      }
    } catch (error) {
      toast({
        title: 'Error flagging song.',
        description: 'Something went wrong. Please try again later.',
        status: 'error',
        duration: 5000,
        isClosable: true,
      });
    }
  }, [clip.id, apiClient]);

  return (
    <ClipMenuItem
      icon={<FrownIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuReportInappropriateClicked',
          context: {
            clipId: clip.id,
            isUserSongOwner: session?.userId !== undefined && isUserSongOwner,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Inappropriate
    </ClipMenuItem>
  );
};

export const ReportBugItem = () => {
  const clip = useClipContext();
  const { openModalWithData } = useModalContext();
  const isUserSongOwner = useIsOwnClip(clip);
  const { session } = useStores();

  const handleClick = useCallback(() => {
    openModalWithData(ModalTypes.FLAG_CLIP, {
      clipId: clip.id,
      clipTitle: clip.title || 'Untitled',
    });
  }, [clip, openModalWithData]);

  if (!isUserSongOwner) return null;

  return (
    <ClipMenuItem
      icon={<BugIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuReportBugClicked',
          context: {
            clipId: clip.id,
            isUserSongOwner: session?.userId !== undefined && isUserSongOwner,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Bug
    </ClipMenuItem>
  );
};

export const ReportCopyrightItem = () => {
  const clip = useClipContext();
  const { openModalWithData } = useModalContext();
  const isUserSongOwner = useIsOwnClip(clip);

  const handleClick = useCallback(() => {
    openModalWithData(ModalTypes.COPYRIGHT_FLAG, { clipId: clip.id });
  }, [clip, openModalWithData]);

  return (
    <ClipMenuItem
      icon={<FlagIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuReportCopyrightClicked',
          context: {
            clipId: clip.id,
            isUserSongOwner,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Copyright Infringement
    </ClipMenuItem>
  );
};

export const ShareToItem = () => {
  const clip = useClipContext();
  const { session } = useStores();
  const { openModalWithData } = useModalContext();
  const isUserSongOwner = useIsOwnClip(clip);

  const handleClick = useCallback(() => {
    openModalWithData(ModalTypes.SHARE_CLIP, { clipId: clip.id }, 'SongMenu');
    session.clearTooltipOnShare();
  }, [clip.id, openModalWithData, session]);

  return (
    <ClipMenuItem
      icon={<UserGroupIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuShareToClicked',
          context: {
            clipId: clip.id,
            isUserSongOwner: session?.userId !== undefined && isUserSongOwner,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Share to...
    </ClipMenuItem>
  );
};

export const ShareWithFriendsItem = () => {
  const clip = useClipContext();
  const { session } = useStores();
  const { openModalWithData } = useModalContext();
  const isUserSongOwner = useIsOwnClip(clip);
  const showInAppSharing = useGateValue(
    'enable-sharelist-and-share-notifications'
  );

  const handleClick = useCallback(() => {
    openModalWithData(
      ModalTypes.SHARE_WITH_FRIENDS,
      { clipId: clip.id },
      'SongMenu'
    );
  }, [clip.id, openModalWithData]);

  // Only show if in-app sharing is enabled
  if (!showInAppSharing) return null;

  return (
    <ClipMenuItem
      icon={<SendIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuShareWithFriendsClicked',
          context: {
            clipId: clip.id,
            isUserSongOwner: session?.userId !== undefined && isUserSongOwner,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Share with friends
    </ClipMenuItem>
  );
};

export const ClipRadioItem = () => {
  const clip = useClipContext();
  const { session } = useStores();
  const pathname = usePathname();
  const router = useRouter();
  const isUserSongOwner = useIsOwnClip(clip);
  const isComplete = useClipIsComplete();

  const handleClick = useCallback(() => {
    router.push(`/radio/song/${clip.id}`);
  }, [clip.id, router]);

  const isHidden =
    !session.user || pathname === `/radio/song/${clip.id}` || !isComplete;

  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<RadioBroadcastIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuSongRadioClicked',
          context: {
            clipId: clip.id,
            isUserSongOwner,
          },
        },
        handleClick
      )}
    >
      Song Radio
    </ClipMenuItem>
  );
};

export const CreateVariationsItem = () => {
  const clip = useClipContext();
  const { session, menus, project } = useStores();
  const { openModalWithData } = useModalContext();
  const isClipComplete = useClipIsComplete();

  const handleClick = useCallback(async () => {
    if (!isClipComplete) {
      return;
    }

    const canVariationRemaster = isFeatureEnabledForPlan(
      session,
      PlanFeature.VariationRemaster
    );
    if (!canVariationRemaster) {
      menus.setCurrentUpsellFeature(FeatureKey.REMASTER);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }
    if (!!clip.is_contest_base_clip) {
      return;
    }
    if (isProjectsFeatureEnabled(session)) {
      await project.setCurrentProjectToClipProject(clip);
    }

    openModalWithData(ModalTypes.UPSAMPLE_MODEL_SELECT, { clipId: clip.id });
  }, [clip, session, menus, project, isClipComplete, openModalWithData]);

  const isInfill = !!clip.metadata?.infill;
  const isOwnSong = clip?.user_id === session.user?.id;

  const isHidden =
    !isClipComplete ||
    clip?.is_trashed ||
    !isOwnSong ||
    !isFeatureEnabledForPlan(session, PlanFeature.VariationRemaster) ||
    !(
      clip?.major_model_version === 'v4.5' ||
      clip?.model_name?.includes('bluejay') ||
      !clip?.major_model_version
    ) ||
    isInfill ||
    session.flags?.['remaster-modal'];

  if (isHidden) return null;

  const isDisabled =
    !isFeatureEnabledForPlan(session, PlanFeature.VariationRemaster) ||
    !!clip.is_contest_base_clip;

  return (
    <ClipMenuItem
      icon={<SlidersIcon />}
      onClick={handleClick}
      disabled={isDisabled}
    >
      Create Variations
    </ClipMenuItem>
  );
};

export const RemasterV4Item = () => {
  const clip = useClipContext();
  const { session, clips, project, menus } = useStores();
  const isClipComplete = useClipIsComplete();
  const router = useRouter();
  const pathname = usePathname();

  const clipCreated = useContextSelector(
    ClipBrowserRegistryContext,
    (context) => context?.clipCreated || noop
  );

  const handleClick = useCallback(async () => {
    if (!isClipComplete) {
      return;
    }

    const canUpsample = isFeatureEnabledForPlan(session, PlanFeature.V4);

    if (!canUpsample) {
      menus.setCurrentUpsellFeature(FeatureKey.REMASTER);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }
    if (!!clip.is_contest_base_clip) {
      return;
    }
    if (isProjectsFeatureEnabled(session)) {
      await project.setCurrentProjectToClipProject(clip);
    }

    const remasteredClips = await clips.upsampleClip(clip);
    remasteredClips?.forEach(clipCreated);
    if (pathname !== '/create' && pathname !== '/studio') {
      router.push(`/create`);
    }
    toast({
      title: 'Remastering clip...',
      status: 'info',
      duration: 10000,
      isClosable: true,
    });
  }, [
    clip,
    session,
    clips,
    project,
    menus,
    router,
    pathname,
    isClipComplete,
    clipCreated,
  ]);

  const isInfill = !!clip.metadata?.infill;
  const isOwnSong = clip?.user_id === session.user?.id;

  const isHidden =
    !session.flags?.['upsample'] ||
    !isClipComplete ||
    clip?.is_trashed ||
    !isOwnSong ||
    isInfill ||
    session.flags?.['remaster-modal'];

  if (isHidden) return null;

  const canUpsample = isFeatureEnabledForPlan(session, PlanFeature.V4);
  const isTooLong = (clip.metadata?.duration ?? 0) > 960;
  const isDisabled = !canUpsample || !!clip.is_contest_base_clip || isTooLong;

  const renderTags = () => (
    <>
      {!session.flags?.['upsample'] && session.freeRemastersLeft > 0 && (
        <span className='ml-2 text-xs text-foreground-inactive'>
          {session.freeRemastersLeft} free
        </span>
      )}
      <Tag className='ml-2'>v4</Tag>
      <Tag className='ml-2' variant={TagVariant.Pro}>
        Pro
      </Tag>
    </>
  );

  return (
    <ConditionalTooltip
      isTooltipEnabled={isTooLong}
      label='Cannot remaster songs longer than 16 minutes'
    >
      <ClipMenuItem
        icon={<CreateIcon />}
        onClick={withWebUserEvent(
          {
            actionName: 'SongMenuRemasterClicked',
            context: {
              clipId: clip?.id,
            },
          },
          handleClick
        )}
        disabled={isDisabled}
        renderTags={renderTags}
      >
        Remaster
      </ClipMenuItem>
    </ConditionalTooltip>
  );
};

export const RemasterV4_5PlusItem = () => {
  const clip = useClipContext();
  const { session, clips, project, menus } = useStores();
  const isClipComplete = useClipIsComplete();
  const router = useRouter();
  const pathname = usePathname();

  const clipCreated = useContextSelector(
    ClipBrowserRegistryContext,
    (context) => context?.clipCreated || noop
  );

  const handleClick = useCallback(async () => {
    if (!isClipComplete) {
      return;
    }

    const canUpsample = isFeatureEnabledForPlan(session, PlanFeature.Auk);

    if (!canUpsample) {
      menus.setCurrentUpsellFeature(FeatureKey.REMASTER);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }
    if (!!clip.is_contest_base_clip) {
      return;
    }
    await project.setCurrentProjectToClipProject(clip);

    if (canUpsample) {
      const remasteredClips = await clips.upsampleClip(clip, 'chirp-bass');
      remasteredClips?.forEach(clipCreated);
      if (pathname !== '/create' && pathname !== '/studio') {
        router.push(`/create`);
      }
      toast({
        title: 'Remastering clip...',
        status: 'info',
        duration: 10000,
        isClosable: true,
      });
    }
  }, [
    clip,
    session,
    clips,
    project,
    menus,
    router,
    pathname,
    isClipComplete,
    clipCreated,
  ]);

  const isInfill = !!clip.metadata?.infill;
  const isOwnSong = clip?.user_id === session.user?.id;

  const isHidden =
    !isClipComplete ||
    clip?.is_trashed ||
    !isOwnSong ||
    isInfill ||
    session.flags?.['remaster-modal'];

  if (isHidden) return null;

  const isTooLong = (clip.metadata?.duration ?? 0) > 960;
  const isDisabled = !!clip.is_contest_base_clip || isTooLong;

  const renderTags = () => (
    <>
      <Tag className='ml-2' variant={TagVariant.Auk}>
        v4.5+
      </Tag>
      <Tag className='ml-2' variant={TagVariant.Pro}>
        Pro
      </Tag>
    </>
  );

  return (
    <ConditionalTooltip
      isTooltipEnabled={isDisabled}
      label={
        isTooLong
          ? 'Cannot remaster songs longer than 16 minutes'
          : 'Contest songs cannot be remastered'
      }
    >
      <ClipMenuItem
        icon={<CreateIcon />}
        onClick={withWebUserEvent(
          {
            actionName: 'SongMenuRemasterClicked',
            context: {
              clipId: clip?.id,
            },
          },
          handleClick
        )}
        disabled={isDisabled}
        renderTags={renderTags}
      >
        Remaster
      </ClipMenuItem>
    </ConditionalTooltip>
  );
};

export const MakePersonaItem = () => {
  const clip = useClipContext();
  const { session, menus, genForm } = useStores();
  const isClipComplete = useClipIsComplete();

  const handleClick = useCallback(() => {
    if (!isClipComplete) {
      return;
    }

    genForm.setIsRemixCreate(false);

    if (!isFeatureEnabledForPlan(session, PlanFeature.Persona)) {
      menus.setCurrentUpsellFeature(FeatureKey.PERSONAS);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }

    if (
      (clip?.metadata?.has_vocal || clip?.metadata?.type === 'upload') &&
      !isStaff(session) &&
      !session.flags?.['personas-audio-upload']
    ) {
      return;
    }

    menus.setCurrentClip(clip);
    menus.openModal(ModalTypes.CREATE_PERSONA);
  }, [clip, session, menus, genForm, isClipComplete]);

  const isInfill = !!clip.metadata?.infill;
  const isStem = clip?.metadata?.type === 'stem';
  const alreadyHasPersona = !!clip.persona?.id;
  const isOwnSong = clip?.user_id === session.user?.id;

  const isHidden =
    isInfill ||
    isStem ||
    (alreadyHasPersona && clip.metadata?.type !== 'edit_crop') ||
    !isOwnSong;

  if (isHidden) return null;

  const uploadDerivative = !!(
    clip?.metadata?.has_vocal || clip?.metadata?.type === 'upload'
  );
  const hasValidModel = uploadDerivative ? true : isValidModelVersion(clip);
  const isOwner = clip?.user_id === session.user?.id;

  const isStaffUser = isStaff(session);
  let isDisabled = false;
  if (isStaffUser) {
    isDisabled = uploadDerivative ? false : !hasValidModel;
  } else {
    isDisabled =
      (!uploadDerivative && !hasValidModel) ||
      !isOwner ||
      (uploadDerivative && !session.flags?.['personas-audio-upload']);
  }

  return (
    <ConditionalTooltip
      isTooltipEnabled={
        uploadDerivative &&
        !isStaffUser &&
        !session.flags?.['personas-audio-upload']
      }
      label='Personas cannot be created from audio uploads.'
    >
      <ClipMenuItem
        icon={<PersonaCreateIcon />}
        onClick={withWebUserEvent(
          {
            actionName: 'SongMenuMakePersonaClicked',
            context: {
              clipId: clip?.id,
            },
          },
          handleClick
        )}
        aria-label='Make Persona'
        disabled={isDisabled}
        renderTags={() => (
          <Tag className='ml-2' variant={TagVariant.Pro}>
            Pro
          </Tag>
        )}
      >
        Make Persona
      </ClipMenuItem>
    </ConditionalTooltip>
  );
};

export const UsePersonaItem = () => {
  const clip = useClipContext();
  const { session, menus, genForm } = useStores();
  const pathname = usePathname();
  const router = useRouter();

  const personaAction = useClipAction((clip) => applyPersona(clip));

  const isInfill = !!clip.metadata?.infill;
  const isPrivateNotOwned = !clip.persona?.is_owned && !clip.persona?.is_public;

  const isHidden = isInfill || !clip.persona?.id || isPrivateNotOwned;

  if (isHidden) return null;

  const isDisabled = !isValidClipForPersona({ clip, session });

  const handleUsePersonaClick = () => {
    if (!isFeatureEnabledForPlan(session, PlanFeature.Persona)) {
      menus.setCurrentUpsellFeature(FeatureKey.PERSONAS);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }

    if (pathname !== '/create' && pathname !== '/studio') {
      router.push('/create?use_persona=' + clip.id);
    }
    personaAction();
    genForm.shouldOpenMobileCreate = true;
  };

  const personaName = clip.persona?.name || 'Persona';
  const truncatedPersonaName =
    personaName.length > 20 ? `${personaName.slice(0, 20)}...` : personaName;
  const menuText = `Use ${truncatedPersonaName}`;

  return (
    <ClipMenuItem
      icon={<PersonaCreateIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuUsePersonaClicked',
          context: {
            clipId: clip?.id,
            isUserSongOwner:
              session?.userId !== undefined &&
              clip?.user_id === session?.userId,
          },
        },
        handleUsePersonaClick
      )}
      disabled={isDisabled}
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Pro}>
          Pro
        </Tag>
      )}
    >
      {menuText}
    </ClipMenuItem>
  );
};

export const DownloadMP3Item = () => {
  const clip = useClipContext();
  const { session, menus, clips, library } = useStores();
  const router = useRouter();
  const statsigClient = useStatsigClient();
  const apiClient = useApiClient();

  const handleClick = useCallback(async () => {
    if (isDownloadDisabled(clip, session)) {
      return;
    }

    logWebUserEvent({
      actionName: 'SongMenuMP3AudioClicked',
      context: {
        clipId: clip?.id,
        isUserSongOwner:
          session?.userId !== undefined && clip?.user_id === session?.userId,
      },
    });

    await openDownloadConfirmModal(
      clip,
      menus,
      session,
      clips,
      router,
      statsigClient,
      apiClient,
      () => {
        downloadClipAudio(library.apiClient, clip, session);
        logDownloadToBilling(library.apiClient, clip.id);
      }
    );
  }, [clip, session, menus, clips, library, router, statsigClient, apiClient]);

  const isDisabled = isDownloadDisabled(clip, session);

  return (
    <ClipMenuItem
      icon={<HeadphoneIcon />}
      onClick={handleClick}
      disabled={isDisabled}
      enableForIncompleteClips={false}
    >
      MP3 Audio
    </ClipMenuItem>
  );
};

export const DownloadWAVItem = () => {
  const clip = useClipContext();
  const { session, menus, clips, library } = useStores();
  const router = useRouter();
  const isClipComplete = useClipIsComplete();
  const statsigClient = useStatsigClient();
  const apiClient = useApiClient();

  const handleClick = useCallback(async () => {
    if (!isClipComplete || isDownloadDisabled(clip, session)) {
      return;
    }

    if (!isWavDownloadAvailable(session)) {
      menus.setCurrentUpsellFeature(FeatureKey.DOWNLOAD_WAV);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }

    logWebUserEvent({
      actionName: 'SongMenuWAVAudioClicked',
      context: {
        clipId: clip?.id,
        isUserSongOwner:
          session?.userId !== undefined && clip?.user_id === session?.userId,
      },
    });

    await openDownloadConfirmModal(
      clip,
      menus,
      session,
      clips,
      router,
      statsigClient,
      apiClient,
      () => {
        menus.openModal(ModalTypes.DOWNLOAD_FILE);
        initDownloadClipWav(library.apiClient, clip.id);
        clips.pendingWavDownloadClip = clip;
        clips.pendingWavDownloadAtTime = Date.now();
        clips.setPendingWavPolling();
      }
    );
  }, [
    clip,
    session,
    menus,
    clips,
    library,
    router,
    isClipComplete,
    statsigClient,
    apiClient,
  ]);

  const isDisabled = !isClipComplete || isDownloadDisabled(clip, session);
  const isOwner = clip?.user_id === session?.userId;
  const isHidden = (!session.isStaff && !isOwner) || clip?.is_trashed;

  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<HeadphoneIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuWAVAudioClicked',
          context: {
            clipId: clip?.id,
            isUserSongOwner:
              session?.userId !== undefined &&
              clip?.user_id === session?.userId,
          },
        },
        handleClick
      )}
      disabled={isDisabled}
      enableForIncompleteClips={false}
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Pro}>
          Pro
        </Tag>
      )}
    >
      WAV Audio
    </ClipMenuItem>
  );
};

export const DownloadSamplePackItem = () => {
  const clip = useClipContext();
  const { session, library } = useStores();
  const isClipComplete = useClipIsComplete();
  const isSamplePackEnabled = useGateValue('download-sample-pack');

  const handleClick = useCallback(async () => {
    if (
      !isClipComplete ||
      (!!clip.download_disabled_reason &&
        !!session.flags?.['remix-contest-disable-downloads'])
    ) {
      return;
    }

    toast({
      title: 'Your sample pack is being prepared',
      description: 'This may take 2-3 minutes, please wait...',
      status: 'info',
      duration: 8000,
      isClosable: true,
    });

    try {
      await downloadSamplePack(library.apiClient, clip);
    } catch (error) {
      toast({
        title: 'Sample pack generation failed',
        description: 'Please try again later.',
        status: 'error',
        duration: 5000,
        isClosable: true,
      });
    }
  }, [clip, session, library, isClipComplete]);

  if (!isSamplePackEnabled) return null;

  const isDisabled =
    !isClipComplete ||
    (!!clip.download_disabled_reason &&
      !!session.flags?.['remix-contest-disable-downloads']);

  return (
    <ClipMenuItem
      icon={<StemsIcon />}
      onClick={handleClick}
      disabled={isDisabled}
      enableForIncompleteClips={false}
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Beta}>
          Beta
        </Tag>
      )}
    >
      Sample Pack
    </ClipMenuItem>
  );
};

export const DownloadVideoItem = () => {
  const clip = useClipContext();
  const { session, menus, clips, library } = useStores();
  const router = useRouter();
  const statsigClient = useStatsigClient();
  const apiClient = useApiClient();
  const isClipComplete = useClipIsComplete();

  const handleClick = useCallback(async () => {
    const hasVideoUrl = !!clip?.video_url;
    const hasPendingVideo = !!clips.videoPendingById[clip?.id];

    if (!hasVideoUrl || hasPendingVideo || isDownloadDisabled(clip, session)) {
      return;
    }

    logWebUserEvent({
      actionName: 'SongMenuVideoClicked',
      context: {
        clipId: clip?.id,
        isUserSongOwner:
          session?.userId !== undefined && clip?.user_id === session?.userId,
      },
    });

    await openDownloadConfirmModal(
      clip,
      menus,
      session,
      clips,
      router,
      statsigClient,
      apiClient,
      () => {
        downloadClipVideo(library.apiClient, clip, session);
      }
    );
  }, [clip, session, menus, clips, library, router, statsigClient, apiClient]);

  const hasVideoUrl = !!clip?.video_url;
  const hasPendingVideo = !!clips.videoPendingById[clip?.id];
  const isDisabled =
    !hasVideoUrl || hasPendingVideo || isDownloadDisabled(clip, session);
  const videoIsStale = !!clip?.metadata?.video_is_stale;

  // you can download the video if:
  // - the clip is complete and
  // - (if free user): video (URL) exists
  // - (if pro/premier user): video (URL) exists and is not stale
  const hasGenFeatureEnabled = isFeatureEnabledForPlan(
    session,
    PlanFeature.GenerateSongVideo
  );
  const canDownloadVideo =
    isClipComplete &&
    hasVideoUrl &&
    (hasGenFeatureEnabled ? !videoIsStale : true);
  if (!canDownloadVideo) return null;

  return (
    <ClipMenuItem
      icon={<VideoIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuVideoClicked',
          context: {
            clipId: clip?.id,
            isUserSongOwner:
              session?.userId !== undefined &&
              clip?.user_id === session?.userId,
          },
        },
        handleClick
      )}
      disabled={isDisabled}
      enableForIncompleteClips={true}
    >
      Video
    </ClipMenuItem>
  );
};

export const GenerateAndDownloadVideoItem = () => {
  const clip = useClipContext();
  const { session, clips, menus } = useStores();
  const router = useRouter();
  const statsigClient = useStatsigClient();
  const isClipComplete = useClipIsComplete();
  const downloadDisabled = isDownloadDisabled(clip, session);

  const hasGenFeatureEnabled = isFeatureEnabledForPlan(
    session,
    PlanFeature.GenerateSongVideo
  );

  const handleClick = useCallback(() => {
    if (clips.videoPendingById[clip.id] || downloadDisabled) {
      return;
    }
    if (!hasGenFeatureEnabled) {
      menus.setCurrentUpsellFeature(FeatureKey.GENERATE_VIDEO);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }

    clips.regenerateVideo(
      clip,
      router,
      statsigClient,
      openDownloadConfirmModal
    );
  }, [clip, clips, router, downloadDisabled, statsigClient]);

  const isEnabled = !clips.videoPendingById[clip.id];
  const isDisabled = !isEnabled || downloadDisabled;

  const hasVideoUrl = !!clip?.video_url;
  const videoIsStale = !!clip?.metadata?.video_is_stale;

  // you should be allowed to regenerate the video/see this button if:
  // - the clip is complete and
  // - (if pro/premier user): video (URL) exists and is not stale
  // - (if free user): no video (URL) exists
  const canGenerateVideo =
    isClipComplete &&
    (hasGenFeatureEnabled ? !hasVideoUrl || videoIsStale : !hasVideoUrl);
  if (!canGenerateVideo) return null;

  return (
    <ClipMenuItem
      icon={<CycleIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuRegenerateVideoClicked',
          context: {
            clipId: clip?.id,
            isUserSongOwner:
              session.userId !== undefined && clip?.user_id === session?.userId,
          },
        },
        handleClick
      )}
      disabled={isDisabled}
      enableForIncompleteClips={false}
      renderTags={() => (
        <Tag className='ml-2' variant={TagVariant.Pro}>
          Pro
        </Tag>
      )}
    >
      <div className='flex w-full flex-row items-center gap-2'>
        <span>Video</span>
      </div>
    </ClipMenuItem>
  );
};

export const ShareAssetItem = () => {
  const clip = useClipContext();
  const { session, clips } = useStores();
  const { openModal } = useModalContext();
  const isClipComplete = useClipIsComplete();

  const handleClick = useCallback(() => {
    if (!isClipComplete) {
      return;
    }
    clips.selectedShareAssetClip = clip;
    openModal(ModalTypes.DOWNLOAD_SHARE_ASSET);
  }, [clip, clips, isClipComplete, openModal]);

  const isShareAssetAvailable = session.isStaff && !clip?.is_trashed;

  if (!isShareAssetAvailable) return null;

  return (
    <ClipMenuItem
      icon={<ShareArrowIcon />}
      onClick={handleClick}
      disabled={!isClipComplete}
      enableForIncompleteClips={false}
    >
      Share Asset
    </ClipMenuItem>
  );
};

export const AllowCommentsItem = observer(() => {
  const clip = useClipContext();
  const { clips } = useStores();

  const handleClick = useCallback(async () => {
    const isEnabled = !clip.allow_comments;

    await clips.setCommentsEnabled(clip.id, isEnabled);

    toast({
      title: `Comments have been ${isEnabled ? 'enabled' : 'disabled'}.`,
      duration: 2000,
      isClosable: true,
    });
    logWebUserEvent({
      actionName: 'SongMenuAllowCommentsClicked',
      context: {
        clipId: clip?.id,
        enable: isEnabled,
      },
    });
  }, [clip, clips]);

  return (
    <ClipMenuItem
      icon={<CommentIcon />}
      onClick={handleClick}
      enableForIncompleteClips
      keepMenusOpen
    >
      <div className='flex w-full flex-row items-center justify-between gap-2'>
        <span>Allow Comments</span>
        <Switch
          small
          checked={!!clip.allow_comments}
          containerClassName='pointer-events-none'
        />
      </div>
    </ClipMenuItem>
  );
});

export const AllowRemixesItem = observer(() => {
  const clip = useClipContext();
  const { clips, session } = useStores();

  const handleClick = useCallback(async () => {
    if ((clip.metadata?.contest_ids?.length ?? 0) > 0) {
      return;
    }

    const isEnabled = clip.metadata?.can_remix === true;

    logWebUserEvent({
      actionName: 'SongMenuAllowRemixesToggled',
      context: {
        clipId: clip?.id,
        allowed: !isEnabled,
      },
    });

    await clips.toggleCanRemix(clip.id, !isEnabled);

    toast({
      title: `Remixes have been ${!isEnabled ? 'enabled' : 'disabled'}.`,
      duration: 2000,
      isClosable: true,
    });
  }, [clip, clips]);

  const isOwner = session.user?.id === clip?.user_id;
  const isDisabled = (clip.metadata?.contest_ids?.length ?? 0) > 0;

  if (!isOwner) return null;

  return (
    <ClipMenuItem
      keepMenusOpen
      icon={<RemixIcon />}
      disabled={isDisabled}
      enableForIncompleteClips
      onClick={handleClick}
    >
      <Tooltip
        label="You can now Remix songs on Suno — and other users can Remix your songs, too! By default, songs you create will Allow Remixes, but you can turn it off for any song here. Every Remix will link back to the song that inspired it, so you'll always get credit where it's due."
        placement='right'
      >
        <div className='flex w-full flex-row justify-between gap-2'>
          <span className='flex flex-1 items-center'>Allow Remixes</span>
          <Switch
            small
            checked={clip.metadata?.can_remix === true}
            containerClassName='pointer-events-none'
          />
        </div>
      </Tooltip>
    </ClipMenuItem>
  );
});

export const PinToProfileItem = observer(() => {
  const clip = useClipContext();
  const { clips, session } = useStores();
  const { openModalWithData } = useModalContext();
  const handleClick = useCallback(async () => {
    logWebUserEvent({
      actionName: 'SongMenuPinToProfileClicked',
      context: {
        clipId: clip?.id,
        isPinned: !clips.isClipPinned(clip.id),
      },
    });
    await handlePinOrConfirm({ clip, clips, openModalWithData, session });
  }, [clip, clips, openModalWithData, session]);

  const hasPinFeature = session.flags?.['profile-pins'];
  const isOwner = session.user?.id === clip?.user_id;
  const isHidden =
    !hasPinFeature || !isOwner || isUnpublishableUploadClip(clip);

  if (isHidden) return null;

  return (
    <ClipMenuItem keepMenusOpen icon={<PinIcon />} onClick={handleClick}>
      <div className='flex w-full flex-row items-center gap-2'>
        <span>
          {clips?.isClipPinned(clip.id)
            ? 'Unpin from Profile'
            : 'Pin to Profile'}
        </span>
        <div className='ml-auto'>
          <Switch
            small
            checked={clips?.isClipPinned(clip.id)}
            containerClassName='pointer-events-none'
          />
        </div>
      </div>
    </ClipMenuItem>
  );
});

export const ShowInFeedItem = observer(() => {
  const clip = useClipContext();
  const { clips, session } = useStores();
  const statsigClient = useStatsigClient();

  const handleClick = useCallback(async () => {
    const currentlyShowing = clip.metadata?.opt_out_video_cover_hook !== true;

    await clips.toggleVideoHookFeedVisibility(clip.id, !currentlyShowing);

    toast({
      title: `Video cover ${!currentlyShowing ? 'will be shown' : 'will be hidden'} in Hooks Feed.`,
      status: 'info',
      duration: 2000,
      isClosable: true,
    });
    logWebUserEvent({
      actionName: 'SongMenuShowInFeedToggled',
      context: {
        clipId: clip?.id,
        showInFeed: !currentlyShowing,
      },
    });
  }, [clip, clips]);

  const hooksEnabled = statsigClient.checkGate('web-hooks-2025');
  const isOwner = session.user?.id === clip?.user_id;
  const hasVideoHook = clip.is_public && !!clip.video_cover_url;
  const isHidden = !hooksEnabled || !isOwner || !hasVideoHook;

  if (isHidden) return null;

  return (
    <ClipMenuItem
      keepMenusOpen
      icon={<HooksIcon />}
      onClick={handleClick}
      enableForIncompleteClips
    >
      <div className='flex w-full flex-row items-center gap-2'>
        <span>Show in Hooks Feed</span>
        <div className='ml-auto'>
          <Switch
            small
            checked={clip.metadata?.opt_out_video_cover_hook !== true}
            containerClassName='pointer-events-none'
          />
        </div>
      </div>
    </ClipMenuItem>
  );
});

export const SpeedItem = () => {
  const clip = useClipContext();
  const { genForm } = useStores();
  const router = useRouter();
  const pathname = usePathname();
  const adjustSpeed = useClipAction(adjustClipSpeed);
  const expandCreatePanel = useExpandCreatePanel();
  const isComplete = useClipIsComplete();

  const handleClick = useCallback(() => {
    if (pathname !== '/create' && pathname !== '/studio') {
      router.push('/create?remix_clip=' + clip.id + '&remix_type=speed');
    }
    genForm.shouldOpenMobileCreate = true;
    adjustSpeed();
    expandCreatePanel();
  }, [genForm, adjustSpeed, expandCreatePanel, pathname, router, clip.id]);

  // Hide if clip is not complete
  if (!isComplete) return null;

  // Disable for uploads or clips with vocals
  const isDisabled =
    clip?.metadata?.type === 'upload' || !!clip?.metadata?.has_vocal;

  return (
    <ConditionalTooltip
      isTooltipEnabled={isDisabled}
      label='Cannot adjust speed of uploaded audio and its derivatives'
    >
      <ClipMenuItem
        icon={<SpeedIcon />}
        onClick={withWebUserEvent(
          {
            actionName: 'SongMenuRemixAdjustSpeedClicked',
            context: {
              clipId: clip?.id,
            },
          },
          handleClick
        )}
        disabled={isDisabled}
        aria-label='Adjust Speed'
      >
        Adjust Speed
      </ClipMenuItem>
    </ConditionalTooltip>
  );
};

export const MoveToTrashItem = () => {
  const clip = useClipContext();
  const { clips, session } = useStores();
  const selectedClipIds = useContextSelector(
    MultiSelectContext,
    (ctx) => ctx.selectedClipIds
  );
  const { moveToTrash } = useTrashActions();

  const handleClick = useCallback(
    async (e: React.MouseEvent<HTMLElement>) => {
      e.stopPropagation();
      e.preventDefault();

      const clipIds = selectedClipIds.length > 0 ? selectedClipIds : [clip.id];

      if (!clipIds.length) {
        return;
      }

      await moveToTrash(clipIds);
    },
    [clip, selectedClipIds, moveToTrash]
  );

  // Check if all selected clips (or single clip) are owned by user and not already trashed
  const clipIds = selectedClipIds.length > 0 ? selectedClipIds : [clip.id];
  const allSelectedClipsOwnedByUser = clipIds.every((id) => {
    const c = clips.clipById[id];
    return c?.user_id === session.user?.id;
  });
  const selectedClipsIsTrashedState = clipIds.some((id) => {
    const c = clips.clipById[id];
    return !!c?.is_trashed;
  });

  const isHidden = !allSelectedClipsOwnedByUser || selectedClipsIsTrashedState;

  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<TrashIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuMoveToTrashClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Move to Trash
    </ClipMenuItem>
  );
};

export const RestoreToLibraryItem = () => {
  const clip = useClipContext();
  const { clips, session } = useStores();
  const selectedClipIds = useContextSelector(
    MultiSelectContext,
    (ctx) => ctx.selectedClipIds
  );
  const { restoreFromTrash } = useTrashActions();

  const handleClick = useCallback(async () => {
    const clipIds = selectedClipIds.length > 0 ? selectedClipIds : [clip.id];
    await restoreFromTrash(clipIds);
  }, [clip, selectedClipIds, restoreFromTrash]);

  // Check if all selected clips (or single clip) are owned by user and currently trashed
  const clipIds = selectedClipIds.length > 0 ? selectedClipIds : [clip.id];
  const allSelectedClipsOwnedByUser = clipIds.every((id) => {
    const clip = clips.clipById[id];
    return clip?.user_id === session.user?.id;
  });
  const selectedClipsIsTrashedState = clipIds.every((id) => {
    const clip = clips.clipById[id];
    return !!clip?.is_trashed;
  });

  const isHidden = !allSelectedClipsOwnedByUser || !selectedClipsIsTrashedState;

  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<EditUndoIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuRestoreToLibraryClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Restore to Library
    </ClipMenuItem>
  );
};

export const RemasterItem = () => {
  const clip = useClipContext();
  const { session, menus } = useStores();
  const { openModalWithData } = useModalContext();
  const isClipComplete = useClipIsComplete();

  const handleClick = useCallback(() => {
    if (!isClipComplete) {
      return;
    }

    const canRemaster = isFeatureEnabledForPlan(session, PlanFeature.Remaster);

    if (!canRemaster) {
      menus.setCurrentUpsellFeature(FeatureKey.REMASTER);
      menus.openModal(ModalTypes.UPSELL_MODAL);
      return;
    }

    openModalWithData(ModalTypes.REMASTER_MODAL, { clipId: clip.id });
  }, [clip.id, isClipComplete, openModalWithData, session, menus]);

  const isHidden =
    !!clip.metadata?.infill ||
    !session.flags?.['remaster-modal'] ||
    !isClipComplete ||
    clip.is_trashed ||
    clip.user_id !== session.user?.id;

  if (isHidden) return null;

  const canRemaster = isFeatureEnabledForPlan(session, PlanFeature.Remaster);
  const isTooLong = (clip.metadata?.duration ?? 0) > 960;
  const isDisabled = !canRemaster || isTooLong;

  return (
    <ConditionalTooltip
      isTooltipEnabled={isTooLong}
      label='Cannot remaster songs longer than 16 minutes'
    >
      <ClipMenuItem
        icon={<CreateIcon />}
        onClick={withWebUserEvent(
          {
            actionName: 'SongMenuRemasterClicked',
            context: {
              clipId: clip?.id,
            },
          },
          handleClick
        )}
        disabled={isDisabled}
        enableForIncompleteClips={false}
        renderTags={() => (
          <Tag className='ml-2' variant={TagVariant.Pro}>
            Pro
          </Tag>
        )}
      >
        Remaster
      </ClipMenuItem>
    </ConditionalTooltip>
  );
};

export const ClipRemixItem = () => {
  const clip = useClipContext();
  const { session, genForm, project } = useStores();
  const router = useRouter();
  const pathname = usePathname();
  const isClipComplete = useClipIsComplete();

  // Get state and modal setters
  const addCondition = useContextSelector(
    CreateFormContext,
    (context) => context.addCondition
  );
  const expandCreatePanel = useExpandCreatePanel();

  // default to remix cover
  const handleClick = useCallback(async () => {
    await project.setCurrentProjectToClipProject(clip);

    if (pathname !== '/create' && pathname !== '/studio') {
      router.push('/create?remix_clip=' + clip.id + '&remix_type=cover');
    }
    genForm.shouldOpenMobileCreate = true;

    // Use unified addCondition - it will handle the modal logic
    await addCondition(clip.id, AddConditionType.COVER);
    expandCreatePanel();
  }, [
    clip,
    expandCreatePanel,
    addCondition,
    genForm,
    pathname,
    project,
    router,
  ]);

  const isOwnSong = clip.user_id === session.userId;
  // For user's own songs, hide
  // For non-owned songs, only show if can_remix is true
  if (
    isOwnSong ||
    (!isOwnSong && clip.metadata?.can_remix !== true) ||
    !!clip?.is_trashed
  ) {
    return null;
  }

  // Compute disabled state
  const isDisabled = !clip?.status || !isClipComplete || isSunoShort(clip);

  const getTooltipMessage = () => {
    if (isSunoShort(clip)) return 'Not available for Suno Scenes';
    if (!clip?.status) return "Can't remix an invalid clip";
    if (!clip.metadata?.can_remix)
      return 'The creator has disabled remixing for this song';
    return '';
  };

  const tooltipMessage = getTooltipMessage();

  return (
    <ConditionalTooltip
      isTooltipEnabled={!!tooltipMessage}
      label={tooltipMessage}
    >
      <ClipMenuItem
        icon={<RemixIcon />}
        onClick={withWebUserEvent(
          {
            actionName: 'SongMenuRemixButtonClicked',
            context: {
              clipId: clip?.id,
            },
          },
          handleClick
        )}
        className='rounded-sm !bg-gray-950 text-black hover:!bg-strawberry-600 hover:!text-gray-950'
        disabled={isDisabled}
        renderTags={() => (
          <Tag className='ml-2 uppercase' variant={TagVariant.New}>
            New
          </Tag>
        )}
      >
        Remix
      </ClipMenuItem>
    </ConditionalTooltip>
  );
};

export const DescribeClipItem = () => {
  const clip = useClipContext();
  const { session } = useStores();

  const handleClick = useCallback(() => {
    window.open(`/b-side/describe-clip?clipId=${clip?.id}`, '_blank');
  }, [clip]);

  // Only staff or staging users can see this
  if (!isStaff(session) && isProd) return null;

  // Only owner can click this button
  const isDisabled = clip?.user_id !== session.user?.id;

  return (
    <ClipMenuItem
      icon={<TicketIcon />}
      onClick={handleClick}
      disabled={isDisabled}
    >
      Describe Clip
    </ClipMenuItem>
  );
};

export const RemoveFromPlaylistItem = () => {
  const clip = useClipContext();
  const { session } = useStores();
  const { onRemoveFromPlaylist } = usePlaylistActions();

  const handleClick = useCallback(() => {
    if (onRemoveFromPlaylist) {
      onRemoveFromPlaylist();
    }
  }, [onRemoveFromPlaylist]);

  // Only show if onRemoveFromPlaylist callback is provided
  if (!onRemoveFromPlaylist) return null;

  return (
    <ClipMenuItem
      icon={<MinusIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuRemoveFromPlaylistClicked',
          context: {
            clipId: clip?.id,
            isUserSongOwner:
              session?.userId !== undefined &&
              clip?.user_id === session?.userId,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Remove from Playlist
    </ClipMenuItem>
  );
};

export const DeletePermanentlyItem = () => {
  const clip = useClipContext();
  const { clips, session } = useStores();
  const arrayContainingClipId = useMemo(() => [clip.id], [clip.id]);
  const selectedClipIds = useContextSelector(MultiSelectContext, (ctx) =>
    ctx.selectedClipIds.length === 0
      ? arrayContainingClipId
      : ctx.selectedClipIds
  );
  const { deletePermanently } = useDeletePermanently();

  const handleClick = useCallback(() => {
    deletePermanently(selectedClipIds);
  }, [deletePermanently, selectedClipIds]);

  // Check if all selected clips (or single clip) are owned by user, trashed, and complete
  const clipIds = selectedClipIds.length > 0 ? selectedClipIds : [clip.id];
  const allSelectedClipsOwnedByUser = clipIds.every((id) => {
    const c = clips.clipById[id];
    return c?.user_id === session.user?.id;
  });
  const selectedClipsIsTrashedState = clipIds.every((id) => {
    const c = clips.clipById[id];
    return !!c?.is_trashed;
  });
  const allSelectedClipsComplete = clipIds.every((id) => {
    const c = clips.clipById[id];
    return c?.status === 'complete';
  });

  const isHidden = !(
    allSelectedClipsOwnedByUser &&
    selectedClipsIsTrashedState &&
    allSelectedClipsComplete
  );

  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<SkullIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuDeletePermanentlyClicked',
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
      enableForIncompleteClips
    >
      Delete Permanently
    </ClipMenuItem>
  );
};

export const NotInterestedItem = () => {
  const clip = useClipContext();
  const { clips, session, playbar } = useStores();
  const pathname = usePathname();
  const menuContext = useMenuContext();

  const handleClick = useCallback(async () => {
    const isNotInterested = !clips.notInterestedById[clip.id];

    logWebUserEvent({
      actionName: 'SongMenuNotInterestedClicked',
      context: {
        clipId: clip.id,
        isNotInterested: isNotInterested,
      },
    });

    try {
      await clips.updateSongNotInterested(clip.id, isNotInterested);
      if (isNotInterested) {
        if (
          playbar.isPlaying &&
          playbar.clip?.id === clip.id &&
          playbar.canStepForward()
        ) {
          playbar.stepForward();
        }
        toast({
          duration: 2500,
          isClosable: true,
          render: ({ onClose }) => (
            <ToastWithUndo
              content={`${clip.title || 'Untitled'} will be hidden in future recommendations`}
              onUndo={async () => {
                await clips.updateSongNotInterested(clip.id, false);
              }}
              onClose={onClose}
            />
          ),
        });
      } else {
        toast({
          title: `${clip.title || 'Untitled'} will be shown in future recommendations`,
          duration: 4000,
          isClosable: true,
        });
      }
    } catch (error) {
      toast({
        title: 'Error updating song preferences',
        description: 'Please try again later.',
        status: 'error',
        duration: 5000,
        isClosable: true,
      });
    }
  }, [clip, clips, playbar]);

  // Visibility logic matching original implementation
  const sectionName = menuContext?.sectionName;
  const isHidden =
    !session.user ||
    (!pathname.includes('/on_repeat') &&
      (!sectionName ||
        (!!sectionName &&
          !['new_songs_for_you', 'featured_feed_for_you'].includes(
            sectionName
          ))));

  if (isHidden) return null;

  const isNotInterested = clips.notInterestedById[clip.id];

  return (
    <ClipMenuItem
      icon={<ProhibitionIcon />}
      onClick={handleClick}
      enableForIncompleteClips
      aria-label='Not Interested'
      className={
        isNotInterested ? 'bg-foreground-primary text-background-primary' : ''
      }
    >
      Not Interested
    </ClipMenuItem>
  );
};
export const MarketplaceCreateProjectItem = () => {
  const clip = useClipContext();
  const { session } = useStores();
  const { openModalWithData } = useModalContext();
  const statsigClient = useStatsigClient();
  const isClipComplete = useClipIsComplete();

  const marketplaceEnabled = statsigClient.checkGate('enable-marketplace');

  const handleClick = useCallback(() => {
    openModalWithData(ModalTypes.MARKETPLACE_CREATE_PROJECT, {
      clipId: clip.id,
      clipTitle: clip?.title || 'Untitled',
      clipUrl: clip?.audio_url || '',
    });
  }, [clip, openModalWithData]);

  const isHidden =
    !session.user ||
    !marketplaceEnabled ||
    session.user?.id !== clip?.user_id ||
    !isClipComplete ||
    !!clip?.is_trashed;

  if (isHidden) return null;

  return (
    <ClipMenuItem
      icon={<UserGroupIcon />}
      onClick={withWebUserEvent(
        {
          actionName: 'SongMenuCreateMarketplaceProjectClicked' as any,
          context: {
            clipId: clip?.id,
          },
        },
        handleClick
      )}
      enableForIncompleteClips={false}
    >
      Hire an Editor
    </ClipMenuItem>
  );
};
