'use client';

import { useAuth, useClerk } from '@clerk/nextjs';
import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import { usePathname } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';
import { twMerge } from 'tailwind-merge';

import { useStores } from '@/app/(root)/AppProviders';
import { ClipLikeButton } from '@/components/button/ClipLikeButton';
import Link from '@/components/link/Link';
import { SongMenuWithContext } from '@/components/song/newActions/SongMenuWithContext';
import ArtistTag from '@/components/tag/ArtistTag';
import {
  PlayIcon,
  ShareArrowIcon,
  ThumbsDownIcon,
  UserAddIcon,
  UserAddedIcon,
} from '@/icons';
import { ContextType } from '@/logging/contextTypes';
import { ParentClip, isDisliked, isLiked } from '@/state/clipStore';
import { ControlSliderKey } from '@/state/createV2Store';
import { getClipTitle } from '@/utils/clip';
import {
  CONTROL_SLIDERS,
  CREATE_SLIDER_DEFAULT_VALUES,
  REMIX_OPTIONS_BUTTON_CLASSNAME,
  REMIX_OPTIONS_CLASSNAME,
} from '@/utils/constants';
import { shareClip } from '@/utils/download';
import { isDevOrStaging } from '@/utils/environment';
import { eventLogger } from '@/utils/event-logger';
import { ActionName } from '@/utils/event-names';
import { getLyricsRangeIndexes } from '@/utils/lyrics';
import {
  shouldShowClipLineageCard,
  shouldShowRemixOf,
} from '@/utils/remixUtils';
import { getClerkSignInRedirectProps, getCountString } from '@/utils/utils';
import { formatDateStringWTime } from '@/utils/utils';

import { Clip } from '../../state/clipStore';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '../button/Button';
import CloseButton from '../button/CloseButton';
import ClipCaption from '../caption/ClipCaption';
import CompactCardOverlayButton from '../card/CompactCardOverlayButton';
import PersonaTag from '../tag/PersonaTag';
import SummaryOrFullTags from '../tag/SummaryOrFullTags';
import ClipLineageCard from './ClipLineageCard';
import ExtendedFromDropdown from './ExtendedFromDropdown';
import LargeSongCard from './LargeSongCard';
import RemixOf from './RemixOf';
import RemixOptions from './RemixOptions';
import Remixes from './Remixes';
import { getSunoShortType, shouldShowPersona } from './songUtils';

