import styled from '@emotion/styled';
import { observer } from 'mobx-react-lite';
import { RefObject, useCallback, useEffect, useRef, useState } from 'react';
// eslint-disable-next-line @suno-custom/no-react-icons -- grandfathered in, need to migrate
import { BsFullscreen } from 'react-icons/bs';
import { useInterval } from 'usehooks-ts';

import {
  MinusIcon,
  PauseIcon,
  PlayIcon,
  PlusIcon,
  UserIcon,
  Volume0Icon,
  VolumeDownIcon,
  VolumeOnIcon,
} from '@/icons';
import ctrlStr from '@/utils/ctrlStr';

import Button, { ButtonSize, ButtonVariant } from '../button/Button';
import { Tooltip } from '../tooltip/Tooltip';
import PopupFader from './PopupFader';
import TimeReadout from './TimeReadout';
import { SongImage } from './components';

const Wrapper = styled.div`
  display: grid;
  position: relative;
  z-index: 10;
  grid-template-columns: 1fr 52px 1fr;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  background-color: rgba(255, 255, 255, 0.075);
  > * {
    min-height: 0;
  }
  box-shadow: 0 0 24px rgba(0, 0, 0, 0.2);
`;

const SongMeta = styled.div`
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 5px;
  gap: 10px;
`;

const SongText = styled.div`
  display: flex;
  flex-direction: column;
  gap: 2px;
`;

const SongTitle = styled.h4`
  font-size: 14px;
  color: white;
`;

const SongDetails = styled.p`
  color: #999;
  display: flex;
  gap: 3px;
  align-items: center;
  font-size: 12px;
  svg {
    color: inherit;
  }
`;

const DetailSeparator = styled.span`
  display: inline-block;
  margin: 0 5px;
  width: 1px;
  height: 13px;
  background-color: white;
`;

