import styled from '@emotion/styled';
import clsx from 'clsx';
import { omit } from 'lodash-es';
import { autorun, toJS } from 'mobx';
import { observer } from 'mobx-react-lite';
import { usePathname } from 'next/navigation';
import React, {
  ComponentProps,
  HTMLProps,
  PropsWithChildren,
  ReactNode,
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import { SkeletonBone } from '@/components/layout/Skeleton';
import PokemonV2 from '@/components/pokemon/PokemonV2';
import { SongMenuWithContext } from '@/components/song/newActions/SongMenuWithContext';
import { toast } from '@/components/toast/Toast';
import useClip from '@/hooks/useClip';
import {
  BookmarkOutlineIcon,
  DownloadIcon,
  MoreVerticalIcon,
  PauseIcon,
  PlayIcon,
  PulsingLinesIcon,
  ShareArrowIcon,
  ThumbsDownIcon,
  ThumbsUpIcon,
} from '@/icons';
import { useApiClient } from '@/lib/apiClient';
import { Clip, isDisliked, isLiked } from '@/state/clipStore';
import { PlayContext, autoAssignPlayContextIndex } from '@/state/queueStore';
import { getClipDisplayTags, getClipTitle } from '@/utils/clip';
import { FALLBACK_IMAGE_URL, SMALL_IMAGE } from '@/utils/constants';
import { downloadClipAudio, shareClip } from '@/utils/download';
import { eventLogger } from '@/utils/event-logger';
import { ActionName } from '@/utils/event-names';
import { encodeTimeFormat } from '@/utils/utils';

import {
  ContextMenuItem,
  ContextMenuTrigger,
} from '../contextMenu/ContextMenu';
import { AvatarMaskShape } from '../image/Avatar';
import ImageWithFallback from '../image/ImageWithFallback';
import Link from '../link/Link';
import { tagsToArray, tagsToNegativeTags } from '../song/songUtils';
import Switch from '../switch/Switch';
import MusicStyleTags from '../tag/MusicStyleTags';

export type ClipChangeCallback = (
  clipBefore: Clip | undefined,
  clipAfter: Clip | undefined
) => void;
export const ClipWatcherContext = createContext<ClipChangeCallback>(() => {});

const useClipContext = (
  clip: Clip | undefined,
  playContext: PlayContext | ((clip: Clip) => void)
) => {
  const {
    playbar: playbarStore,
    clips: clipsStore,
    queue: queueStore,
    session: sessionStore,
  } = useStores();
  const pathname = usePathname();
  const clipWatcher = useContext(ClipWatcherContext);

  const clipBeforeRef = useRef<Clip | undefined>(undefined);
  useEffect(() => {
    if (clip) clipBeforeRef.current = toJS(clip);
  }, [clip]);

  const clipChanged = useCallback(() => {
    if (clipWatcher) clipWatcher(clipBeforeRef.current, clip);
    clipBeforeRef.current = toJS(clip);
  }, [clipWatcher, clip]);

  useEffect(() => {
    return autorun(() => clipChanged());
  }, [clip, clipChanged]);

  const [hasPlayed, setHasPlayed] = useState(false);

  const onPlayClick = useCallback(
    (e: React.MouseEvent<HTMLElement>) => {
      e.stopPropagation();
      if (clip) {
        if (typeof playContext === 'function') {
          playContext(clip);
        } else {
          const wasPlaying =
            playbarStore.isPlaying && playbarStore.clip?.id === clip.id;
          if (playbarStore.clip?.id === clip.id) {
            playbarStore.togglePlay();
          } else {
            playbarStore.playClip(clip);
            queueStore.setPlayContext(
              autoAssignPlayContextIndex(playContext, clip.id)
            );
          }
          if (!wasPlaying && !hasPlayed) {
            setHasPlayed(true);
            clip.play_count = (clip.play_count || 0) + 1;
            clipChanged();
          }
        }
      }
    },
    [clip, playbarStore, hasPlayed]
  );

  const onLikeClick = useCallback(
    (e: React.MouseEvent<HTMLElement>) => {
      e.stopPropagation();
      if (clip) {
        clipsStore.likeClip(clip.id, !isLiked(clip));
        clipChanged();
      }
    },
    [clip, clipsStore]
  );

  const onDislikeClick = useCallback(
    (e: React.MouseEvent<HTMLElement>) => {
      e.stopPropagation();
      if (clip) {
        clipsStore.dislikeClip(clip.id, !isDisliked(clip));
        clipChanged();
      }
    },
    [clip, clipsStore]
  );

  const onShareClick = useCallback(
    (e: React.MouseEvent<HTMLElement>) => {
      e.stopPropagation();
      if (clip) {
        shareClip(clipsStore.apiClient, clip);
      }
    },
    [clip, clipsStore]
  );

  const onPublicToggle = useCallback(async () => {
    const isPublic = clip?.is_public;
    if (!clip?.id) {
      return;
    }
    try {
      await clipsStore.setClipVisibility({
        clipId: clip?.id,
        isPublic: !isPublic,
      });
      toast({
        title: `Clip is now ${!isPublic ? 'public' : 'link only'}.`,
        duration: 2000,
        isClosable: true,
      });
      if (!isPublic) {
        clipsStore.getVideoGenStatus({ clip: clip });
      }
      eventLogger.logAudioActionEvent(
        false,
        !isPublic ? ActionName.makePublic : ActionName.makePrivate,
        clip,
        sessionStore,
        pathname
      );
    } catch (error) {
      console.error('Failed to update clip visibility:', error);
    }
  }, [clip, clipsStore]);

  const inPlaybar = useMemo(() => {
    return Boolean(playbarStore.clip && playbarStore.clip?.id === clip?.id);
  }, [playbarStore.clip?.id, clip?.id]);

  const playing = useMemo(() => {
    return Boolean(inPlaybar && playbarStore.isPlaying);
  }, [inPlaybar, playbarStore.isPlaying]);

  const allowReactions = !!clip?.audio_url;
  const allowPlayback = !!clip?.audio_url;

  return useMemo(
    () => ({
      onPlayClick,
      onLikeClick,
      onDislikeClick,
      onShareClick,
      onPublicToggle,
      clip,
      playing,
      inPlaybar,
      allowReactions,
      allowPlayback,
    }),
    [
      onPlayClick,
      onLikeClick,
      onDislikeClick,
      onShareClick,
      onPublicToggle,
      clip,
      playing,
      inPlaybar,
      allowReactions,
      allowPlayback,
    ]
  );
};

export const ClipContext = createContext<ReturnType<typeof useClipContext>>({
  clip: undefined,
  playing: false,
  inPlaybar: false,
  onPlayClick: () => {},
  onLikeClick: () => {},
  onDislikeClick: () => {},
  onShareClick: () => {},
  onPublicToggle: async () => {},
  allowReactions: false,
  allowPlayback: false,
});

const NotificationDot = styled.div`
  z-index: 2;
  position: absolute;
  top: 50%;
  margin-top: -4px;
  left: 0;
  width: 8px;
  height: 8px;
  background-color: rgb(var(--rgb-strawberry-600) / var(--tw-bg-opacity, 1));
  border-radius: 100px;
`;

const ArtworkContainer = styled.div`
  height: 100%;
  width: auto;
  aspect-ratio: 2/3;
  position: relative;
  background-color: rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  ${({ onClick }) => onClick && 'cursor: pointer;'}
`;

// const ArtworkUpper = styled.div`
//   position: absolute;
//   top: 0;
//   left: 0;
//   right: 0;
//   z-index: 1;
// `;

const ArtworkLower = styled.div`
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 3;
  display: flex;
  flex-direction: row-reverse;
`;

const ArtworkMiddle = styled.div`
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
`;

const ArtworkImg = styled.img`
  height: 100%;
  width: 100%;
  object-fit: cover;
  border-radius: 4px;
`;

const Row = styled.div`
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
`;

const Column = styled.div`
  display: flex;
  flex-direction: column;
  gap: 5px;

  [data-selected] & {
    filter: brightness(1);
  }
`;

const PrimaryText = styled.span`
  font-size: 14px;
  font-weight: 500;
  color: white;
  ${({ onClick }) => onClick && 'cursor: pointer;'}
  &:hover {
    ${({ onClick }) => onClick && 'color: rgba(255, 255, 255, 0.8);'}
  }
  a:hover & {
    color: rgba(255, 255, 255, 0.8);
    text-decoration: underline;
  }
`;

const SecondaryText = styled.span`
  font-size: 12px;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.4);
  ${({ onClick }) => onClick && 'cursor: pointer;'}
  &:hover {
    ${({ onClick }) => onClick && 'color: rgba(255, 255, 255, 0.8);'}
  }
  a:hover & {
    color: rgba(255, 255, 255, 0.8);
    text-decoration: underline;
  }
`;

const EllipsesWrapper = styled.div`
  position: relative;
  max-width: 100%;
  > * {
    width: 100%;
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
`;

const AutoSkeletonBone = ({ width }: { width: string | number }) => (
  <span className='relative inline-block'>
    &nbsp;
    <SkeletonBone
      style={{ width }}
      className='absolute top-0 left-0 h-3 rounded-md'
    />
  </span>
);

const ClipTitle = () => {
  const clip = useContext(ClipContext).clip;
  const title = !!clip ? getClipTitle(clip) : 'Untitled';
  return (
    <h4 className={clsx('line-clamp-2', { ['overflow-visible']: !title })}>
      <PrimaryText>{title ?? <AutoSkeletonBone width={110} />}</PrimaryText>
    </h4>
  );
};

const ClipTitleNew = () => {
  const clip = useContext(ClipContext).clip;
  const title = !!clip ? getClipTitle(clip) : 'Untitled';
  return (
    <h4
      className={clsx('line-clamp-1 text-base', {
        ['overflow-visible']: !title,
      })}
    >
      {title ?? <AutoSkeletonBone width={110} />}
    </h4>
  );
};

const getTagStringFromMetadata = (clip?: Clip) => {
  const { tags, negative_tags } = clip?.metadata ?? {};
  if (tags === undefined && negative_tags === undefined) return undefined;
  const tagsStr = tags
    ?.split(',')
    .map((tag) => tag.trim())
    .join(', ');

  const negativeTagsStr = negative_tags
    ?.split(',')
    .map((tag) => `-${tag.trim()}`)
    .join(', ');

  const result = [tagsStr, negativeTagsStr].filter(Boolean).join(', ');
  return result || '[no styles]';
};

const ClipTags = () => {
  const clip = useContext(ClipContext).clip;
  const str = useMemo(() => {
    return getTagStringFromMetadata(clip);
  }, [clip?.metadata]);
  return (
    <EllipsesWrapper>
      <SecondaryText>{str}</SecondaryText>
    </EllipsesWrapper>
  );
};

const ClipTagsNew = () => {
  const clip = useContext(ClipContext).clip;
  const tags = [
    ...tagsToArray(clip ? getClipDisplayTags(clip) : ''),
    ...tagsToNegativeTags(tagsToArray(clip?.metadata?.negative_tags || '')),
  ];
  const linkPressProps = useMemo(
    () => ({
      onPointerDownCapture: (e: React.PointerEvent) => {
        e.stopPropagation();
      },
    }),
    []
  );
  const renderLink = useCallback<
    NonNullable<React.ComponentProps<typeof MusicStyleTags>['renderTag']>
  >((props) => <Link {...linkPressProps} {...props} />, [linkPressProps]);
  return (
    <MusicStyleTags
      className='line-clamp-1 flex-nowrap pr-2 text-sm text-foreground-primary'
      tags={tags}
      title={clip?.metadata.tags || ''}
      renderTag={renderLink}
    />
  );
};

const ClipArtwork = ({
  children,
}: {
  children?: React.ReactNode[] | React.ReactNode;
}) => {
  const { clip, onPlayClick } = useContext(ClipContext);
  const imageUrl = clip?.image_url;
  return (
    <ArtworkContainer onClick={onPlayClick}>
      {imageUrl ? (
        <ArtworkImg src={imageUrl} alt='Clip artwork' />
      ) : (
        <SkeletonBone className='h-full w-full opacity-50' />
      )}
      {children}
    </ArtworkContainer>
  );
};

const ClipMetaBlock = styled.span<{
  color?: string;
  borderColor?: string;
  transparent?: boolean;
}>`
  font-size: 12px;
  line-height: 12px;
  font-weight: 500;
  color: ${({ color }) => color ?? 'inherit'};
  background-color: ${({ transparent }) =>
    transparent ? 'transparent' : 'rgba(0, 0, 0, 0.3)'};
  padding: 4px;
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border: 1px solid ${({ borderColor }) => borderColor ?? 'transparent'};
  backdrop-filter: ${({ transparent }) => (transparent ? 'none' : 'blur(6px)')};
  cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')};
`;

const ClipDuration = () => {
  const duration = useContext(ClipContext).clip?.metadata?.duration;
  const durationEncoded = useMemo(() => {
    if (!duration) return '--:--';
    const encoded = encodeTimeFormat(duration);
    if (encoded?.[0] === '0') return encoded.slice(1);
    return encoded || '--:--';
  }, [duration]);
  return (
    <span className='m-[2px] rounded-md bg-black/70 px-1 text-xs'>
      {durationEncoded}
    </span>
  );
};

const ClipModelVersion = () => {
  const modelVersion = useContext(ClipContext).clip?.major_model_version;
  if (!modelVersion) {
    return null;
  }
  return <ClipMetaBlock>{modelVersion}</ClipMetaBlock>;
};

const ClipPlayCount = observer(({ subtle }: { subtle?: boolean }) => {
  const { onPlayClick, allowPlayback, clip } = useContext(ClipContext);
  const content = allowPlayback ? (
    <>
      <PlayIcon className='mt-px text-inherit' />
      {clip?.play_count}
    </>
  ) : (
    <SkeletonBone className={'w-8'} />
  );
  if (subtle) {
    return (
      <SecondaryText onClick={onPlayClick} className='flex items-center gap-1'>
        {content}
      </SecondaryText>
    );
  } else {
    return <ClipMetaBlock onClick={onPlayClick}>{content}</ClipMetaBlock>;
  }
});

const ClipLikeCount = observer(({ subtle }: { subtle?: boolean }) => {
  const { clip, allowReactions, onLikeClick } = useContext(ClipContext);

  const content = allowReactions ? (
    <>
      <ThumbsUpIcon className='mt-px text-inherit' />
      {clip?.upvote_count}
    </>
  ) : (
    <SkeletonBone className={'w-8'} />
  );

  if (subtle) {
    return (
      <SecondaryText className='flex items-center gap-2' onClick={onLikeClick}>
        {content}
      </SecondaryText>
    );
  } else {
    return <ClipMetaBlock onClick={onLikeClick}>{content}</ClipMetaBlock>;
  }
});

const ClipArtist = () => {
  const { avatar_image_url, display_name, handle } =
    useContext(ClipContext).clip || {};
  return (
    <a href={handle ? `/@${handle}` : undefined}>
      <Row>
        {avatar_image_url && (
          <img
            src={avatar_image_url}
            className='-mt-px h-4 w-4 rounded-full'
            alt={`${display_name || handle || "Artist's"} avatar`}
          />
        )}
        <SecondaryText>
          {display_name ?? <AutoSkeletonBone width={160} />}
        </SecondaryText>
      </Row>
    </a>
  );
};

const ClipPersona = observer(() => {
  const { persona } = useContext(ClipContext).clip || {};
  return !!persona ? (
    <a href={persona.id ? `/persona/${persona.id}` : undefined}>
      <div style={AvatarMaskShape.Persona}>
        <ImageWithFallback
          imageSize={SMALL_IMAGE}
          className='h-full w-full object-cover'
          src={persona.image_s3_id || FALLBACK_IMAGE_URL}
          alt={`Persona picture for ${persona.name}`}
        />
      </div>
      <SecondaryText>
        {persona.name ?? <AutoSkeletonBone width={160} />}
      </SecondaryText>
    </a>
  ) : null;
});

const SongWrapper = styled(Row)<{ selected?: boolean }>`
  height: 100%;
  width: 100%;
  flex-grow: 0;
  padding: 10px;
  border-radius: 10px;
  position: relative;
  line-height: 16px;
  .hover-only > * {
    opacity: ${({ selected }) => (selected ? 1 : 0)};
  }
  &:hover {
    background-color: ${({ selected }) =>
      selected ? '' : 'rgba(255, 255, 255, 0.1)'};
    .hover-only > * {
      opacity: 1;
    }
  }
  background-color: ${({ selected }) =>
    selected ? 'rgba(255, 255, 255, 0.17)' : 'rgba(255,255,255,0)'};
`;

const SongRowWrapper = styled(Row)<{ selected?: boolean }>`
  height: 100%;
  width: 100%;
  flex-grow: 0;
  padding: 8px;
  border-radius: 12px;
  position: relative;
  line-height: 16px;
  cursor: pointer;
  .hover-only > * {
    opacity: ${({ selected }) => (selected ? 1 : 0)};
  }
  &:hover {
    background-color: ${({ selected }) => (selected ? '' : 'rgba(20, 20, 22)')};
    .hover-only > * {
      opacity: 1;
    }
  }
  background-color: ${({ selected }) =>
    selected ? 'rgba(45, 45, 49)' : 'rgba(255,255,255,0)'};

  [data-selected] & {
    background-color: rgba(45, 45, 49);
  }
`;

const HoverOnly = (props: HTMLProps<HTMLDivElement>) => (
  <div className='hover-only contents' {...props} />
);

const SongRowButton = (
  props: ComponentProps<typeof Button> & { skeleton?: boolean }
) => {
  if (props.skeleton) {
    return <SkeletonBone className='h-8 w-8 rounded-full' />;
  }
  return (
    <Button
      variant={ButtonVariant.Secondary}
      shape={ButtonShape.Pill}
      className='relative flex h-8 w-8 items-center justify-center bg-black/40 p-0'
      {...(omit(props, 'skeleton') as any)}
    />
  );
};

const ThumbsUpButton = observer(() => {
  const { clip, allowReactions, onLikeClick } = useContext(ClipContext);
  const liked = clip && isLiked(clip);
  return (
    <SongRowButton skeleton={!allowReactions} onClick={onLikeClick}>
      <ThumbsUpIcon
        className={clsx({ 'text-foreground-inactive': !liked }, 'h-4 w-4')}
      />
    </SongRowButton>
  );
});

const ThumbsDownButton = observer(() => {
  const { clip, allowReactions, onDislikeClick } = useContext(ClipContext);
  const disliked = clip && isDisliked(clip);
  return (
    <SongRowButton skeleton={!allowReactions} onClick={onDislikeClick}>
      <ThumbsDownIcon
        className={clsx({ 'text-foreground-inactive': !disliked }, 'h-4 w-4')}
      />
    </SongRowButton>
  );
});

const HoverSwitchWrapper = styled.span`
  display: contents;
  .base {
    display: contents;
  }
  .hover {
    display: none;
  }
  &:hover {
    .base {
      display: none;
    }
    .hover {
      display: contents;
    }
  }
`;

const HoverSwitch = ({
  hover,
  base,
}: {
  hover: React.ReactNode;
  base: React.ReactNode;
}) => {
  return (
    <HoverSwitchWrapper>
      <span className='hover'>{hover}</span>
      <span className='base'>{base}</span>
    </HoverSwitchWrapper>
  );
};

const PlayButton = () => {
  const { playing, onPlayClick, allowPlayback, inPlaybar } =
    useContext(ClipContext);
  const innerButton = (
    <SongRowButton onClick={onPlayClick} skeleton={!allowPlayback}>
      {playing ? (
        <HoverSwitch
          hover={<PauseIcon className='h-4 w-4' />}
          base={<PulsingLinesIcon className='h-4 w-4' />}
        />
      ) : (
        <PlayIcon className='h-4 w-4' />
      )}
    </SongRowButton>
  );
  return inPlaybar ? innerButton : <HoverOnly>{innerButton}</HoverOnly>;
};

const MenuButton = (
  props: ComponentProps<typeof SongRowButton> & { narrow?: boolean }
) => {
  return (
    <SongRowButton
      variant={ButtonVariant.Tertiary}
      shape={ButtonShape.Rounded}
      className={clsx('relative flex h-8 w-4 items-center justify-center p-0', {
        '-mr-1 -ml-1': props.narrow,
      })}
      {...(omit(props, 'narrow') as any)}
    >
      <MoreVerticalIcon />
    </SongRowButton>
  );
};

const MenuTrigger = ({ narrow }: { narrow?: boolean }) => {
  return (
    <HoverOnly>
      <ContextMenuTrigger
        ButtonComponent={(props) => <MenuButton {...props} narrow={narrow} />}
        ContentsComponent={MenuContents}
      ></ContextMenuTrigger>
    </HoverOnly>
  );
};

const UnplayedNotificationDot = ({ narrow }: { narrow?: boolean }) => {
  const { clip, allowPlayback } = useContext(ClipContext);
  const unplayed = allowPlayback && clip?.play_count === 0;
  return (
    <div className={clsx('relative h-full w-[8px]', { '-mr-1 -ml-1': narrow })}>
      {unplayed && <NotificationDot />}
    </div>
  );
};

const MenuContents = () => {
  const apiClient = useApiClient();
  const { session } = useStores();
  const { clip } = useContext(ClipContext);
  return (
    <>
      <ContextMenuItem
        icon={<DownloadIcon className='h-4 w-4' />}
        disabled={!clip}
        onClick={() => {
          if (clip) downloadClipAudio(apiClient, clip, session);
        }}
      >
        Download MP3
      </ContextMenuItem>
    </>
  );
};

const MinimumSongEvo = ({
  displayPurpose,
}: {
  displayPurpose: SongDisplayPurpose;
}) => {
  const { inPlaybar, onPlayClick } = useContext(ClipContext);

  return (
    <SongWrapper onClick={onPlayClick} selected={inPlaybar}>
      {displayPurpose === 'creation' && <UnplayedNotificationDot narrow />}

      <ClipArtwork />

      <div className='relative h-full grow'>
        <Column className='absolute inset-0 justify-center'>
          <Row className='-mb-[5px]'>
            <ClipTitle />
          </Row>
          <Row>
            <ClipTags />
          </Row>
        </Column>
      </div>

      <Column className='shrink-0 justify-center'>
        <Row>
          {displayPurpose === 'creation' && (
            <>
              <ThumbsUpButton />
              <ThumbsDownButton />
            </>
          )}
          <MenuTrigger narrow />
        </Row>
      </Column>
    </SongWrapper>
  );
};

const StandardSongEvo = ({
  displayPurpose,
}: {
  displayPurpose: SongDisplayPurpose;
}) => {
  const { inPlaybar, onPlayClick } = useContext(ClipContext);

  return (
    <SongWrapper onClick={onPlayClick} selected={inPlaybar}>
      {displayPurpose === 'creation' && <UnplayedNotificationDot />}
      <ClipArtwork>
        <ArtworkLower>
          <ClipDuration />
        </ArtworkLower>
        <ArtworkMiddle>
          <PlayButton />
        </ArtworkMiddle>
      </ClipArtwork>

      <div className='relative h-full grow'>
        <Column className='absolute inset-0 justify-center'>
          <Row className='-mb-[5px]'>
            <ClipTitle />
            <ClipModelVersion />
            <ClipPlayCount subtle />
          </Row>
          <ClipTags />
          <ClipArtist />
        </Column>
      </div>

      <Column className='shrink-0 justify-center'>
        <Row>
          {displayPurpose === 'creation' && (
            <>
              <ThumbsUpButton />
              <ThumbsDownButton />
            </>
          )}
          <MenuTrigger />
        </Row>
      </Column>
    </SongWrapper>
  );
};

const DetailListSongEvo = ({
  displayPurpose,
}: {
  displayPurpose: SongDisplayPurpose;
}) => {
  const { inPlaybar, onPlayClick } = useContext(ClipContext);

  return (
    <SongWrapper onClick={onPlayClick} selected={inPlaybar}>
      {displayPurpose === 'creation' && <UnplayedNotificationDot />}
      <ClipArtwork>
        <ArtworkLower>
          <ClipDuration />
        </ArtworkLower>
        <ArtworkMiddle>
          <PlayButton />
        </ArtworkMiddle>
      </ClipArtwork>
      <Column className='w-[250px] grow justify-center'>
        <Row>
          <ClipTitle />
          <ClipModelVersion />
        </Row>
        <ClipArtist />
      </Column>
      <Column className='w-[200px] grow justify-center'>
        <ClipTags />
      </Column>
      <Column className='w-[200px] shrink-0 items-end justify-center'>
        <Row className='justify-end'>
          <ClipPlayCount subtle />
          {displayPurpose !== 'creation' && <ClipLikeCount subtle />}
          <div className='w-4' />
          {displayPurpose === 'creation' && (
            <>
              <ThumbsUpButton />
              <ThumbsDownButton />
            </>
          )}
          <MenuTrigger />
        </Row>
      </Column>
    </SongWrapper>
  );
};

const IconButton = ({
  label,
  children,
  onClick,
  invert = false,
}: PropsWithChildren<{
  onClick: (e: React.MouseEvent<HTMLElement>) => void;
  label: string;
  invert?: boolean;
}>) => {
  return (
    <button
      aria-label={label}
      className={
        invert
          ? 'brightness-100 hover:brightness-[0.8]'
          : 'brightness-50 hover:brightness-[0.7]'
      }
      onClick={onClick}
    >
      {children}
    </button>
  );
};

type TopLineProps = {
  children?: ReactNode;
};

type BottomLineProps = {
  children?: ReactNode;
};

interface SongRowLayoutComponent
  extends React.FC<{
    children?: ReactNode;
    className?: string;
  }> {
  TopLine: React.FC<TopLineProps>;
  BottomLine: React.FC<BottomLineProps>;
}

const TopLine: React.FC<TopLineProps> = ({ children }: PropsWithChildren) => {
  return children;
};

const BottomLine: React.FC<BottomLineProps> = ({
  children,
}: PropsWithChildren) => {
  return children;
};

type SongRowLayoutProps = {
  showPersona?: boolean;
  showArtist?: boolean;
};

const SongRowLayoutBase = observer(
  ({
    children,
    showPersona,
    showArtist,
  }: PropsWithChildren<SongRowLayoutProps>) => {
    const { onPlayClick, inPlaybar } = useContext(ClipContext);
    const topLineRef = React.useRef(null);
    const bottomLineRef = React.useRef(null);

    useEffect(() => {
      React.Children.forEach(children, (child: any) => {
        if (child.type === SongRowLayout.TopLine) {
          topLineRef.current = child;
        } else if (child.type === SongRowLayout.BottomLine) {
          bottomLineRef.current = child;
        }
      });
    }, [children]);

    return (
      <div className='mb-2 h-[90px] min-w-[380px]'>
        <SongRowWrapper
          onClick={() => {}}
          onDoubleClick={onPlayClick}
          className='group'
          selected={inPlaybar}
        >
          <ClipArtwork>
            <ArtworkLower>
              <ClipDuration />
            </ArtworkLower>
            <ArtworkMiddle>
              <PlayButton />
            </ArtworkMiddle>
          </ClipArtwork>
          <Column className='w-[250px] grow justify-center'>
            <Row>
              <ClipTitleNew />
              <ClipModelVersion />
            </Row>
            <Row>
              {showArtist ? <ClipArtist /> : null}
              {showPersona ? <ClipPersona /> : null}
              <ClipTagsNew />
            </Row>
          </Column>
          <Column className='h-full w-[200px] shrink-0 items-end justify-between brightness-50 group-hover:brightness-100'>
            <div className='flex flex-row justify-end gap-4 pt-1'>
              {topLineRef.current}
            </div>
            <div className='flex flex-row gap-[5px]'>
              {bottomLineRef.current}
            </div>
          </Column>
        </SongRowWrapper>
      </div>
    );
  }
);

const SongRowLayout = SongRowLayoutBase as SongRowLayoutComponent;

SongRowLayout.TopLine = TopLine;
SongRowLayout.BottomLine = BottomLine;

SongRowLayout.displayName = 'SongRowLayout';
SongRowLayout.TopLine.displayName = 'SongRowLayout.TopLine';
SongRowLayout.BottomLine.displayName = 'SongRowLayout.BottomLine';

const DEBUG_FORCE_SKELETON = false;

type SongDisplayPurpose = 'creation' | 'listening' | 'remixing';

const SongPokemon = observer(
  ({
    clipId,
    displayPurpose = 'listening',
    playContext,
  }: {
    clipId?: string;
    displayPurpose: SongDisplayPurpose;
    playContext: PlayContext | ((clip: Clip) => void);
  }) => {
    const { clip } = useClip(clipId);
    const selectEvo = useCallback(
      (width: number) =>
        width > 700
          ? DetailListSongEvo
          : width > 480
            ? StandardSongEvo
            : MinimumSongEvo,
      []
    );
    const clipContext = useClipContext(
      DEBUG_FORCE_SKELETON ? undefined : clip || undefined,
      playContext
    );
    return (
      <ClipContext.Provider value={clipContext}>
        <div className='h-[90px]'>
          <PokemonV2 selectEvo={selectEvo} evoProps={{ displayPurpose }} />
        </div>
      </ClipContext.Provider>
    );
  }
);

export const CreateSongRowBottomLine = observer(() => {
  const { clip, onShareClick, onPublicToggle } = useContext(ClipContext);
  return (
    <>
      <Button
        size={ButtonSize.Mini}
        shape={ButtonShape.Pill}
        variant={ButtonVariant.Secondary}
        icon={ShareArrowIcon}
        onClick={onShareClick}
      ></Button>
      <Button
        size={ButtonSize.Mini}
        shape={ButtonShape.Pill}
        variant={ButtonVariant.Secondary}
        onClick={() => {
          window.location.href = `/edit/${clip?.id}`;
        }}
      >
        Edit
      </Button>
      <Button
        size={ButtonSize.Mini}
        shape={ButtonShape.Pill}
        variant={ButtonVariant.Secondary}
        onClick={() => {
          onPublicToggle();
        }}
        className='whitespace-nowrap'
      >
        Public
        <Switch
          small
          checked={!!clip?.is_public}
          onChange={() => {
            onPublicToggle();
          }}
        />
      </Button>
    </>
  );
});

export const CreateSongRowTopLine = observer(() => {
  const { clip, onLikeClick, onDislikeClick } = useContext(ClipContext);

  return (
    <>
      <IconButton onClick={() => {}} label='Bookmark Song'>
        <BookmarkOutlineIcon className='h-4 w-4' />
      </IconButton>
      <IconButton
        onClick={onLikeClick}
        label='Like Song'
        invert={clip ? isLiked(clip) : false}
      >
        <ThumbsUpIcon className='h-4 w-4' />
      </IconButton>
      <IconButton
        onClick={onDislikeClick}
        label='Dislike Song'
        invert={clip ? isDisliked(clip) : false}
      >
        <ThumbsDownIcon className='h-4 w-4' />
      </IconButton>
      {clip && <SongMenuWithContext clip={clip} />}
    </>
  );
});

export const CreateSongRow = observer(
  ({
    clipId,
    playContext,
  }: {
    clipId?: string;
    playContext: PlayContext | ((clip: Clip) => void);
  }) => {
    const { clip } = useClip(clipId);
    const clipContext = useClipContext(clip || undefined, playContext);
    return (
      <ClipContext.Provider value={clipContext}>
        <SongRowLayout>
          <SongRowLayout.TopLine>
            <CreateSongRowTopLine />
          </SongRowLayout.TopLine>
          <SongRowLayout.BottomLine>
            <CreateSongRowBottomLine />
          </SongRowLayout.BottomLine>
        </SongRowLayout>
      </ClipContext.Provider>
    );
  }
);

export default SongPokemon;