const ClipPreview = observer(
  ({
    clip,
    onCloseClipPreview: closeClipPreview,
    infillRange,
    parentClip,
  }: {
    clip: Clip;
    onCloseClipPreview: () => void;
    onAddToPlaylist?: () => any;
    infillRange?: {
      start: number;
      end: number;
    };
    parentClip?: ParentClip | null;
  }) => {
    const {
      clips,
      session,
      library,
      playbar,
      edit,
      queue: queueStore,
    } = useStores();

    const lyricsWindowRef = useRef<any>(undefined);

    const [isHovered, setIsHovered] = useState(false);
    const [isFollowing, setIsFollowing] = useState<boolean>(false);
    const likeStatus = isLiked(clip);
    const [dislikeStatus, setDislikeStatus] = useState(isDisliked(clip));
    const { isSignedIn } = useAuth();
    const clerk = useClerk();

    const [scrollPosition, setScrollPosition] = useState(0);
    const containerRef = useRef<HTMLDivElement>(null);
    const clipIdRef = useRef<string>(clip.id);

    const [containerHeight, setContainerHeight] = useState(0);

    useEffect(() => {
      if (clipIdRef.current !== clip.id) {
        clipIdRef.current = clip.id;
        setScrollPosition(0);

        setTimeout(() => {
          if (containerRef.current) {
            containerRef.current.scrollTop = 0;
          }
        }, 0);
      }
    }, [clip.id, session.flags]);

    useEffect(() => {
      const handleScroll = () => {
        if (containerRef.current) {
          const currentScrollPosition = containerRef.current.scrollTop;
          setScrollPosition(currentScrollPosition);
        }
      };

      if (containerRef.current) {
        containerRef.current.scrollTop = 0;
        handleScroll();
      }

      const container = containerRef.current;
      if (container) {
        container.addEventListener('scroll', handleScroll);
        return () => container.removeEventListener('scroll', handleScroll);
      }
    }, [clip.id]);

    const calculateOpacity = () => {
      const maxScrollForFade = 50;
      return Math.max(0, 1 - scrollPosition / maxScrollForFade);
    };

    const overlayOpacity = calculateOpacity();

    useEffect(() => {
      const getFollow = async () => {
        if (session.user?.id) {
          const { data } = await library.apiClient.GET(
            '/api/user/get-creator-info/{creator_id}',
            {
              params: { path: { creator_id: clip?.user_id || '' } },
            }
          );
          setIsFollowing(data?.is_following || false);
        }
      };
      getFollow();
    }, [clip, library]);

    useEffect(() => {
      lyricsWindowRef.current?.scrollIntoView();
    }, [infillRange]);

    const pathname = usePathname();

    const handleFollow = async () => {
      await library.apiClient.POST('/api/profiles/follow', {
        body: {
          unfollow: isFollowing,
          handle: clip.handle || '',
        },
      });
      setIsFollowing(!isFollowing);
    };

    if (!clip) {
      return null;
    }

    const { startIndex, endIndex } =
      infillRange?.start !== undefined && infillRange?.end !== undefined
        ? getLyricsRangeIndexes(
            clips.alignedLyricsByClipId[clip.id],
            infillRange?.start,
            infillRange?.end
          )
        : { startIndex: undefined, endIndex: undefined };

    const handlePlayClip = (clipToPlay: Clip) => {
      if (playbar.clip?.id === clipToPlay.id) {
        playbar.togglePlay();
        return;
      }
      queueStore.setPlayContext({
        contextType: ContextType.CreateClipPreview,
        contextId: 'clip_preview',
        currentIndex: clips.clips.findIndex(
          (c: Clip) => c.id === clipToPlay.id
        ),
        clips: clips.clips,
      });
      playbar.playClip(clipToPlay);
    };

    const sunoShortType = getSunoShortType(clip);

    const handleLikeClick = ({ isLiked }: { isLiked: boolean }) => {
      // TODO: refactor this after dislike button is implemented
      if (isLiked && dislikeStatus) {
        setDislikeStatus(false);
        clips.dislikeClip(clip.id, false);
      }
      eventLogger.logAudioActionEvent(
        false,
        isLiked ? ActionName.likeSong : ActionName.undoLikeSong,
        clip,
        session,
        pathname
      );
    };

    const handleDislikeClick = () => {
      if (!isSignedIn) {
        clerk.openSignIn({
          withSignUp: true,
          ...getClerkSignInRedirectProps(pathname),
        });
      } else {
        const newStatus = !isDisliked(clips.clipById[clip.id]);
        setDislikeStatus(newStatus);
        if (newStatus && likeStatus) {
          clips.likeClip(clip?.id, false);
        }
        clips.dislikeClip(clip.id, newStatus);
        eventLogger.logAudioActionEvent(
          false,
          newStatus ? ActionName.dislikeSong : ActionName.undoDislikeSong,
          clip,
          session,
          pathname
        );
      }
    };

    const handleShare = async () => {
      await shareClip(clips.apiClient, clip);
    };

    const isControlSliderEnabledForClip = (
      clip: Clip,
      sliderKey: ControlSliderKey
    ) => {
      const sliderValue = clip.metadata?.control_sliders?.[sliderKey];
      const defaultValue = CREATE_SLIDER_DEFAULT_VALUES[sliderKey] / 100.0;
      return (
        sliderValue !== null &&
        sliderValue !== undefined &&
        sliderValue !== defaultValue
      );
    };

    useEffect(() => {
      const updateHeight = () => {
        if (containerRef.current) {
          setContainerHeight(containerRef.current.offsetHeight);
        }
      };

      updateHeight();

      const resizeObserver = new ResizeObserver(updateHeight);
      if (containerRef.current) {
        resizeObserver.observe(containerRef.current);
      }

      return () => resizeObserver.disconnect();
    }, [session.flags]);

    return (
      <div
        key={clip.id}
        className='relative flex h-full flex-col bg-background-primary'
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
      >
        <div
          ref={containerRef}
          className='scrollbar-thin scrollbar-thumb-white/20 scrollbar-track-transparent flex-1 overflow-x-hidden overflow-y-auto'
        >
          {isHovered && (
            <div
              className='fixed top-2 right-2 z-10'
              style={{
                opacity: overlayOpacity,
                transition: 'opacity 0.1s ease-out',
              }}
            >
              <CloseButton onClick={() => closeClipPreview()} />
            </div>
          )}
          <div className='sticky top-0 z-0'>
            <LargeSongCard
              rounded={false}
              clip={clip}
              preview
              sunoShortType={sunoShortType}
            />
            <div
              className='pointer-events-none absolute right-0 bottom-0 left-0'
              style={{
                height: '150px',
                background:
                  'linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,0.5) 40%, rgba(0,0,0,0.8) 70%, rgba(0,0,0,1) 100%)',
              }}
            />
          </div>

          <div
            className='relative z-10 -mt-[70px] flex flex-col'
            style={{
              background: `linear-gradient(
                to bottom,
                rgb(var(--rgb-background-primary) / 0) 0%,
                rgb(var(--rgb-background-primary) / 1) 150px
              )`,
            }}
          >
            <div className='px-4'>
              <div
                className='mt-2 mb-3 flex flex-row items-center justify-center gap-1.5'
                style={{
                  opacity: 1,
                  transition: 'opacity 0.1s ease-out',
                }}
              >
                <CompactCardOverlayButton
                  className='flex-1'
                  aria-label='Play button with play count'
                  onClick={() => handlePlayClip(clip)}
                  icon={PlayIcon}
                >
                  {getCountString(clip.play_count || 0)}
                </CompactCardOverlayButton>
                <ClipLikeButton
                  clipId={clip.id}
                  onClick={handleLikeClick}
                  variant={ButtonVariant.Glass}
                  size={ButtonSize.Mini}
                  shape={ButtonShape.Rounded}
                  aspectSquare={false}
                  disabled={clip.preview_seconds !== undefined}
                  className={
                    'min-h-7 p-1.5 font-sans text-[11px] leading-none font-medium [&:hover]:bg-primary/10!'
                  }
                  contentClassName={'flex-row items-center gap-1'}
                  iconClassName={clsx('m-0 w-3.5 h-3.5', {
                    'text-white': !likeStatus,
                  })}
                />
                <CompactCardOverlayButton
                  className='flex-1'
                  aria-label='Downvote'
                  onClick={handleDislikeClick}
                  disabled={clip.preview_seconds !== undefined}
                  active={dislikeStatus}
                  icon={ThumbsDownIcon}
                />
                <CompactCardOverlayButton
                  className='flex-1'
                  aria-label='Share'
                  onClick={handleShare}
                  icon={ShareArrowIcon}
                />
              </div>

              <div className='flex items-start justify-between pt-5'>
                <Link
                  href={`/song/${clip.id}`}
                  className='line-clamp-2 flex-1 pr-2 text-xl text-foreground-primary hover:underline'
                >
                  {getClipTitle(clip)}
                </Link>
                {clip.preview_seconds === undefined && (
                  <SongMenuWithContext clip={clip} />
                )}
              </div>
            </div>

            <div className='mt-3 flex flex-col gap-3 px-4'>
              <div className='flex items-center gap-4'>
                {!!clip.handle && (
                  <ArtistTag
                    displayName={clip.display_name}
                    handle={clip.handle}
                    imageUrl={clip.avatar_image_url || undefined}
                  />
                )}
                {session.user?.id && clip.user_id !== session.user?.id && (
                  <Button
                    variant={ButtonVariant.Secondary}
                    active={isFollowing}
                    aspectSquare={false}
                    shape={ButtonShape.Pill}
                    size={ButtonSize.Mini}
                    icon={isFollowing ? UserAddedIcon : UserAddIcon}
                    onClick={handleFollow}
                  />
                )}
              </div>

              <span className='font-sans text-[14px] font-normal break-words whitespace-pre-wrap text-foreground-secondary'>
                <ClipCaption
                  caption={clip.caption || undefined}
                  clipId={clip.id}
                  clip={clip}
                  maxLength={100}
                  isSongOwner={
                    !!(session.userId && session.userId === clip.user_id)
                  }
                  displayButton={true}
                />
              </span>

              <SummaryOrFullTags
                tags={clip.metadata?.tags || undefined}
                negativeTags={clip.metadata?.negative_tags || undefined}
                displayTags={clip.display_tags || undefined}
              />

              {shouldShowPersona(clip.persona, session.user?.handle) && (
                <div
                  className={
                    'inline-block rounded-md bg-background-tertiary px-2 py-2'
                  }
                >
                  <PersonaTag persona={clip.persona} />
                </div>
              )}
            </div>

            {session?.flags?.['configs'] &&
              isDevOrStaging &&
              clip.metadata?.configurations &&
              Object.keys(clip.metadata.configurations).length > 0 && (
                <div className='mt-4 rounded-md bg-tertiary p-4 font-sans'>
                  <div className='mb-2 text-sm font-bold'>Configurations</div>
                  <ul>
                    {Object.entries(clip.metadata.configurations).map(
                      ([key, value]) => (
                        <li key={key} className='mb-1 text-xs'>
                          <span className='font-bold'>{key}:</span>&nbsp;
                          <span>{value}</span>
                        </li>
                      )
                    )}
                  </ul>
                </div>
              )}

            {session?.flags?.['control-sliders'] &&
              Object.entries(CONTROL_SLIDERS).some(([sliderKey]) =>
                isControlSliderEnabledForClip(
                  clip,
                  sliderKey as ControlSliderKey
                )
              ) && (
                <div className='m-4 rounded-md bg-background-tertiary p-4 font-sans'>
                  <div className='mb-2 text-sm font-bold'>Control Settings</div>
                  <ul>
                    {Object.entries(CONTROL_SLIDERS).map(([key, label]) => {
                      return isControlSliderEnabledForClip(
                        clip,
                        key as ControlSliderKey
                      ) ? (
                        <li key={key} className='mb-1 text-xs'>
                          <span className='font-bold'>{label}:</span>&nbsp;
                          <span>{`${Math.round((clip.metadata?.control_sliders?.[key as ControlSliderKey] ?? 0) * 100.0)}%`}</span>
                        </li>
                      ) : null;
                    })}
                  </ul>
                </div>
              )}

            {parentClip?.user_handle &&
              shouldShowRemixOf(clip, parentClip, session) && (
                <div className='px-4 pt-2 pb-4'>
                  <RemixOf
                    parentClip={parentClip}
                    contextId='clip_preview'
                    contextType={ContextType.CreateClipPreview}
                  />
                </div>
              )}

            {/* TODO: consolidate ClipLineageCard component calls */}
            {clip.metadata?.speed_clip_id &&
              shouldShowClipLineageCard(clip, parentClip, session) && (
                <ClipLineageCard
                  clipId={clip.metadata.speed_clip_id}
                  label='Adjusted Speed of'
                  contextId='clip_preview'
                  contextType={ContextType.CreateClipPreview}
                />
              )}
            {clip.metadata?.cover_clip_id &&
              shouldShowClipLineageCard(clip, parentClip, session) && (
                <ClipLineageCard
                  clipId={clip.metadata.cover_clip_id}
                  label='Cover of'
                  contextId='clip_preview'
                  contextType={ContextType.CreateClipPreview}
                />
              )}
            {clip.metadata?.upsample_clip_id &&
              shouldShowClipLineageCard(clip, parentClip, session) && (
                <ClipLineageCard
                  label='Remastered from'
                  clipId={clip.metadata.upsample_clip_id}
                  contextId='clip_preview'
                  contextType={ContextType.CreateClipPreview}
                />
              )}
            {clip.metadata?.history &&
              clip.metadata.history.length > 0 &&
              session.user?.id === clip.user_id &&
              clip.metadata?.task !== 'gen_stem' &&
              shouldShowClipLineageCard(clip, parentClip, session) && (
                <div className='p-4'>
                  <ExtendedFromDropdown
                    clipHistoryIds={clip.metadata.history.map((h: any) => h.id)}
                    contextId='clip_preview'
                    contextType={ContextType.CreateClipPreview}
                  />
                </div>
              )}
            {clip.metadata?.task === 'gen_stem' &&
              clip.metadata.stem_from_id &&
              shouldShowClipLineageCard(clip, parentClip, session) && (
                <ClipLineageCard
                  label='Stemmed from'
                  clipId={clip.metadata.stem_from_id}
                  contextId='clip_preview'
                  contextType={ContextType.CreateClipPreview}
                />
              )}
            {clip.metadata?.underpainting_clip_id &&
              shouldShowClipLineageCard(clip, parentClip, session) && (
                <ClipLineageCard
                  label='Vocals from'
                  clipId={clip.metadata.underpainting_clip_id}
                  contextId='clip_preview'
                  contextType={ContextType.CreateClipPreview}
                />
              )}
            {clip.metadata?.overpainting_clip_id &&
              shouldShowClipLineageCard(clip, parentClip, session) && (
                <ClipLineageCard
                  label='Instrumental from'
                  clipId={clip.metadata.overpainting_clip_id}
                  contextId='clip_preview'
                  contextType={ContextType.CreateClipPreview}
                />
              )}
            <span className='mt-4 mb-4 max-w-full px-4 font-sans text-[16px] font-normal break-words whitespace-pre-wrap text-foreground-primary'>
              {session.flags?.['edit-mode-ui'] &&
              startIndex !== undefined &&
              endIndex !== undefined ? (
                <>
                  {startIndex > 0 ? (
                    <span>{clip.metadata?.prompt?.slice(0, startIndex)}</span>
                  ) : null}
                  <span
                    ref={lyricsWindowRef}
                    className={
                      edit.activeEditTool === 'extend'
                        ? 'text-foreground-inactive'
                        : 'text-accent-pink'
                    }
                  >
                    {clip.metadata?.prompt?.slice(startIndex, endIndex)}
                  </span>
                  {endIndex < (clip.metadata?.prompt?.length || 0) ? (
                    <span>{clip.metadata?.prompt?.slice(endIndex)}</span>
                  ) : null}
                </>
              ) : (
                clip.metadata?.prompt
              )}
            </span>

            <span
              className='mb-6 max-w-full px-4 font-sans text-[12px] font-normal break-words whitespace-pre-wrap text-foreground-secondary'
              title={formatDateStringWTime(clip.created_at)}
            >
              {formatDateStringWTime(clip.created_at)}
            </span>
          </div>
          <div className='pb-24' />
        </div>

        <div className='absolute right-0 bottom-0 left-0 z-20 border-t border-white/10 bg-background-primary py-3'>
          <Remixes clip={clip} containerHeight={containerHeight} />
          <RemixOptions
            clip={clip}
            dropdownPosition='top'
            className={REMIX_OPTIONS_CLASSNAME}
            buttonClassName={twMerge(REMIX_OPTIONS_BUTTON_CLASSNAME, 'py-6')}
          />
        </div>
      </div>
    );
  }
);

export default ClipPreview;
