import { omit } from 'lodash-es';
import { toJS } from 'mobx';
import { useCallback } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import { isSunoShort } from '@/components/song/songUtils';
import Tag from '@/components/tag/Tag';
import { useModalContext } from '@/context/ModalContext';
import { useBreakpointMd } from '@/hooks/useBreakpoint';
import { useContextSelector } from '@/hooks/useContextSelector';
import {
  BugIcon,
  CreateIcon,
  DownloadIcon,
  EyeIcon,
  PersonaSmileIcon,
  ShareArrowIcon,
  SkullIcon,
  SlidersIcon,
  TriangleRightIcon,
  VinylIcon,
} from '@/icons';
import {
  Clip,
  canAddInstrumental,
  canAddVocal,
  canRemix,
} from '@/state/clipStore';
import {
  DEFAULT_AUDIO_WEIGHT_VALUE,
  DEFAULT_CREATE_CONTROL_VALUE,
} from '@/utils/constants';

import { Props as ButtonProps } from '../button/Button';
import {
  ContextMenuGroup,
  ContextMenuItem,
  ContextMenuItemMainText,
  ContextMenuItemSubtext,
  ContextMenuTrigger,
} from '../contextMenu/ContextMenu';
import StudioContext from '../studio/StudioContext';
import {
  ClipContextProvider,
  useClipContext,
  useNullableClipContext,
} from './ClipContext';
import {
  AddInstrumentalItem,
  AddToPlaylistItem,
  AddToQueueItem,
  AddVocalItem,
  AllowCommentsItem,
  AllowRemixesItem,
  ClipMenuItem,
  ClipRadioItem,
  ConfirmSectionItem,
  CopyLinkAtCurrentTimeItem,
  CopyLinkItem,
  CoverItem,
  CreateVariationsItem,
  CropItem,
  DeletePermanentlyItem,
  DescribeClipItem,
  DownloadMP3Item,
  DownloadSamplePackItem,
  DownloadVideoItem,
  DownloadWAVItem,
  ExtendItem,
  GenerateAndDownloadVideoItem,
  GenerateCoverArtItem,
  GetFullSongItem,
  GetStemsItem,
  MakePersonaItem,
  MarketplaceCreateProjectItem,
  MoveToTrashItem,
  MoveToWorkspaceItem,
  MultiSelectAddToQueueItem,
  NotInterestedItem,
  OpenInChatItem,
  OpenInStudioItem,
  PinToProfileItem,
  PublishItem,
  RemasterItem,
  RemasterV4Item,
  RemasterV4_5PlusItem,
  RemoveFromPlaylistItem,
  ReplaceSectionItem,
  ReportBugItem,
  ReportCopyrightItem,
  ReportInappropriateItem,
  RestoreToLibraryItem,
  ReuseStylesLyricsItem,
  ShareAssetItem,
  ShareToItem,
  ShareWithFriendsItem,
  ShowInFeedItem,
  SongDetailsItem,
  SpeedItem,
  UsePersonaItem,
} from './ClipMenuItems';
import { OpenInEditorItem } from './ClipMenuItems';
import MultiSelectContext from './MultiSelectContext';
import { useIsOwnClip, useIsStaff } from './clipHelpers';

const supportsHover = () => {
  if (typeof window === 'undefined') return false;
  return window.matchMedia('(hover: hover)').matches;
};

export const ClipSubmenuTrigger = (props: ButtonProps) => {
  return (
    <ClipMenuItem
      {...(omit(props, 'children') as ButtonProps)}
      keepMenusOpen
      enableForIncompleteClips
    >
      <ContextMenuItemMainText>{props.children}</ContextMenuItemMainText>
      <ContextMenuItemSubtext>
        <TriangleRightIcon className='-mr-2 text-foreground-primary' />
      </ContextMenuItemSubtext>
    </ClipMenuItem>
  );
};

export const RemixEditMenuContents = () => {
  const clip = useClipContext();
  const isOwnClip = useIsOwnClip(clip);

  return (
    <>
      {isOwnClip && (
        <ContextMenuGroup>
          <OpenInStudioItem />
          <OpenInEditorItem />
          <OpenInChatItem />
        </ContextMenuGroup>
      )}
      <ContextMenuGroup>
        <CoverItem />
        <ExtendItem />
        <SpeedItem />
        <DescribeClipItem />
        <ReuseStylesLyricsItem />
        {isOwnClip && (
          <>
            <CropItem />
            <ReplaceSectionItem />
            {canAddVocal(clip) && <AddVocalItem />}
            {canAddInstrumental(clip) && <AddInstrumentalItem />}
          </>
        )}
      </ContextMenuGroup>
    </>
  );
};

export const CreateMenuContents = () => {
  const clip = useClipContext();
  const isOwnClip = useIsOwnClip(clip);
  return (
    <>
      {isOwnClip && <MakePersonaItem />}
      <UsePersonaItem />
      {isOwnClip && (
        <>
          <GetFullSongItem />
          <ConfirmSectionItem />
          <RemasterItem />
          <RemasterV4_5PlusItem />
          <RemasterV4Item />
          <CreateVariationsItem />
        </>
      )}
      <ClipRadioItem />
    </>
  );
};

