import styled from '@emotion/styled';
import clsx from 'clsx';
import { uniq } from 'lodash-es';
import { useCallback, useEffect, useState } from 'react';

import useClip from '@/hooks/useClip';
import { useContext, useContextSelector } from '@/hooks/useContextSelector';
import {
  ClipZoomInIcon,
  FastForwardIcon,
  FollowPlayHeadIcon,
  LoopIcon,
  MinusIcon,
  PauseIcon,
  PlayIcon,
  PlusIcon,
  RewindIcon,
  UserIcon,
  Volume0Icon,
  VolumeDownIcon,
  VolumeOnIcon,
} from '@/icons';
import { getClipTitle } from '@/utils/clip';
import ctrlStr from '@/utils/ctrlStr';
import { truncateText } from '@/utils/utils';

import Button, { ButtonVariant } from '../button/Button';
import PopupFader from '../edit2025/PopupFader';
import TimeReadout from '../edit2025/TimeReadout';
import { SongImage } from '../edit2025/components';
import { Tooltip } from '../tooltip/Tooltip';
import BasicTempoControl from './BasicTempoControl';
import Metronome from './Metronome';
import StudioContext from './StudioContext';
import toggleMetronome from './actions/toggleMetronome';
import toggleTimelineLoop, {
  DEFAULT_LOOP_DURATION_BEATS,
} from './actions/toggleTimelineLoop';
import { setPointSelection } from './actions/updateSelection';
import {
  getSongEndBeats,
  getSongEndSeconds,
  getSongStartBeats,
  getStudioClips,
  getTracks,
} from './selectors';
import useZoomButtons from './useZoomButtons';

const Wrapper = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 20px;
  height: 100%;
  gap: 10px;
