'use client';

/* eslint jsx-a11y/click-events-have-key-events: warn */
import { useStatsigClient } from '@statsig/react-bindings';
import { useQuery } from '@tanstack/react-query';
import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import { useRouter } from 'next/navigation';
import React, {
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import { useTranslation } from 'react-i18next';
import { deepCamelKeys } from 'string-ts';
import { twMerge } from 'tailwind-merge';

import { useStores } from '@/app/(root)/AppProviders';
import { UploadHookVideoScreenBody } from '@/app/(root)/hooks/create/UploadHookVideoScreen';
import UploadLoadingTile from '@/app/(root)/hooks/create/UploadLoadingTile';
import HookFormContext, {
  MAX_MEDIA_DESYNCED_MS,
} from '@/app/(root)/hooks/create/useHookForm';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import ImageWithFallback from '@/components/image/ImageWithFallback';
import { SkeletonBone } from '@/components/layout/Skeleton';
import PlaybackProgress from '@/components/mediaPlayback/PlaybackProgress';
import PlaybackProgressHoverOverlay, {
  PlaybackProgressHoverOverlayProps,
} from '@/components/mediaPlayback/PlaybackProgressHoverOverlay';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import ConfirmationModal from '@/components/modal/publishSong/ConfirmationModal';
import LyricsRenderer, {
  LyricsHighlightMode,
} from '@/components/omniplayer/LyricsRenderer';
import { formatDuration } from '@/components/song/songUtils';
import SpinnerSVG from '@/components/svg/SpinnerSVG';
import Filmstrip from '@/components/timeline/Filmstrip';
import LinesWaveform from '@/components/timeline/LinesWaveform';
import Trimmer, { TrimmerDragType } from '@/components/timeline/Trimmer';
import { Tooltip } from '@/components/tooltip/Tooltip';
import SimpleVideoPlayer, {
  VideoPlayerInterface,
} from '@/components/video/SimpleVideoPlayer';
import { useAlignedLyricsV2 } from '@/hooks/useAlignedLyrics';
import { useBreakpointMd } from '@/hooks/useBreakpoint';
import useMediaPlayback from '@/hooks/useMediaPlayback';
import usePolledValue from '@/hooks/usePolledValue';
import {
  CloseIcon,
  LyricsIcon,
  MusicNoteIcon,
  PreviousTrackIcon,
  ScissorsIcon,
  StatefulPlayPauseIcon,
  StemsIcon,
  VolumeMuteIcon,
  VolumeOnIcon,
} from '@/icons';
import { useApiClient } from '@/lib/apiClient';
import logWebUserEvent from '@/logging/logWebUserEvent';
import { SMALL_IMAGE } from '@/utils/constants';

// @TODO: Remove this dev stuff
const DEBUG_HOOKS_TRIMMER = false;
function formatDurationMs(timeMs: number) {
  return (timeMs / 1000).toFixed(2);
}

const getTooltipContent = (
  uploadStatus: string,
  audioAlignmentTimestamp: number | null
) => {
  switch (uploadStatus) {
    case 'complete':
      if (audioAlignmentTimestamp != null) {
        return `Audio aligned with video at ${audioAlignmentTimestamp.toFixed(2)}s`;
      }
      return 'Audio alignment not detected';
    case 'processing':
      return 'Detecting audio alignment...';
    case 'error':
      return 'Error detecting audio alignment';
    case 'uploading':
      return 'Uploading video...';
    default:
      return 'Please upload video first';
  }
};

const TrimmerHoverOverlay = (props: PlaybackProgressHoverOverlayProps) => {
  const {
    currentTime: currentTimeMs,
    hoverTime: hoverTimeMs,
    ...restProps
  } = props;

  const currentTime = currentTimeMs && currentTimeMs / 1000;
  const hoverTime = hoverTimeMs && hoverTimeMs / 1000;

  return (
    <PlaybackProgressHoverOverlay
      currentTime={currentTime}
      hoverTime={hoverTime}
      {...restProps}
    >
      {formatDuration(hoverTime ?? 0, false, true)}
    </PlaybackProgressHoverOverlay>
  );
};

export const HookFormHeader: React.FC<React.HTMLAttributes<HTMLDivElement>> =
  observer((props) => {
    const { className, ...restProps } = props;
    const { menus } = useStores();
    const { navigateTo, selectedVideo, selectedSong } =
      useContext(HookFormContext);

    const isMobile = !useBreakpointMd();

    const handleReplaceVideo = () => {
      menus.openModal(ModalTypes.SELECT_HOOK_SONG);
      navigateTo('uploadVideo');
    };

    const handleReplaceSong = () => {
      menus.openModal(ModalTypes.SELECT_HOOK_SONG);
      navigateTo('selectSong');
    };

    return (
      <div
        className={twMerge(
          'flex h-fit w-full flex-row items-center justify-between p-4 text-foreground-primary',
          'max-md:p-2',
          className
        )}
        {...restProps}
      >
        <h1 className='text-2xl max-md:text-base'>Edit Hook</h1>
        <div className='flex flex-row gap-2'>
          <Button
            shape={ButtonShape.Pill}
            size={isMobile ? ButtonSize.Mini : ButtonSize.Small}
            onClick={handleReplaceVideo}
          >
            {selectedVideo ? 'Replace Video' : 'Upload Video'}
          </Button>
          <Button
            shape={ButtonShape.Pill}
            size={isMobile ? ButtonSize.Mini : ButtonSize.Small}
            onClick={handleReplaceSong}
          >
            {selectedSong ? 'Replace Song' : 'Select Song'}
          </Button>
        </div>
      </div>
    );
  });

export const WaveformTrimmer: React.FC<{
  onDragStart?: () => void;
  onDragEnd?: () => void;
}> = (props) => {
  const { onDragStart, onDragEnd } = props;

  const { selectedSong, selectedVideo, mediaEditState } =
    useContext(HookFormContext);

  return (
    selectedSong && (
      <div className='relative w-full pt-4'>
        <Trimmer
          className='[--trimmer-padding:1.5rem]'
          rangeContainerClassName='text-accent-brand'
          contentClassName='bg-background-secondary'
          playheadClassName='hidden'
          progressClassName='block'
          tooltipClassName='bottom-auto top-full'
          disableHandles
          disableRange={!selectedVideo}
          start={mediaEditState.audioStart}
          end={mediaEditState.audioEnd}
          duration={mediaEditState.audioDuration}
          viewportStart={mediaEditState.audioViewportStart}
          viewportEnd={mediaEditState.audioViewportEnd}
          current={mediaEditState.current}
          dragType={TrimmerDragType.Content}
          onDragStart={onDragStart}
          onDragEnd={onDragEnd}
          onRangeSet={mediaEditState.onAudioRangeSet}
          renderTooltip={TrimmerHoverOverlay}
        >
          <LinesWaveform
            src={selectedSong?.audio_url || ''}
            className='absolute inset-x-0 inset-y-2 mask-(--trimmer-mask)'
          />
        </Trimmer>
        <div className='absolute inset-x-0 top-0 z-10 flex flex-row items-center justify-center'>
          <div
            className={clsx(
              'pointer-events-none rounded-full border-2 px-2 pt-1 pb-1.5',
              'font-mono text-[10px] leading-3 font-medium',
              'border-background-secondary bg-foreground-primary text-background-primary'
            )}
          >
            {formatDuration(mediaEditState.current / 1000, false, false)}
          </div>
        </div>
      </div>
    )
  );
};

export const VideoTrimmer: React.FC<{
  onCurrentTimeSet: (value: number) => void;
  onDragStart?: () => void;
  onDragEnd?: () => void;
}> = (props) => {
  const { onCurrentTimeSet, onDragStart, onDragEnd } = props;

  const { mediaEditState } = useContext(HookFormContext);

  const { uploadId, uploadStatus } = useContext(HookFormContext);
  const apiClient = useApiClient();

  const { data: spriteData } = useQuery({
    enabled: !!uploadId && uploadStatus === 'complete',
    queryKey: ['videoSprite', uploadId],
    queryFn: async () => {
      const response = await apiClient.GET(`/api/video/sprite`, {
        params: { query: { entity_id: uploadId, type: 'video_upload' } },
      });
      if (!response.data) return undefined;
      const data = deepCamelKeys(response.data);
      const thumbnailColumns = Math.floor(
        data.imageWidth / data.thumbnailWidth
      );
      const thumbnailRows = Math.floor(data.imageHeight / data.thumbnailHeight);
      return {
        ...data,
        filmstripUrl: `https://cdn1.suno.ai/${data.s3Id}.jpeg`,
        thumbnailColumns,
        thumbnailRows,
        thumbnailCount: data.totalFrames ?? thumbnailColumns * thumbnailRows,
      };
    },
  });

  const currentTime =
    mediaEditState.current -
    mediaEditState.audioStart +
    mediaEditState.videoStart;

  return (
    <Trimmer
      contentClassName='bg-background-secondary'
      className='w-full'
      start={mediaEditState.videoStart}
      end={mediaEditState.videoEnd}
      duration={mediaEditState.videoDuration}
      viewportStart={mediaEditState.videoViewportStart}
      viewportEnd={mediaEditState.videoViewportEnd}
      onRangeSet={mediaEditState.onVideoRangeSet}
      current={currentTime}
      onCurrentTimeSet={onCurrentTimeSet}
      onDragStart={onDragStart}
      onDragEnd={onDragEnd}
      renderTooltip={TrimmerHoverOverlay}
    >
      {spriteData?.filmstripUrl ? (
        <Filmstrip
          className='absolute inset-0'
          src={spriteData.filmstripUrl}
          thumbnailColumns={spriteData.thumbnailColumns}
          thumbnailWidth={spriteData.thumbnailWidth}
          thumbnailHeight={spriteData.thumbnailHeight}
          thumbnailCount={spriteData.thumbnailCount}
        />
      ) : (
        <SkeletonBone
          className='absolute inset-0 flex h-auto items-center justify-center gap-2 rounded-md bg-background-tertiary'
          as='div'
        >
          <span className='text-foreground-tertiary'>Processing video...</span>
        </SkeletonBone>
      )}
    </Trimmer>
  );
};

const HookAudioControlItem: React.FC<
  {
    enabled?: boolean;
    imageUrl?: string;
    title?: React.ReactNode;
    description?: React.ReactNode;
  } & Omit<
    React.HTMLAttributes<HTMLDivElement>,
    'enabled' | 'title' | 'description'
  >
> = (props) => {
  const {
    className,
    enabled,
    imageUrl,
    title,
    description,
    onClick,
    ...restProps
  } = props;
  return (
    <div
      className={twMerge(
        clsx(
          'flex flex-row items-center gap-2 rounded-xl bg-background-fog-thin p-3',
          {
            'cursor-pointer hover:bg-background-fog-thick': !!onClick,
          }
        ),
        className
      )}
      onClick={onClick}
      role={onClick ? 'button' : undefined}
      {...restProps}
    >
      <div className=''>
        <ImageWithFallback
          className='lazyload h-8 w-8 rounded-lg object-cover'
          src={imageUrl}
          imageSize={SMALL_IMAGE}
          alt=''
        />
      </div>
      <div className='min-w-0 flex-1'>
        {title && (
          <p className='text-sm font-semibold text-foreground-primary'>
            {title}
          </p>
        )}
        {description && (
          <p className='text-xs text-foreground-secondary'>{description}</p>
        )}
      </div>
      <div>
        <Button
          variant={ButtonVariant.Primary}
          shape={ButtonShape.Pill}
          size={ButtonSize.Small}
          active={enabled}
          icon={enabled ? VolumeOnIcon : VolumeMuteIcon}
        />
      </div>
    </div>
  );
};

const HookAudioControls: React.FC<
  {
    enableSongSound?: boolean;
    enableVideoSound?: boolean;
    clipTitle?: string;
    clipArtist?: string;
    clipImageUrl?: string;
    onSetSongSound?: () => void;
    onSetVideoSound?: () => void;
    onClose?: () => void;
  } & React.HTMLAttributes<HTMLDivElement>
> = (props) => {
  const {
    className,
    enableSongSound,
    enableVideoSound,
    clipTitle,
    clipArtist,
    clipImageUrl,
    onSetSongSound,
    onSetVideoSound,
    onClose,
    ...restProps
  } = props;

  const { t } = useTranslation();

  return (
    <div
      className={twMerge(
        'relative flex flex-col gap-2 p-4',
        'bg-background-tertiary',
        className
      )}
      {...restProps}
    >
      <div>
        <h4 className='text-base font-semibold text-foreground-primary'>
          {t('hooks.audioControls')}
        </h4>
        <p className='text-sm text-foreground-secondary'>
          {t('hooks.oneAudioSource')}
        </p>
      </div>
      <div className='flex flex-col gap-2'>
        <HookAudioControlItem
          onClick={onSetVideoSound}
          enabled={enableVideoSound}
          title={t('hooks.videoSound')}
          description={t('hooks.videoSound.description')}
          // imageUrl={clipImageUrl} // @TODO: Pull thumbnail from video instead
        />
        <HookAudioControlItem
          onClick={onSetSongSound}
          enabled={enableSongSound}
          title={clipTitle || t('hooks.clipSound')}
          description={
            clipArtist ? `by ${clipArtist}` : t('hooks.clipSound.description')
          }
          imageUrl={clipImageUrl}
        />
      </div>
      {onClose && (
        <Button
          className='absolute top-2 right-2'
          variant={ButtonVariant.Tertiary}
          shape={ButtonShape.Pill}
          size={ButtonSize.Small}
          icon={CloseIcon}
          onClick={onClose}
        />
      )}
    </div>
  );
};

export const HookFormBody: React.FC<React.HTMLAttributes<HTMLDivElement>> = (
  props
) => {
  const { className, ...restProps } = props;

  const { t } = useTranslation();
  const statsigClient = useStatsigClient();
  const videoAlignmentGate = statsigClient.checkGate('hooks-video-alignment');
  const videoRef = useRef<VideoPlayerInterface>(null);

  const {
    selectedVideo,
    selectedSong,
    uploadStatus,
    videoUrl,
    videoDimensions,
    mediaEditState,
    uploadProgress,
    videoSound,
    uploadId,
    setVideoSound,
    showLyrics,
    setShowLyrics,
    audioAlignmentTimestamp,
  } = useContext(HookFormContext);

  const { onCurrentTimeSet, onAudioRangeSet } = mediaEditState;

  const { alignedLyrics } = useAlignedLyricsV2(selectedSong?.id || '', {
    enabled: !!selectedSong?.id && showLyrics && !videoSound,
  });

  const tooltipContent = getTooltipContent(
    uploadStatus || '',
    audioAlignmentTimestamp
  );

  const [isTrimming, setIsTrimming] = useState(false);
  const [isLoopEnabled, setIsLoopEnabled] = useState(false);
  const [showAudioControls, setShowAudioControls] = useState(false);

  const handleTrimVideoClick = useCallback(() => {
    // Log video trim action
    logWebUserEvent({
      actionName: 'HookVideoEdit',
      context: {
        uploadId: uploadId || undefined,
        clipId: selectedSong?.id || undefined,
        editType: 'videoTrim',
      },
    });

    setIsTrimming((prevIsTrimming) => !prevIsTrimming);
  }, [uploadId, selectedSong?.id]);

  const handleSongSoundClick = useCallback(() => {
    // Log combined audio source change
    logWebUserEvent({
      actionName: 'HookVideoEdit',
      context: {
        uploadId: uploadId || undefined,
        clipId: selectedSong?.id || undefined,
        editType: 'volumeAdjustment',
        videoSound: false,
        showLyrics: true,
      },
    });

    setVideoSound(false);
    setShowLyrics(true);
  }, [setVideoSound, setShowLyrics, uploadId, selectedSong?.id]);
  const handleVideoSoundClick = useCallback(() => {
    // Log combined audio source change
    logWebUserEvent({
      actionName: 'HookVideoEdit',
      context: {
        uploadId: uploadId || undefined,
        clipId: selectedSong?.id || undefined,
        editType: 'volumeAdjustment',
        videoSound: true,
        showLyrics: false,
      },
    });

    setVideoSound(true);
    setShowLyrics(false);
  }, [setVideoSound, setShowLyrics, uploadId, selectedSong?.id]);
  const handleAudioLevelsClick = useCallback(() => {
    setShowAudioControls((prevShowAudioControls) => !prevShowAudioControls);
  }, []);

  const audioPlayback = useMediaPlayback({
    onPlay() {
      const currentTime = getCurrentTimeMs();
      const { audioStart, audioEnd } = mediaEditStateRef.current;
      if (currentTime < audioStart || currentTime >= audioEnd) {
        seekMs(mediaEditStateRef.current.audioStart);
      } else {
        getCurrentTimeWithVideoSync();
      }
    },
    onPause() {
      getCurrentTimeWithVideoSync();
    },
  });
  const audioPlaybackRef = useRef(audioPlayback);
  useEffect(() => {
    audioPlaybackRef.current = audioPlayback;
  }, [audioPlayback]);
  const {
    isPlaying,
    load,
    toggle,
    play,
    pause,
    seek,
    setMuted,
    getCurrentTime,
    addTimeCallback,
    clearTimeCallbacks,
  } = audioPlayback;

  useEffect(() => {
    setMuted(videoSound);
  }, [videoSound, setMuted]);

  const getCurrentTimeMs = useCallback(() => {
    return Math.round(getCurrentTime() * 1000);
  }, [getCurrentTime]);
  const seekMs = useCallback(
    (timeMs: number) => {
      seek(timeMs / 1000);
    },
    [seek]
  );

  useEffect(() => {
    if (selectedSong?.audio_url) {
      load(selectedSong.audio_url);
    }
  }, [selectedSong?.audio_url, load]);

  const mediaEditStateRef = useRef(mediaEditState);
  useEffect(() => {
    mediaEditStateRef.current = mediaEditState;
  }, [mediaEditState]);

  const getCurrentTimeWithVideoSync = useCallback(() => {
    const currentTime = getCurrentTimeMs();
    if (videoRef.current) {
      const { videoStart, audioStart } = mediaEditStateRef.current;
      const targetVideoTimeMs = currentTime + videoStart - audioStart;
      const currentVideoTime = Math.round(
        videoRef.current.getCurrentTime() * 1000
      );
      const mediaDesyncedMs = Math.abs(targetVideoTimeMs - currentVideoTime);
      if (!videoSound && mediaDesyncedMs >= MAX_MEDIA_DESYNCED_MS) {
        const targetVideoTime =
          targetVideoTimeMs < 1000
            ? Math.round(targetVideoTimeMs / 1000)
            : targetVideoTimeMs / 1000;
        videoRef.current.seek(targetVideoTime);
      }
    }
    return currentTime;
  }, [getCurrentTimeMs, videoSound]);

  const [currentTime, updateCurrentTime] = usePolledValue(
    getCurrentTimeWithVideoSync,
    {
      enabled: isPlaying,
      pollingInterval: 16,
    }
  );
  useEffect(() => {
    onCurrentTimeSet(currentTime);
  }, [currentTime, onCurrentTimeSet]);

  const handleRestartClick = useCallback(() => {
    const { videoStart, audioStart, current } = mediaEditStateRef.current;
    const targetVideoTimeMs = current + videoStart - audioStart;
    const targetVideoTime =
      targetVideoTimeMs < 1000
        ? Math.round(targetVideoTimeMs / 1000)
        : targetVideoTimeMs / 1000;
    seekMs(audioStart);
    videoRef.current?.seek(targetVideoTime);
    updateCurrentTime();
  }, [seekMs, updateCurrentTime]);

  const handlePlayPauseClick = useCallback(
    (e: React.MouseEvent) => {
      // Make sure to sync the video
      const { videoStart, audioStart, current } = mediaEditStateRef.current;
      const targetVideoTimeMs = current + videoStart - audioStart;
      const targetVideoTime =
        targetVideoTimeMs < 1000
          ? Math.round(targetVideoTimeMs / 1000)
          : targetVideoTimeMs / 1000;
      videoRef.current?.seek(targetVideoTime);
      // Now start playing
      toggle();
      setIsLoopEnabled(!e.shiftKey);
    },
    [toggle]
  );

  useEffect(() => {
    // Require a minimum audio length
    if (mediaEditState.audioEnd - mediaEditState.audioStart < 1000) return;
    // Listener to handle looping
    addTimeCallback(
      mediaEditState.audioEnd / 1000,
      () => {
        if (audioPlaybackRef.current.isPlaying) {
          if (!isLoopEnabled) {
            pause();
          }
          const { videoStart, audioStart, current } = mediaEditStateRef.current;
          const targetVideoTimeMs = current + videoStart - audioStart;
          const targetVideoTime =
            targetVideoTimeMs < 1000
              ? Math.round(targetVideoTimeMs / 1000)
              : targetVideoTimeMs / 1000;
          seekMs(audioStart);
          videoRef.current?.seek(targetVideoTime / 1000);
        }
      },
      {
        id: 'hookAudioEnd',
        once: false,
      }
    );
    return () => {
      clearTimeCallbacks();
    };
  }, [
    mediaEditState.audioStart,
    mediaEditState.audioEnd,
    pause,
    seekMs,
    addTimeCallback,
    clearTimeCallbacks,
    isLoopEnabled,
  ]);

  const handleVideoCurrentTimeSet = useCallback(
    (videoCurrentTimeMs: number) => {
      const { videoStart, audioStart } = mediaEditStateRef.current;
      const currentTime = videoCurrentTimeMs - videoStart + audioStart;
      onCurrentTimeSet(currentTime);
      seekMs(currentTime);
      const targetVideoTime =
        videoCurrentTimeMs < 1000
          ? Math.round(videoCurrentTimeMs / 1000)
          : videoCurrentTimeMs / 1000;
      videoRef.current?.seek(targetVideoTime);
    },
    [seekMs, onCurrentTimeSet]
  );

  const playAfterSeek = useRef(false);
  const [isSeeking, setIsSeeking] = useState(false);
  const handleSeekStart = useCallback(() => {
    setIsSeeking(true);
    playAfterSeek.current = audioPlaybackRef.current.isPlaying;
    pause();
  }, [pause]);
  const handleSeekEnd = useCallback(() => {
    setIsSeeking(false);
    seekMs(mediaEditStateRef.current.current);
    if (playAfterSeek.current) {
      play();
    }
  }, [play, seekMs]);
  const handleSeekTo = useCallback(
    (time: number | null) => {
      if (time != null) {
        const hookCurrentTimeMs = Math.round(time * 1000);
        const { videoStart, audioStart } = mediaEditStateRef.current;
        const audioCurrentTimeMs = hookCurrentTimeMs + audioStart;
        const videoCurrentTimeMs = hookCurrentTimeMs + videoStart;
        onCurrentTimeSet(audioCurrentTimeMs);
        seekMs(audioCurrentTimeMs);
        videoRef.current?.seek(videoCurrentTimeMs / 1000);
      }
    },
    [seekMs, onCurrentTimeSet]
  );

  const hookCurrentTimeSeconds =
    (mediaEditState.current - mediaEditState.audioStart) / 1000;
  const hookDurationSeconds = mediaEditState.duration / 1000;

  // Convert hook-relative time to absolute song time for lyrics (updates during scrubbing)
  const lyricsScrubTime = useMemo(() => {
    if (!selectedSong) return undefined;
    // hookCurrentTimeSeconds is relative to the hook segment
    // Add audioStart to get absolute position in the full song
    return hookCurrentTimeSeconds + mediaEditState.audioStart / 1000;
  }, [hookCurrentTimeSeconds, mediaEditState.audioStart, selectedSong]);

  const [videoWidth, videoHeight] = videoDimensions;
  const aspectRatio =
    videoWidth && videoHeight ? `${videoWidth}/${videoHeight}` : undefined;

  const isLandscapeOrientation = videoWidth > videoHeight;

  const syncButtonText =
    audioAlignmentTimestamp != null &&
    audioAlignmentTimestamp * 1000 === mediaEditState.audioStart
      ? 'Synced with Video'
      : 'Sync Audio With Video';
  return (
    <div
      className={twMerge(
        'flex w-full flex-col items-stretch justify-start gap-4',
        className
      )}
      data-media-playing={isPlaying}
      {...restProps}
    >
      <div
        className={clsx(
          'relative flex w-full flex-row justify-center gap-4 overflow-clip px-4',
          {
            'max-h-[calc(100svh-30rem)]': isLandscapeOrientation,
            'h-[calc(100svh-30rem)] min-h-40': !isLandscapeOrientation,
          }
        )}
      >
        {uploadStatus === 'uploading' ? (
          <UploadLoadingTile uploadProgress={uploadProgress} />
        ) : selectedVideo && uploadStatus !== 'error' ? (
          <div
            className={clsx('relative', {
              'aspect-video w-full': isLandscapeOrientation,
              'aspect-9/16 h-full': !isLandscapeOrientation,
            })}
            style={{ aspectRatio }}
          >
            <SimpleVideoPlayer
              ref={videoRef}
              playing={!isSeeking && isPlaying}
              className='absolute inset-0 h-full w-full overflow-clip rounded-xl'
              url={videoUrl}
              loop={false}
              muted={!videoSound}
              volume={1}
            />
            {showLyrics && !videoSound && alignedLyrics && (
              <div className='pointer-events-none absolute inset-0 overflow-hidden rounded-xl'>
                <div className='relative h-full w-full'>
                  <div
                    className='absolute inset-0 flex items-end justify-start'
                    style={{
                      aspectRatio,
                      objectFit: 'contain',
                      margin: 'auto',
                      maxWidth: '100%',
                      maxHeight: '100%',
                    }}
                  >
                    <div className='p-4 pb-6'>
                      <LyricsRenderer
                        alignedLyrics={alignedLyrics}
                        currentTime={lyricsScrubTime}
                        className='font-sans text-base font-bold'
                        lineClassName='hidden data-highlight:block animate-fade-in'
                        wordClassName='text-foreground-tertiary-glass data-highlight:text-foreground-primary-glass data-highlight:duration-100 transition-colors [text-shadow:0px_1px_3px_rgba(0,0,0,0.5)]'
                        highlightMode={LyricsHighlightMode.Group}
                        groupLines={true}
                        maxGroupDuration={Infinity}
                        maxLinesPerGroup={2}
                        highlightLineOffsetStart={-0.1}
                        highlightLineOffsetEnd={-0.1}
                        highlightWordOffsetStart={-0.1}
                        highlightWordOffsetEnd={-0.1}
                      />
                    </div>
                  </div>
                </div>
              </div>
            )}
            {uploadStatus === 'processing' ? (
              <Button
                className='absolute top-2 right-2'
                variant={ButtonVariant.Glass}
                shape={ButtonShape.Pill}
                size={ButtonSize.Mini}
                icon={<SpinnerSVG />}
              >
                Processing...
              </Button>
            ) : null}
          </div>
        ) : (
          <div
            className='flex h-full w-max cursor-pointer flex-col items-center justify-center gap-4 rounded-xl border border-border-secondary p-10'
            // style={{ height: VIDEO_WIDTH }}
          >
            <UploadHookVideoScreenBody />
          </div>
        )}
        <div className='absolute inset-y-0 right-2 flex flex-col items-center justify-center gap-2'>
          <div>
            <Button
              variant={ButtonVariant.Primary}
              shape={ButtonShape.Pill}
              size={ButtonSize.Medium}
              active={isTrimming}
              onClick={handleTrimVideoClick}
              icon={ScissorsIcon}
              aria-label={t('hooks.trimVideo')}
            />
          </div>
          <div>
            <Button
              variant={ButtonVariant.Primary}
              shape={ButtonShape.Pill}
              size={ButtonSize.Medium}
              active={!videoSound}
              // onClick={handleTrimVideoClick}
              icon={StemsIcon}
              aria-label={t('hooks.audioSync')}
              disabled={videoSound}
            />
          </div>
          <div>
            <Button
              variant={ButtonVariant.Primary}
              shape={ButtonShape.Pill}
              size={ButtonSize.Medium}
              active={showLyrics && !videoSound}
              onClick={() => setShowLyrics(!showLyrics)}
              icon={LyricsIcon}
              aria-label={t('hooks.toggleLyrics')}
              disabled={videoSound}
            />
          </div>
          <div className='relative'>
            <Button
              variant={ButtonVariant.Primary}
              shape={ButtonShape.Pill}
              size={ButtonSize.Medium}
              active={showAudioControls}
              onClick={handleAudioLevelsClick}
              icon={VolumeOnIcon}
              aria-label={t('hooks.audioControls')}
            />
            {showAudioControls && (
              <HookAudioControls
                className='absolute right-[calc(100%+1rem)] bottom-0 w-80 rounded-3xl'
                clipImageUrl={selectedSong?.image_url || ''}
                enableSongSound={!videoSound}
                enableVideoSound={videoSound}
                onSetSongSound={handleSongSoundClick}
                onSetVideoSound={handleVideoSoundClick}
                onClose={() => {
                  setShowAudioControls(false);
                }}
              />
            )}
          </div>
        </div>
      </div>
      <div className='flex flex-row items-center justify-between gap-2 px-4'>
        <div className='flex flex-1 flex-row justify-start'>
          <Button
            variant={ButtonVariant.Tertiary}
            shape={ButtonShape.Pill}
            size={ButtonSize.Small}
            icon={PreviousTrackIcon}
            onClick={handleRestartClick}
          />
        </div>
        <div className='flex flex-2 flex-row items-center justify-center gap-2'>
          <div className='flex flex-row items-center justify-center'>
            <Button
              variant={ButtonVariant.Tertiary}
              shape={ButtonShape.Pill}
              size={ButtonSize.Medium}
              icon={StatefulPlayPauseIcon}
              iconClassName='m-0 w-6 h-6'
              onClick={handlePlayPauseClick}
              disabled={!selectedSong}
              // disabled={!selectedSong || !selectedVideo}
            />
          </div>
          <div className='font-mono text-xs tracking-tight text-foreground-inactive tabular-nums'>
            <span className='text-foreground-primary'>
              {formatDuration(Math.max(0, hookCurrentTimeSeconds))}
            </span>
            {' / '}
            {formatDuration(hookDurationSeconds)}
          </div>
        </div>
        <div className='flex flex-1 flex-row justify-end'>
          {videoAlignmentGate && (
            <Tooltip label={tooltipContent || ''}>
              <Button
                size={ButtonSize.Small}
                shape={ButtonShape.Pill}
                disabled={
                  uploadStatus !== 'complete' ||
                  audioAlignmentTimestamp == null ||
                  (audioAlignmentTimestamp || 0) * 1000 ===
                    mediaEditState.audioStart
                }
                onClick={() => {
                  // Log sync audio action
                  logWebUserEvent({
                    actionName: 'HookVideoEdit',
                    context: {
                      uploadId: uploadId || undefined,
                      clipId: selectedSong?.id || undefined,
                      editType: 'syncAudio',
                    },
                  });

                  // Convert seconds to milliseconds for onAudioRangeSet
                  const alignmentTimeMs = (audioAlignmentTimestamp || 0) * 1000;
                  onAudioRangeSet(alignmentTimeMs);
                }}
                iconStart={
                  uploadStatus &&
                  ['processing', 'uploading'].includes(uploadStatus) ? (
                    <SpinnerSVG />
                  ) : (
                    MusicNoteIcon
                  )
                }
              >
                {syncButtonText}
              </Button>
            </Tooltip>
          )}
        </div>
      </div>
      <div className='flex min-h-12 items-center justify-stretch'>
        {isTrimming ? (
          <div className='flex w-full flex-col items-center justify-center gap-4 px-6'>
            <VideoTrimmer
              onCurrentTimeSet={handleVideoCurrentTimeSet}
              onDragStart={handleSeekStart}
              onDragEnd={handleSeekEnd}
            />
          </div>
        ) : (
          <div className='flex w-full flex-col items-center justify-center gap-4 px-6 pt-4'>
            <PlaybackProgress
              className={clsx(
                'w-full',
                '[--track-progress-color:var(--color-foreground-primary)]',
                '[--track-remaining-color:var(--color-background-tertiary)]',
                '[--button-color:var(--color-foreground-primary)]',
                '[--time-color:var(--color-foreground-tertiary)]'
              )}
              showTime={false}
              currentTime={hookCurrentTimeSeconds}
              duration={hookDurationSeconds}
              onSeekStart={handleSeekStart}
              onSeekEnd={handleSeekEnd}
              onSeekTo={handleSeekTo}
              renderTooltip={PlaybackProgressHoverOverlay}
            />
          </div>
        )}
      </div>
      <div className='flex h-12 w-full flex-row justify-center gap-4 overflow-x-clip'>
        {selectedSong?.audio_url ? (
          <div
            className={clsx(
              'relative flex h-full w-full flex-col items-center justify-center gap-4',
              { hidden: videoSound }
            )}
          >
            <WaveformTrimmer
              onDragStart={handleSeekStart}
              onDragEnd={handleSeekEnd}
            />
          </div>
        ) : (
          <div className='flex h-full w-full flex-col items-center justify-center gap-4 text-foreground-primary'>
            <p>No song selected</p>
          </div>
        )}
      </div>
      {!DEBUG_HOOKS_TRIMMER ? null : (
        <div>
          <div className='flex flex-row gap-4'>
            <div>Audio time: {formatDurationMs(mediaEditState.current)}</div>
            <div>
              Video time:{' '}
              {formatDurationMs(
                mediaEditState.current -
                  mediaEditState.audioStart +
                  mediaEditState.videoStart
              )}
            </div>
          </div>
          <div className='flex flex-row gap-4'>
            <div>Video</div>
            <div>Start: {formatDurationMs(mediaEditState.videoStart)}</div>
            <div>End: {formatDurationMs(mediaEditState.videoEnd)}</div>
            <div>
              Range duration:{' '}
              {formatDurationMs(
                mediaEditState.videoEnd - mediaEditState.videoStart
              )}
            </div>
            <div>
              Viewport Start:{' '}
              {formatDurationMs(mediaEditState.videoViewportStart)}
            </div>
            <div>
              Viewport End: {formatDurationMs(mediaEditState.videoViewportEnd)}
            </div>
            <div>
              Total duration: {formatDurationMs(mediaEditState.videoDuration)}
            </div>
          </div>
          <div className='flex flex-row gap-4'>
            <div>Audio</div>
            <div>Start: {formatDurationMs(mediaEditState.audioStart)}</div>
            <div>End: {formatDurationMs(mediaEditState.audioEnd)}</div>
            <div>
              Range duration:{' '}
              {formatDurationMs(
                mediaEditState.audioEnd - mediaEditState.audioStart
              )}
            </div>
            <div>
              Viewport Start:{' '}
              {formatDurationMs(mediaEditState.audioViewportStart)}
            </div>
            <div>
              Viewport End: {formatDurationMs(mediaEditState.audioViewportEnd)}
            </div>
            <div>
              Total duration: {formatDurationMs(mediaEditState.audioDuration)}
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

export const HookFormFooter: React.FC<React.HTMLAttributes<HTMLDivElement>> =
  observer((props) => {
    const { className, ...restProps } = props;

    const {
      selectedSong,
      selectedVideo,
      uploadStatus,
      uploadId,
      navigateTo,
      openModal,
      resetFormState,
    } = useContext(HookFormContext);
    const router = useRouter();

    const [isConfirmingClose, setIsConfirmingClose] = useState(false);
    const handleConfirmClose = () => {
      logWebUserEvent({
        actionName: 'HookCreationUserCancelled',
        context: {
          uploadId: uploadId || undefined,
        },
      });
      setIsConfirmingClose(false);
      resetFormState();
      router.push('/hooks');
    };

    return (
      <div
        className={twMerge(
          'flex h-fit flex-col justify-end gap-4 p-4',
          className
        )}
        {...restProps}
      >
        {/* TODO: make this render condition better + style modal */}
        {isConfirmingClose && (
          <ConfirmationModal
            onCancel={() => setIsConfirmingClose(false)}
            onConfirm={handleConfirmClose}
          />
        )}
        <div className='flex flex-row justify-end gap-4'>
          <Button
            shape={ButtonShape.Pill}
            size={ButtonSize.Medium}
            onClick={() => {
              setIsConfirmingClose(true);
            }}
          >
            Cancel
          </Button>
          <Button
            variant={ButtonVariant.Primary}
            shape={ButtonShape.Pill}
            size={ButtonSize.Medium}
            disabled={
              !selectedSong ||
              !selectedVideo ||
              uploadStatus === 'uploading' ||
              uploadStatus === 'processing' ||
              uploadStatus === 'error'
            }
            onClick={() => {
              openModal();
              navigateTo('postHook');
            }}
          >
            Next
          </Button>
        </div>
      </div>
    );
  });

export const EditHookForm = observer(() => {
  const { menus } = useStores();
  const statsigClient = useStatsigClient();
  const hooksEnabled = statsigClient.checkGate('web-hooks-2025');

  useEffect(() => {
    if (hooksEnabled) {
      menus.openModal(ModalTypes.SELECT_HOOK_SONG);
    } else {
      menus.closeModal(ModalTypes.SELECT_HOOK_SONG);
    }
    return () => {
      menus.closeModal(ModalTypes.SELECT_HOOK_SONG);
    };
  }, [hooksEnabled, menus]);

  if (!hooksEnabled) {
    return <div>Not found.</div>;
  }

  return (
    <div className='h-full w-screen p-3'>
      <div className='flex h-full flex-col gap-2 rounded-lg border border-background-tertiary bg-background-secondary'>
        <HookFormHeader className='border-b border-background-tertiary' />
        <div className='flex flex-1 flex-col overflow-y-auto'>
          <HookFormBody className='m-auto' />
        </div>
        <HookFormFooter className='border-t border-background-tertiary' />
      </div>
    </div>
  );
});

export default EditHookForm;