export const PermissionsMenuContents = () => {
  return (
    <>
      <AllowCommentsItem />
      <AllowRemixesItem />
      <PinToProfileItem />
      <ShowInFeedItem />
    </>
  );
};

export const ShareMenuContents = () => {
  return (
    <>
      <CopyLinkItem />
      <CopyLinkAtCurrentTimeItem />
      <ShareToItem />
      <ShareWithFriendsItem />
    </>
  );
};

export const DownloadMenuContents = () => {
  return (
    <>
      <DownloadMP3Item />
      <DownloadWAVItem />
      <DownloadSamplePackItem />
      <DownloadVideoItem />
      <GenerateAndDownloadVideoItem />
      <ShareAssetItem />
    </>
  );
};

export const ReportMenuContents = () => {
  const clip = useClipContext();
  const own = useIsOwnClip(clip);
  return (
    <>
      {own && <ReportBugItem />}
      <ReportInappropriateItem />
      <ReportCopyrightItem />
    </>
  );
};

export const TrashedMenuContents = () => {
  return (
    <>
      <ContextMenuGroup>
        <RestoreToLibraryItem />
        <ContextMenuTrigger
          openOnMouseOver={supportsHover()}
          placement='right'
          ButtonComponent={(props) => (
            <ClipSubmenuTrigger {...props} icon={<BugIcon />}>
              Report
            </ClipSubmenuTrigger>
          )}
          ContentsComponent={ReportMenuContents}
        />
        <DeletePermanentlyItem />
      </ContextMenuGroup>
    </>
  );
};

export const TrashedMultiSelectMenuContents = () => {
  return (
    <>
      <RestoreToLibraryItem />
      <DeletePermanentlyItem />
    </>
  );
};

export const MultiSelectMenuContents = () => {
  const clip = useClipContext();
  const isOwnClip = useIsOwnClip(clip);
  return (
    <>
      <MultiSelectAddToQueueItem />
      <AddToPlaylistItem />
      <RemoveFromPlaylistItem />
      {isOwnClip && <MoveToWorkspaceItem />}
      <MoveToTrashItem />
    </>
  );
};

export const SingleUntrashedMoreMenuContents = () => {
  const clip = useClipContext();
  const isRemixable = canRemix(clip);
  const isOwnClip = useIsOwnClip(clip);
  const hasStudioContext = useContextSelector(StudioContext, (ctx) => !!ctx);
  const isStaff = useIsStaff();
  const isOwnOrRemixable = isOwnClip || isRemixable;
  const isMobile = !useBreakpointMd();
  const isSunoScene = isSunoShort(clip);
  const isTrashed = clip.is_trashed;
  const { session } = useStores();
  const isLoggedIn = !!session.user?.id;

  return (
    <>
      <ContextMenuGroup>
        {isOwnOrRemixable && !isTrashed && (
          <ContextMenuTrigger
            openOnMouseOver={supportsHover()}
            placement='right'
            ButtonComponent={(props) => (
              <ClipSubmenuTrigger {...props} icon={<CreateIcon />}>
                Remix/Edit
              </ClipSubmenuTrigger>
            )}
            ContentsComponent={RemixEditMenuContents}
          />
        )}
        {isLoggedIn && !isSunoScene && !!clip.status && !isTrashed && (
          <ContextMenuTrigger
            openOnMouseOver={supportsHover()}
            placement='right'
            ButtonComponent={(props) => (
              <ClipSubmenuTrigger {...props} icon={<CreateIcon />}>
                Create
              </ClipSubmenuTrigger>
            )}
            ContentsComponent={CreateMenuContents}
          />
        )}
        {isOwnClip && <GetStemsItem />}
        {isOwnClip && <MarketplaceCreateProjectItem />}
        <AddToQueueItem />
        <AddToPlaylistItem />
        <RemoveFromPlaylistItem />
        {isOwnClip && <MoveToWorkspaceItem />}
        {hasStudioContext && !isMobile && (
          <ClipMenuItem
            icon={<VinylIcon />}
            href={`/song/${clip.id}`}
            target='_blank'
          >
            Open Song in New Tab
          </ClipMenuItem>
        )}
      </ContextMenuGroup>
      {isOwnClip && !isTrashed && (
        <ContextMenuGroup>
          <PublishItem />
          <SongDetailsItem />
          <GenerateCoverArtItem />
          <ContextMenuTrigger
            openOnMouseOver={supportsHover()}
            placement='right'
            ButtonComponent={(props) => (
              <ClipSubmenuTrigger {...props} icon={<EyeIcon />}>
                Visibility &amp; Permissions
              </ClipSubmenuTrigger>
            )}
            ContentsComponent={PermissionsMenuContents}
          />
        </ContextMenuGroup>
      )}
      {!isTrashed && (
        <ContextMenuGroup>
          <ContextMenuTrigger
            openOnMouseOver={supportsHover()}
            placement='right'
            ButtonComponent={(props) => (
              <ClipSubmenuTrigger {...props} icon={<ShareArrowIcon />}>
                Share
              </ClipSubmenuTrigger>
            )}
            ContentsComponent={ShareMenuContents}
          />

          {(isOwnClip || isStaff) && !isTrashed && (
            <ContextMenuTrigger
              openOnMouseOver={supportsHover()}
              placement='right'
              ButtonComponent={(props) => (
                <ClipSubmenuTrigger {...props} icon={<DownloadIcon />}>
                  Download
                </ClipSubmenuTrigger>
              )}
              ContentsComponent={DownloadMenuContents}
            />
          )}
        </ContextMenuGroup>
      )}
      <ContextMenuGroup>
        <NotInterestedItem />
        <ContextMenuTrigger
          openOnMouseOver={supportsHover()}
          placement='right'
          ButtonComponent={(props) => (
            <ClipSubmenuTrigger {...props} icon={<BugIcon />}>
              Report
            </ClipSubmenuTrigger>
          )}
          ContentsComponent={ReportMenuContents}
        />
        {isOwnClip && <MoveToTrashItem />}
      </ContextMenuGroup>
    </>
  );
};