const PlaybackControls = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px 0px;
`;

const WindowControls = styled.div`
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 10px;
`;

const ZOOM_PAN_INTERVAL_MS = 1000 / 120;
const ZOOM_FACTOR = 1.02;
const SCROLL_PX = 8;

export default observer(function Transport({
  imageUrl,
  clipUrl,
  title,
  artistName,
  getCurrentTime,
  songEndSeconds,
  resetZoom,
  zoomAboutSelectionOrCenter,
  scrollXRef,
  frameCountRef,
  volume,
  setVolume,
  playing,
  play,
  stop,
  rightSideControls,
}: {
  imageUrl?: string;
  clipUrl?: string;
  title?: string;
  artistName?: string;
  getCurrentTime: () => number;
  songEndSeconds: number;
  resetZoom: () => void;
  zoomAboutSelectionOrCenter: (factor: number) => void;
  scrollXRef: RefObject<number>;
  frameCountRef: RefObject<number>;
  volume: number;
  setVolume: (volume: number, commit: boolean) => void;
  playing: boolean;
  play: () => void;
  stop: () => void;
  rightSideControls?: React.ReactNode[] | React.ReactNode;
}) {
  const zoomPanInstructionsRef = useRef<{
    sprint?: boolean;
    left?: boolean;
    right?: boolean;
    in?: boolean;
    out?: boolean;
  }>({});

  const lastIntervalTimeRef = useRef(performance.now());

  useInterval(
    useCallback(() => {
      const now = performance.now();
      const delta = now - lastIntervalTimeRef.current;
      lastIntervalTimeRef.current = now;
      const instructions = zoomPanInstructionsRef.current;

      const zoomFactor = Math.pow(
        ZOOM_FACTOR * (instructions.sprint ? 1.03 : 1),
        delta / ZOOM_PAN_INTERVAL_MS
      );
      const scrollPx =
        SCROLL_PX *
        (instructions.sprint ? 2.5 : 1) *
        (delta / ZOOM_PAN_INTERVAL_MS);
      let didSomething = false;
      if (instructions.in && !instructions.out) {
        zoomAboutSelectionOrCenter(zoomFactor);
        didSomething = true;
      }
      if (instructions.out && !instructions.in) {
        zoomAboutSelectionOrCenter(1 / zoomFactor);
        didSomething = true;
      }
      if (instructions.left && !instructions.right) {
        scrollXRef.current -= scrollPx;
        didSomething = true;
      }
      if (instructions.right && !instructions.left) {
        scrollXRef.current += scrollPx;
        didSomething = true;
      }
      if (didSomething) frameCountRef.current++;
    }, [zoomAboutSelectionOrCenter]),
    ZOOM_PAN_INTERVAL_MS
  );

  const handleZoomInMouseDown = useCallback(() => {
    zoomPanInstructionsRef.current.in = true;
    const onMouseUp = () => {
      zoomPanInstructionsRef.current.in = false;
      window.removeEventListener('mouseup', onMouseUp);
    };
    window.addEventListener('mouseup', onMouseUp);
  }, []);

  const handleZoomOutMouseDown = useCallback(() => {
    zoomPanInstructionsRef.current.out = true;
    const onMouseUp = () => {
      zoomPanInstructionsRef.current.out = false;
      window.removeEventListener('mouseup', onMouseUp);
    };
    window.addEventListener('mouseup', onMouseUp);
  }, []);

  useEffect(() => {
    const handleWASDDown = (e: KeyboardEvent) => {
      if (
        e.target instanceof HTMLElement &&
        e.target.matches('input, textarea, select, [contenteditable]')
      ) {
        return;
      }
      if (e.metaKey || e.ctrlKey) return;
      if (e.key.toLowerCase() === 'shift') {
        zoomPanInstructionsRef.current.sprint = true;
      } else if (e.key.toLowerCase() === 'a') {
        zoomPanInstructionsRef.current.left = true;
      } else if (e.key.toLowerCase() === 'd') {
        zoomPanInstructionsRef.current.right = true;
      } else if (e.key.toLowerCase() === 'w') {
        zoomPanInstructionsRef.current.in = true;
      } else if (e.key.toLowerCase() === 's') {
        zoomPanInstructionsRef.current.out = true;
      }
    };
    const handleWASDUp = (e: KeyboardEvent) => {
      if (
        e.target instanceof HTMLElement &&
        e.target.matches('input, textarea, select, [contenteditable]')
      ) {
        return;
      }
      if (e.metaKey || e.ctrlKey) return;
      if (e.key.toLowerCase() === 'shift') {
        zoomPanInstructionsRef.current.sprint = false;
      } else if (e.key.toLowerCase() === 'a') {
        zoomPanInstructionsRef.current.left = false;
      } else if (e.key.toLowerCase() === 'd') {
        zoomPanInstructionsRef.current.right = false;
      } else if (e.key.toLowerCase() === 'w') {
        zoomPanInstructionsRef.current.in = false;
      } else if (e.key.toLowerCase() === 's') {
        zoomPanInstructionsRef.current.out = false;
      }
    };
    window.addEventListener('keydown', handleWASDDown);
    window.addEventListener('keyup', handleWASDUp);
    return () => {
      window.removeEventListener('keydown', handleWASDDown);
      window.removeEventListener('keyup', handleWASDUp);
    };
  }, []);

  const [showVolume, setShowVolume] = useState(false);
  const [localVolume, setLocalVolume] = useState(volume);
  useEffect(() => {
    setLocalVolume(volume);
  }, [volume]);

  return (
    <Wrapper>
      <SongMeta>
        {imageUrl ? <SongImage src={imageUrl} /> : <div />}
        <SongText>
          {title &&
            (clipUrl ? (
              <a href={clipUrl} className='hover:underline' target='_blank'>
                <SongTitle>{title}</SongTitle>
              </a>
            ) : (
              <SongTitle>{title}</SongTitle>
            ))}
          <SongDetails>
            {artistName && <UserIcon className='h-4 w-4' />}
            {artistName}
            {artistName && <DetailSeparator />}
            <TimeReadout
              getCurrentTime={getCurrentTime}
              songEndSeconds={songEndSeconds}
            />
          </SongDetails>
        </SongText>
      </SongMeta>

      <PlaybackControls>
        {playing ? (
          <Button
            size={ButtonSize.Large}
            variant={ButtonVariant.Tertiary}
            icon={<PauseIcon className='h-5 w-5' />}
            onClick={() => stop()}
          />
        ) : (
          <Button
            size={ButtonSize.Large}
            variant={ButtonVariant.Tertiary}
            icon={<PlayIcon className='h-5 w-5' />}
            onClick={() => play()}
          />
        )}
      </PlaybackControls>

      <WindowControls>
        {rightSideControls}
        <Tooltip label={`Zoom Out (${ctrlStr}+Scroll)`}>
          <Button
            onMouseDown={handleZoomOutMouseDown}
            size={ButtonSize.Large}
            variant={ButtonVariant.Tertiary}
            icon={<MinusIcon />}
          />
        </Tooltip>
        <Tooltip label={`Zoom In (${ctrlStr}+Scroll)`}>
          <Button
            onMouseDown={handleZoomInMouseDown}
            size={ButtonSize.Large}
            variant={ButtonVariant.Tertiary}
            icon={<PlusIcon />}
          />
        </Tooltip>
        <Tooltip label='Reset Zoom'>
          <Button
            onClick={resetZoom}
            size={ButtonSize.Large}
            variant={ButtonVariant.Tertiary}
            icon={<BsFullscreen />}
          />
        </Tooltip>
        <PopupFader
          visible={showVolume}
          onClose={() => setShowVolume(false)}
          value={volume}
          onChange={(volume) => {
            setVolume(volume, false);
            setLocalVolume(volume);
          }}
          onCommit={(volume) => {
            setVolume(volume, true);
            setLocalVolume(volume);
          }}
        >
          <Tooltip label={showVolume ? '' : 'Volume'}>
            <Button
              size={ButtonSize.Large}
              variant={ButtonVariant.Tertiary}
              icon={
                localVolume > 0.66
                  ? VolumeOnIcon
                  : localVolume > 0.33
                    ? VolumeDownIcon
                    : Volume0Icon
              }
              onMouseDown={() => setShowVolume((prev) => !prev)}
            />
          </Tooltip>
        </PopupFader>
      </WindowControls>
    </Wrapper>
  );
});
