'use client';

/* eslint jsx-a11y/click-events-have-key-events: warn */

/* eslint jsx-a11y/no-static-element-interactions: warn */
import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import { usePathname, useRouter } from 'next/navigation';
import React, {
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import Button, { ButtonVariant } from '@/components/button/Button';
import { toast } from '@/components/toast/Toast';
import { Tooltip } from '@/components/tooltip/Tooltip';
import { ThemeMode, useThemeContext } from '@/context/ThemeContext';
import { useBreakpointLg, useBreakpointMd } from '@/hooks/useBreakpoint';
import ContestClipContext from '@/hooks/useContestClip';
import usePlaySourceContext from '@/hooks/usePlaySource';
import { ImageIcon, PinIcon, SuccessIcon, VideoIcon } from '@/icons';
import { WebUserEvent } from '@/logging/TrackingEventTypes';
import logWebUserEvent from '@/logging/logWebUserEvent';
import { Clip, isLiked as getIsLiked } from '@/state/clipStore';
import { getClipDisplayTags, getClipTitle, getExtendTask } from '@/utils/clip';
import { FALLBACK_IMAGE_URL, NO_STYLE_FALLBACK } from '@/utils/constants';
import { eventLogger } from '@/utils/event-logger';
import { ActionName, ComponentContext } from '@/utils/event-names';
import { getRandomAuraURL, isSecretStatsProfile } from '@/utils/utils';

import ImpressionLogger from '../ImpressionLogger';
import CardPlayPauseButton from '../button/CardPlayPauseButton';
import CardOverlayChip from '../card/CardOverlayChip';
import ImageWithFallback, { ImageSize } from '../image/ImageWithFallback';
import PlaybarSyncVideoPlayer from '../playbar/PlaybarSyncVideoPlayer';
import MetadataBlock from '../section/MetadataBlock';
import VideoLoopPlayer from '../video/VideoLoopPlayer';
import {
  SunoShortType,
  formatDuration,
  tagsToArray,
  tagsToNegativeTags,
} from './songUtils';

interface SongCardInnerProps {
  alt?: string;
  imageUrl: string;
  videoUrl?: string | null;
  videoPreviewUrl?: string | null;
  duration?: number | null;
  isCurrentSong?: boolean;
  isPlaying?: boolean;
  sunoShortType?: SunoShortType;
  modelVersion?: string;
  modelBadgeColor?: string | null;
  modelBackgroundColor?: string | null;
  modelBorderColor?: string | null;
  displayName?: string;
  onMouseEnter?: React.MouseEventHandler;
  onMouseLeave?: React.MouseEventHandler;
  onPlayPauseClick?: React.MouseEventHandler;
  onPinClick?: React.MouseEventHandler;
  isRootClip?: boolean;
  displayPin?: boolean;
  isClipOwner?: boolean;
  isContestSubmission?: boolean;
}

const SongCardInner: React.FC<SongCardInnerProps> = observer((props) => {
  const {
    alt = '',
    imageUrl,
    videoUrl,
    videoPreviewUrl,
    duration,
    isCurrentSong,
    isPlaying,
    sunoShortType,
    modelBadgeColor,
    modelBackgroundColor,
    modelBorderColor,
    displayName,
    onMouseEnter,
    onMouseLeave,
    onPlayPauseClick,
    onPinClick,
    isRootClip,
    displayPin = false,
    isClipOwner = false,
    isContestSubmission,
  } = props;

  // Local state
  const [isHovered, setIsHovered] = useState(false);
  const [showTooltip, setShowTooltip] = useState(false);
  const [auraBackground] = useState(() =>
    isRootClip ? getRandomAuraURL() : FALLBACK_IMAGE_URL
  );

  const isMobile = !useBreakpointMd();

  // Event handlers
  const handleMouseEnter: React.MouseEventHandler<HTMLDivElement> = useCallback(
    (e) => {
      setIsHovered(true);
      onMouseEnter?.(e);
      if (isRootClip) {
        setShowTooltip(true);
      }
    },
    [onMouseEnter, isRootClip]
  );
  const handleMouseLeave: React.MouseEventHandler<HTMLDivElement> = useCallback(
    (e) => {
      setIsHovered(false);
      onMouseLeave?.(e);
      if (isRootClip) {
        setShowTooltip(false);
      }
    },
    [onMouseLeave, isRootClip]
  );

  const isVideo = !!videoUrl;
  const isVideoShort = sunoShortType == SunoShortType.VIDEO && videoUrl;
  const isImageShort = sunoShortType == SunoShortType.IMAGE;
  const hasVideoPreview = !!videoPreviewUrl;

  const showPlayPauseButton = isHovered || isCurrentSong;

  const imageSize = useMemo(() => {
    if (isVideo) {
      return undefined;
    }
    // if loading on mobile, just load the xlarge image without lazyload to
    // see if that helps with the asset loading times
    return isMobile ? ImageSize.XLARGE : ImageSize.LARGE;
  }, [isVideo, isMobile]);

  return (
    <div
      className='relative mb-4 cursor-pointer'
      onClick={onPlayPauseClick}
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
    >
      {showTooltip && isRootClip && (
        <div className='absolute top-1/2 left-full z-30 ml-2 w-[150px] -translate-y-1/2 rounded bg-tertiary px-4 py-2 text-sm break-words whitespace-normal text-primary'>
          This song was used to create this Persona.
        </div>
      )}
      {isRootClip && (
        <div
          className='absolute inset-0 z-0 -m-1 rounded-xl blur-md'
          onMouseEnter={() => setShowTooltip(true)}
          onMouseLeave={() => setShowTooltip(false)}
          style={{
            background: `url(${auraBackground})`,
            backgroundSize: 'cover',
            backgroundPosition: 'center',
            opacity: 0.4,
          }}
        />
      )}
      <div className={'relative h-[256px] w-full overflow-hidden rounded-xl'}>
        <ImageWithFallback
          className={clsx(
            'absolute inset-0 h-full w-full rounded-xl object-cover',
            { lazyload: !isMobile }
          )}
          src={imageUrl}
          alt={alt}
          imageSize={imageSize}
          style={{
            transform: isHovered ? 'scale(1.1)' : 'scale(1)',
            transition: 'transform 0.3s ease-in-out',
          }}
        />
        {hasVideoPreview && !isCurrentSong && isHovered ? (
          <VideoLoopPlayer
            videoUrl={videoPreviewUrl}
            className='absolute inset-0 h-full w-full object-cover'
            playing={isHovered}
          />
        ) : isVideoShort || (isVideo && isCurrentSong) ? (
          <PlaybarSyncVideoPlayer
            videoUrl={videoUrl}
            className='absolute inset-0 h-full w-full object-cover'
            isCurrentSong={isCurrentSong}
          />
        ) : null}
      </div>
      <div className='absolute inset-0 z-20'>
        <CardPlayPauseButton
          className={clsx(
            'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform duration-300',
            {
              'scale-75 opacity-0': !showPlayPauseButton,
              'scale-100 opacity-100': showPlayPauseButton,
            }
          )}
          icon={
            !(isCurrentSong && isPlaying)
              ? 'play'
              : isHovered
                ? 'pause'
                : 'playing'
          }
        />
        <div className='absolute inset-x-2 top-2 flex flex-row items-center gap-1'>
          <CardOverlayChip
            icon={
              isVideoShort ? (
                <VideoIcon className='h-[14px] w-[14px]' />
              ) : isImageShort ? (
                <ImageIcon className='h-[14px] w-[14px]' />
              ) : undefined
            }
            className='border-none'
          >
            {formatDuration(duration)}
          </CardOverlayChip>
          {displayName && modelBadgeColor && (
            <CardOverlayChip
              className='border-none'
              style={{
                color: `#${modelBadgeColor}`,
                backgroundColor: `#${modelBackgroundColor}`,
                borderColor: `#${modelBorderColor}`,
              }}
            >
              {displayName}
            </CardOverlayChip>
          )}
          {isContestSubmission ? (
            <Tooltip label='Submitted to Contest'>
              <CardOverlayChip className='border-none p-1'>
                <SuccessIcon className='h-4 w-4' />
              </CardOverlayChip>
            </Tooltip>
          ) : null}
        </div>
        {displayPin && (
          <div className='absolute end-2 top-2 border-none'>
            {isClipOwner ? (
              <CardOverlayChip
                className='border-none px-[5px] py-[5px] hover:bg-[rgb(var(--rgb-gray-50)/0.6)]! hover:!text-foreground-primary-on-dark'
                icon={<PinIcon className='h-[14px] w-[14px]' />}
                onClick={(e) => {
                  e.stopPropagation();
                  e.preventDefault();
                  onPinClick?.(e);
                }}
              ></CardOverlayChip>
            ) : (
              <CardOverlayChip
                className='border-none px-[5px] py-[5px]'
                icon={<PinIcon className='h-[14px] w-[14px]' />}
              ></CardOverlayChip>
            )}
          </div>
        )}
      </div>
    </div>
  );
});

interface SongCardProps {
  clip: Clip;
  selected?: boolean;
  onClick: (e: any) => any;
  onPlay?: () => any;
  rank?: number;
  isLarge?: boolean;
  index?: number;
  onMenuButtonClick?: () => void;
  onAddToPlaylist?: () => void;
  numColumns?: number;
  contextType?: string;
  styleType?: string;
  contextId?: string;
  isPlaying?: boolean;
  sunoShortType?: SunoShortType;
  isRootClip?: boolean;
  carouselIndex?: number;
  carouselSectionName?: string;
  displayPin?: boolean;
  isClipOwner?: boolean;
  hideAvatar?: boolean;
}

const SongCard: React.FC<SongCardProps> = observer(
  ({
    clip,
    onPlay,
    contextId,
    sunoShortType,
    styleType,
    isRootClip,
    carouselIndex,
    carouselSectionName,
    index,
    displayPin = false,
    isClipOwner = false,
    hideAvatar = false,
  }) => {
    const { clips, playbar, queue, session, genForm } = useStores();
    const [isLiked, setIsLiked] = useState(false);
    const { effectiveTheme } = useThemeContext();
    const pathname = usePathname();

    const playSource = usePlaySourceContext();

    const tags = [
      ...tagsToArray(getClipDisplayTags(clip)),
      ...tagsToNegativeTags(tagsToArray(clip.metadata?.negative_tags || '')),
    ];

    const isDesktop = useBreakpointLg();
    const isMobile = !isDesktop;

    const visibleStats = !isSecretStatsProfile({ handle: clip?.handle || '' });

    const router = useRouter();

    const subtitle = tags.length ? tags.join(', ') : NO_STYLE_FALLBACK;

    const hasCarouselContext =
      carouselIndex !== undefined &&
      index !== undefined &&
      carouselSectionName !== undefined;

    const videoUrl =
      clip.metadata?.video_to_song_video_upload_url ||
      clip.video_cover_url ||
      undefined;
    const videoPreviewUrl = clip.preview_url;

    const { isContestSubmission } = useContext(ContestClipContext);

    useEffect(() => {
      setIsLiked(getIsLiked(clips.clipById[clip.id]));
    }, [clips.clipById[clip.id]?.reaction?.reaction_type]);

    const handleLikeClick = useCallback(
      ({ isLiked: isLikedOnClick }: { isLiked: boolean }) => {
        logWebUserEvent({
          actionName: 'SongCardLikeClicked',
          principalObjectType: 'song',
          principalObjectValue: clip.id,
          context: {
            playSourceType: playSource.playSourceType,
            playSourceId: playSource.playSourceId,
          },
        });

        eventLogger.logAudioActionEvent(
          false,
          isLikedOnClick ? ActionName.undoLikeSong : ActionName.likeSong,
          clip,
          session,
          pathname
        );
      },
      [
        clip,
        playSource.playSourceId,
        playSource.playSourceType,
        session,
        pathname,
      ]
    );

    const handleCommentClick = useCallback(
      (e: React.MouseEvent<HTMLButtonElement>) => {
        e.stopPropagation();
        e.preventDefault();
        logWebUserEvent({
          actionName: 'SongCardCommentClicked',
          principalObjectType: 'song',
          principalObjectValue: clip.id,
          context: {
            playSourceType: playSource.playSourceType,
            playSourceId: playSource.playSourceId,
          },
        });
        router.push(`/song/${clip.id}?show_comments=true`);
      },
      [router, clip.id, playSource.playSourceId, playSource.playSourceType]
    );

    const handleTitleClick = useCallback(() => {
      logWebUserEvent({
        actionName: 'SongCardTitleClicked',
        principalObjectType: 'song',
        principalObjectValue: clip.id,
        context: {
          index,
          playCount: clip.play_count || 0,
          likeCount: clip.upvote_count || 0,
          commentCount: clip.comment_count || 0,
          sectionId: playSource.playSourceId,
          sectionTitle: playSource.playSourceType,
          artistId: clip.user_id || '',
        },
      });
    }, [
      clip.id,
      clip.play_count,
      clip.upvote_count,
      clip.comment_count,
      clip.user_id,
      index,
      playSource.playSourceId,
      playSource.playSourceType,
    ]);

    const handleArtistClick = useCallback(() => {
      logWebUserEvent({
        actionName: 'SongCardArtistClicked',
        principalObjectType: 'song',
        principalObjectValue: clip.id,
        context: {
          index,
          playCount: clip.play_count || 0,
          likeCount: clip.upvote_count || 0,
          commentCount: clip.comment_count || 0,
          sectionId: playSource.playSourceId,
          sectionTitle: playSource.playSourceType,
          artistId: clip.user_id || '',
        },
      });
    }, [
      clip.id,
      clip.play_count,
      clip.upvote_count,
      clip.comment_count,
      clip.user_id,
      index,
      playSource.playSourceId,
      playSource.playSourceType,
    ]);

    const isPlaying = useMemo(
      () =>
        playbar.clip?.id === clip?.id &&
        (queue.contextId || null) === (contextId || null),
      [playbar.clip?.id, queue.contextId, contextId, clip?.id]
    );

    const handlePlayPauseClick = useCallback(
      (e: React.MouseEvent<HTMLElement>) => {
        e.stopPropagation();
        e.preventDefault();
        if (isPlaying) {
          logWebUserEvent({
            actionName: 'SongCardPauseClicked',
            principalObjectType: 'song',
            principalObjectValue: clip.id,
            context: {
              playSourceType: playSource.playSourceType,
              playSourceId: playSource.playSourceId,
            },
          });
          playbar.togglePlay();
        } else {
          logWebUserEvent({
            actionName: 'SongCardPlayClicked',
            principalObjectType: 'song',
            principalObjectValue: clip.id,
            context: {
              playSourceType: playSource.playSourceType,
              playSourceId: playSource.playSourceId,
            },
          });
          onPlay?.();
        }
      },
      [
        isPlaying,
        playbar.togglePlay,
        clip.id,
        playSource.playSourceType,
        playSource.playSourceId,
        onPlay,
      ]
    );

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

        const isPinned = clips.isClipPinned(clip.id);
        logWebUserEvent({
          actionName: 'SongCardPinClicked',
          principalObjectType: 'song',
          principalObjectValue: clip.id,
          context: {
            playSourceType: playSource.playSourceType,
            playSourceId: playSource.playSourceId,
            isPinned: isPinned,
          },
        });

        // If we don't need confirmation, proceed directly
        clips.pinClipToProfile({ clipId: clip.id });

        toast({
          title: `This song has been ${isPinned ? 'unpinned from Profile' : 'pinned to Profile'}.`,
          duration: 2000,
          isClosable: true,
        });
      },
      [clip.id, clips, playSource.playSourceId, playSource.playSourceType]
    );

    const impressionEvent: WebUserEvent = useMemo(
      () => ({
        actionName: 'SongCardSeen',
        principalObjectType: 'song',
        principalObjectValue: clip.id,
        context: {
          title: clip.title,
          subtitle: subtitle,
          artistDisplayName: clip.display_name,

          duration: clip.metadata?.duration,
          playCountWasDisplayed: visibleStats,
          upvoteCountWasDisplayed: visibleStats,
          commentCountWasDisplayed: visibleStats,
          playCount: clip.play_count,
          upvoteCount: clip.upvote_count,
          modelVersion: clip.major_model_version,
          commentCount: clip.comment_count,

          isUserOwner: clip.user_id === session?.userId,
          isLiked: isLiked,

          playSourceType: playSource.playSourceType,
          playSourceId: playSource.playSourceId,

          carouselIndex: carouselIndex,
          index: index,
          carouselSectionName: carouselSectionName,
        },
      }),
      [
        clip.id,
        clip.title,
        clip.metadata?.duration,
        clip.display_name,
        clip.user_id,
        visibleStats,
        subtitle,
        session?.userId,
        isLiked,
        clip.play_count,
        clip.upvote_count,
        clip.comment_count,
        clip.major_model_version,
        playSource,
        carouselIndex,
        index,
        carouselSectionName,
      ]
    );

    const partialImpressionEvent: WebUserEvent = useMemo(
      () => ({
        actionName: 'SongCardSeenPartially',
        principalObjectType: 'song',
        principalObjectValue: clip.id,
        context: {
          title: clip.title,
          subtitle: subtitle,
          artistDisplayName: clip.display_name,

          duration: clip.metadata?.duration,
          playCountWasDisplayed: visibleStats,
          upvoteCountWasDisplayed: visibleStats,
          playCount: clip.play_count,
          upvoteCount: clip.upvote_count,
          modelVersion: clip.major_model_version,

          isUserOwner: clip.user_id === session?.userId,
          isLiked: isLiked,

          playSourceType: playSource.playSourceType,
          playSourceId: playSource.playSourceId,

          // non-null assert these because the partial logger should be disabled otherwise
          carouselIndex: carouselIndex!,
          index: index!,
          carouselSectionName: carouselSectionName!,
        },
      }),
      [
        clip,
        visibleStats,
        subtitle,
        session?.userId,
        isLiked,
        clip.play_count,
        clip.upvote_count,
        clip.major_model_version,
        playSource,
        carouselIndex,
        index,
        carouselSectionName,
      ]
    );

    const impressionLoggerConfigs = useMemo(() => {
      return [
        {
          event: impressionEvent,
          threshold: 1.0,
        },
        {
          event: partialImpressionEvent,
          threshold: 0.25,
          // enable partial logging only for carousel cards
          disabled: !hasCarouselContext,
        },
      ];
    }, [impressionEvent, partialImpressionEvent, hasCarouselContext]);

    const artistTagProps = useMemo(() => {
      return clip.handle
        ? {
            displayName: clip.display_name,
            handle: clip.handle,
            imageUrl: clip.avatar_image_url || undefined,
          }
        : undefined;
    }, [clip.display_name, clip.handle, clip.avatar_image_url]);

    if (!clip) return null;

    return (
      <ImpressionLogger
        configs={impressionLoggerConfigs}
        className={'relative flex w-[172px] shrink-0 cursor-pointer flex-col'}
      >
        <SongCardInner
          alt={`Image for ${clip.title || 'Untitled'}`}
          imageUrl={clip.image_url!}
          videoUrl={videoUrl}
          videoPreviewUrl={videoPreviewUrl}
          duration={clip.metadata?.duration}
          isCurrentSong={isPlaying}
          isPlaying={isPlaying && playbar.isPlaying}
          displayName={clip.metadata?.model_badges?.songcard?.display_name}
          modelBadgeColor={
            effectiveTheme === ThemeMode.Dark
              ? clip.metadata?.model_badges?.songcard?.dark?.text_color
              : clip.metadata?.model_badges?.songcard?.light?.text_color
          }
          modelBackgroundColor={
            effectiveTheme === ThemeMode.Dark
              ? clip.metadata?.model_badges?.songcard?.dark?.background_color
              : clip.metadata?.model_badges?.songcard?.light?.background_color
          }
          modelBorderColor={
            effectiveTheme === ThemeMode.Dark
              ? clip.metadata?.model_badges?.songcard?.dark?.border_color
              : clip.metadata?.model_badges?.songcard?.light?.border_color
          }
          sunoShortType={sunoShortType}
          onPlayPauseClick={handlePlayPauseClick}
          isRootClip={isRootClip}
          displayPin={displayPin}
          onPinClick={handlePinClick}
          isClipOwner={isClipOwner}
          // TODO: this needs to return the contest ids
          isContestSubmission={isContestSubmission({ clip })}
        />
        <MetadataBlock
          clip={clip}
          title={getClipTitle(clip)}
          link={`/song/${clip.id}`}
          subtitle={subtitle}
          isClipMetadata
          artistTagProps={artistTagProps}
          isSongCard={true}
          carouselSectionName={carouselSectionName}
          playCount={clip.play_count}
          commentCount={clip.comment_count}
          isLiked={isLiked}
          visibleStats={visibleStats}
          onCommentClick={handleCommentClick}
          onPlay={handlePlayPauseClick}
          onLike={handleLikeClick}
          onTitleClick={handleTitleClick}
          onArtistClick={handleArtistClick}
          hideAvatar={hideAvatar}
        />
        {styleType === 'contest' && (
          <div className='mt-2 flex w-full flex-row gap-2'>
            <Button
              variant={ButtonVariant.Standard}
              onClick={() => {
                eventLogger.logAudioActionWithContext({
                  isMobile,
                  actionName: ActionName.coverSong,
                  clip,
                  session,
                  pathname,
                  componentContext: ComponentContext.SONG_CARD,
                });

                genForm.resetPersona();
                genForm.resetContinueClip();
                genForm.resetInfill();
                genForm.setCoverClip(clip);

                if (isMobile) {
                  genForm.shouldOpenMobileCreate = true;
                }

                genForm.setTask('cover');

                if (pathname !== '/create') {
                  router.push('/create');
                }
              }}
            >
              Cover
            </Button>
            <Button
              variant={ButtonVariant.Standard}
              onClick={() => {
                eventLogger.logAudioActionWithContext({
                  isMobile,
                  actionName: ActionName.extendSong,
                  clip,
                  session,
                  pathname,
                  componentContext: ComponentContext.SONG_CARD,
                });

                genForm.resetCoverClip();
                genForm.resetPersona();
                genForm.setContinueClip(clip);

                if (isMobile) {
                  genForm.shouldOpenMobileCreate = true;
                }

                genForm.setTask(getExtendTask(clip));
                if (pathname !== '/create') {
                  router.push('/create');
                }
              }}
            >
              Extend
            </Button>
          </div>
        )}
      </ImpressionLogger>
    );
  }
);

export default SongCard;