`;

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

export const PlayAndBackButtons = () => {
  const {
    playbackController,
    previewController,
    state,
    setState,
    timelineController,
  } = useContext(StudioContext);
  const followMode = timelineController.followMode;

  const handleFollowPlayheadClick = useCallback(() => {
    timelineController.setFollowMode((prev) => !prev);
  }, [timelineController, followMode]);

  const loopEnabled = state.loop.enabled;

  // The loop button should only be disabled in the uncommon case where there
  // has been no previous loop set, and there is no selection, like in a new project.

  const handleLoopClick = useCallback(() => {
    const startBeats = state.loop.startBeats || 0;
    const endBeats =
      state.loop.endBeats === state.loop.startBeats
        ? state.loop.startBeats + DEFAULT_LOOP_DURATION_BEATS
        : state.loop.endBeats;
    setState(toggleTimelineLoop(startBeats, endBeats));
  }, [setState, state.loop.startBeats, state.loop.endBeats]);

  return (
    <>
      <div className='flex items-center'>
        <Tooltip label='Back to Section Start' placement='top'>
          <Button
            className='h-[44px] rounded-r-none bg-background-secondary'
            onClick={() => {
              const currentBeats = playbackController.getCurrentBeats();
              const clips = getStudioClips(state) || [];
              const clipEndpoints = uniq(
                clips.flatMap((c) => [c.startBeats, c.endBeats])
              );

              const sectionStartBeats = clipEndpoints.reduce((acc, point) => {
                if (point > acc && point < currentBeats - 1) {
                  return point;
                }
                return acc;
              }, getSongStartBeats(state));

              playbackController.seek(sectionStartBeats);
              if (
                !playbackController.playing &&
                !previewController.previewingOnTimeline
              ) {
                setState(setPointSelection(sectionStartBeats));
              }
            }}
            icon={<RewindIcon className='h-6 w-6' />}
          />
        </Tooltip>

        <Tooltip label='Play/Pause (Spacebar)' placement='top'>
          {playbackController.playing &&
          !previewController.previewingOffTimeline ? (
            <Button
              className='h-[44px] rounded-none bg-background-secondary'
              onClick={() => {
                playbackController.setPlaying(false);
              }}
              icon={<PauseIcon className='h-6 w-6' />}
            />
          ) : (
            <Button
              className='h-[44px] rounded-none bg-background-secondary'
              onClick={() => {
                if (previewController.previewingOffTimeline) {
                  previewController.stopPreviewing();
                }
                setTimeout(() => {
                  playbackController.setPlaying(true);
                }, 0);
              }}
              icon={<PlayIcon className='h-6 w-6' />}
            />
          )}
        </Tooltip>

        <Tooltip label='Forward to Next Section Start' placement='top'>
          <Button
            className='h-[44px] rounded-l-none bg-background-secondary'
            onClick={() => {
              const currentBeats = playbackController.getCurrentBeats();
              const clips = getStudioClips(state) || [];
              const clipEndpoints = uniq(
                clips.flatMap((c) => [c.startBeats, c.endBeats])
              );

              const sectionStartBeats = clipEndpoints.reduce((acc, point) => {
                if (point < acc && point > currentBeats) {
                  return point;
                }
                return acc;
              }, getSongEndBeats(state));

              playbackController.seek(sectionStartBeats);
              if (
                !playbackController.playing &&
                !previewController.previewingOnTimeline
              ) {
                setState(setPointSelection(sectionStartBeats));
              }
            }}
            icon={<FastForwardIcon className='h-6 w-6' />}
          />
        </Tooltip>
      </div>

      <Tooltip label={`Loop [${ctrlStr} L]`} placement='top'>
        <Button
          className={clsx(
            `h-[44px]`,
            !loopEnabled && 'bg-background-secondary'
          )}
          onClick={handleLoopClick}
          variant={loopEnabled ? ButtonVariant.Primary : ButtonVariant.Standard}
          icon={<LoopIcon className='h-6 w-6' />}
        />
      </Tooltip>

      <Tooltip label={`Follow Playhead [${ctrlStr} F]`} placement='top'>
        <Button
          className={clsx(`h-[44px]`, !followMode && 'bg-background-secondary')}
          onClick={handleFollowPlayheadClick}
          variant={followMode ? ButtonVariant.Primary : ButtonVariant.Standard}
          icon={<FollowPlayHeadIcon className='h-6 w-6' />}
        />
      </Tooltip>
    </>
  );
};

export default function StudioTransport() {
  const playbackController = useContextSelector(
    StudioContext,
    (context) => context.playbackController
  );
  const previewingOffTimeline = useContextSelector(
    StudioContext,
    (context) => context.previewController.previewingOffTimeline
  );
  const masterVolume = useContextSelector(
    StudioContext,
    (context) => context.masterVolume
  );
  const setMasterVolume = useContextSelector(
    StudioContext,
    (context) => context.setMasterVolume
  );
  const editClipId = useContextSelector(
    StudioContext,
    (context) => context.state.editClipId
  );
  const firstTrackId = useContextSelector(
    StudioContext,
    (context) => getTracks(context.state)[0]?.id
  );
  const metronomeEnabled = useContextSelector(
    StudioContext,
    (context) => context.state.metronome.enabled
  );
  const setState = useContextSelector(
    StudioContext,
    (context) => context.setState
  );
  const handleToggleMetronome = useCallback(() => {
    setState(toggleMetronome());
  }, [setState]);
  const songEndSeconds = useContextSelector(StudioContext, (context) =>
    getSongEndSeconds(context.state)
  );

  const { clip } = useClip(editClipId);
  const [imageUrl, setImageUrl] = useState(clip?.image_url);
  useEffect(() => {
    setImageUrl(clip?.image_url);
  }, [clip?.image_url]);

  const [showVolume, setShowVolume] = useState(false);
  const [localVolume, setLocalVolume] = useState(masterVolume);

  const { handleZoomInMouseDown, handleZoomOutMouseDown, resetZoom } =
    useZoomButtons();

  return (
    <Wrapper>
      <TransportSection>
        {imageUrl && clip && (
          <SongImage
            className='h-[50px] w-[40px] rounded-md object-cover'
            onError={() =>
              setImageUrl('https://cdn-o.suno.com/auras/Aura-04.jpg')
            }
            src={imageUrl}
            alt={getClipTitle(clip)}
          />
        )}
        {clip && (
          <div className='flex flex-col items-start justify-center gap-1'>
            <a
              href={`/song/${clip.id}`}
              target='_blank'
              className='text-sm text-foreground-primary hover:underline'
            >
              {truncateText(getClipTitle(clip), 30)}
            </a>
            <div className='flex items-center gap-1 text-xs text-secondary'>
              <a
                href={`/@${clip.handle}`}
                target='_blank'
                className='flex items-center gap-1 hover:underline'
              >
                <UserIcon /> {clip?.display_name}
              </a>
            </div>
          </div>
        )}
      </TransportSection>

      <TransportSection>
        <PlayAndBackButtons />
      </TransportSection>

      <TransportSection>
        <TimeReadout
          getCurrentTime={() =>
            previewingOffTimeline
              ? 0
              : Math.max(0, playbackController.getCurrentSeconds())
          }
          songEndSeconds={songEndSeconds}
          timeDisplayStyle='millisecond'
          style={{ fontFamily: 'Input Sans, monospace', fontSize: '20px' }}
        />
      </TransportSection>

      <TransportSection>
        <BasicTempoControl />
        <Tooltip label='Toggle Metronome' openDelay={500}>
          <Button
            className={`relative h-[44px] p-3 ${!metronomeEnabled ? 'opacity-50' : ''}`}
            style={{
              transition: 'none',
            }}
            onClick={handleToggleMetronome}
          >
            <Metronome />
          </Button>
        </Tooltip>
      </TransportSection>

      <TransportSection>
        <div className='flex items-center'>
          <Tooltip label='Zoom Out' placement='top'>
            <Button
              onMouseDown={handleZoomOutMouseDown}
              icon={<MinusIcon className='h-6 w-6' />}
              className='h-[44px] rounded-r-none bg-background-secondary'
            />
          </Tooltip>
          <Tooltip label='Zoom In' placement='top'>
            <Button
              onMouseDown={handleZoomInMouseDown}
              icon={<PlusIcon className='h-6 w-6' />}
              className='h-[44px] rounded-l-none bg-background-secondary'
            />
          </Tooltip>
        </div>
        <Tooltip label='Reset Zoom' placement='top'>
          <Button
            className='h-[44px] bg-background-secondary'
            onClick={resetZoom}
            icon={<ClipZoomInIcon className='h-6 w-6' />}
          />
        </Tooltip>

        <PopupFader
          className='z-10'
          visible={showVolume}
          onClose={() => setShowVolume(false)}
          value={masterVolume}
          onChange={(volume) => {
            setLocalVolume(volume);
            if (firstTrackId)
              playbackController.setTrackGain(firstTrackId, volume);
          }}
          onCommit={(volume) => {
            setLocalVolume(volume);
            setMasterVolume(volume);
          }}
        >
          <Tooltip label={showVolume ? '' : 'Volume'}>
            <Button
              className='h-[44px] bg-background-secondary'
              icon={
                localVolume > 0.66
                  ? VolumeOnIcon
                  : localVolume > 0.33
                    ? VolumeDownIcon
                    : Volume0Icon
              }
              onMouseDown={() => setShowVolume((prev) => !prev)}
            />
          </Tooltip>
        </PopupFader>
      </TransportSection>
    </Wrapper>
  );
}