const getClipJsonTitle = (clip: Clip) => {
  const explicitTitle = clip.title?.trim();
  return explicitTitle || clip.id;
};

const StaffMenuContents = () => {
  const clip = useNullableClipContext();
  const { openModalWithData } = useModalContext();

  const handleOpenClipJson = useCallback(() => {
    if (!clip) return;
    openModalWithData(ModalTypes.CLIP_JSON, {
      clipId: clip.id,
      clipTitle: getClipJsonTitle(clip),
      clipJson: JSON.stringify(toJS(clip), null, 2),
    });
  }, [clip, openModalWithData]);

  if (!clip) {
    return null;
  }

  const controlSliders = clip.metadata?.control_sliders;
  const usesSliders =
    (controlSliders?.audio_weight !== undefined &&
      controlSliders?.audio_weight !== DEFAULT_AUDIO_WEIGHT_VALUE) ||
    (controlSliders?.style_weight !== undefined &&
      controlSliders?.style_weight !== DEFAULT_CREATE_CONTROL_VALUE) ||
    (controlSliders?.weirdness_constraint !== undefined &&
      controlSliders?.weirdness_constraint !== DEFAULT_CREATE_CONTROL_VALUE);
  return (
    <>
      {usesSliders && (
        <>
          <ContextMenuItem
            icon={<SkullIcon />}
            className='py-0 pt-2 text-accent-error'
          >
            Uses Sliders!
          </ContextMenuItem>
          {Object.entries(controlSliders).map(([key, value]) => (
            <ContextMenuItem
              icon={<SlidersIcon />}
              key={key}
              className='py-0 text-accent-error'
            >
              &nbsp;&nbsp;&nbsp;&nbsp;{key}: {value}
            </ContextMenuItem>
          ))}
        </>
      )}
      {!usesSliders && (
        <ContextMenuItem icon={<PersonaSmileIcon />}>
          No Sliders
        </ContextMenuItem>
      )}
      <ClipMenuItem
        icon={<span className='mr-1 ml-2'>🤓</span>}
        onClick={handleOpenClipJson}
      >
        Clip JSON
      </ClipMenuItem>
    </>
  );
};

const StaffSubmenu = () => {
  return (
    <ContextMenuGroup>
      <ContextMenuTrigger
        openOnMouseOver={supportsHover()}
        placement='right'
        ButtonComponent={(props) => (
          <ClipSubmenuTrigger
            {...props}
            icon={<SkullIcon />}
            className='text-accent-brand'
          >
            Noggin Mode <Tag>Staff</Tag>
          </ClipSubmenuTrigger>
        )}
        ContentsComponent={StaffMenuContents}
      />
    </ContextMenuGroup>
  );
};

export const MoreMenuContents = () => {
  const isStaff = useIsStaff();
  const clip = useNullableClipContext();
  const isMultiSelecting = useContextSelector(
    MultiSelectContext,
    (ctx) => ctx.selectedClipIds.length > 0
  );
  if (!clip) return null;
  const isTrashed = clip.is_trashed;
  return (
    <ClipContextProvider clip={clip}>
      <div className='contents'>
        {isTrashed && isMultiSelecting ? (
          <TrashedMultiSelectMenuContents />
        ) : isMultiSelecting ? (
          <MultiSelectMenuContents />
        ) : isTrashed ? (
          <TrashedMenuContents />
        ) : (
          <SingleUntrashedMoreMenuContents />
        )}
        {isStaff && <StaffSubmenu />}
      </div>
    </ClipContextProvider>
  );
};
