import { AudioPlaybackContext } from '@/lib/useAudioPlayback';
import { darkLine, gray300, gray600, moss, white, yellow } from '@/styles/colors';
import { BELOW_W_768 } from '@/styles/dimensions';
import { keyframes } from '@emotion/react';
import styled from '@emotion/styled';
import { useRouter } from 'next/router';
import { Dispatch, SetStateAction, useCallback, useContext, useEffect, useRef, useState } from 'react';
import ForwardIcon from '../icons/Forward.svg';
import PauseIcon from '../icons/Pause.svg';
import PlayIcon from '../icons/Play.svg';
import VolumeIcon from '../icons/Volume.svg';
import VolumeMutedIcon from '../icons/VolumeMuted.svg';
import { TrackInfo, showcaseTracks } from './MadeWithWavTool';

const fadeIn = keyframes`
0% { opacity: 0; transform: translateY(50%) }
100% { opacity: 1; transform: translateY(0) }
`;
const Container = styled.div<{ fadeOut: boolean }>`
  width: 450px;
  z-index: 12;
  position: fixed;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid ${darkLine};
  border-radius: 4px;
  bottom: 20px;
  right: 20px;
  padding: 1rem 1rem 1rem 1.25rem;
  animation: ${fadeIn} 0.5s;
  opacity: ${(props) => (props.fadeOut ? 0 : 1)};
  transition: all 0.3s;
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  gap: 10px;

  @media screen and (${BELOW_W_768}) {
    width: 100vw;
    right: 0;
    bottom: 0;
    padding: 0;
  }
`;

const Artwork = styled.div<{ url?: string }>`
  width: 90px;
  aspect-ratio: 1/1;
  background: ${gray600};
  background-image: url(${(props) => props.url});
  background-size: cover;

  @media screen and (${BELOW_W_768}) {
    width: 60px;
  }
`;

const ArtistDetails = styled.div`
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  justify-content: flex-start;

  h1 {
    font-family: Montreal;
    font-size: 2rem;
  }

  h2 {
    font-family: Architekt;
    font-size: 1.5rem;
    margin-left: 1rem;
    margin-bottom: 2px;
  }
`;

const Playhead = styled.div`
  position: relative;
  height: 4px;
  width: 100%;
  background: ${darkLine};

  &:before {
    position: absolute;
    top: -1.5rem;
    left: 0;
    right: 0;
    height: 3rem;
    background: none;
    z-index: 2;
    content: '';
    display: block;
    cursor: pointer;
  }
`;
const PlayheadProgress = styled.div`
  position: absolute;
  height: 4px;
  left: 0;
  background: ${moss};
`;

const PlayheadSection = styled.div`
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 4px;
  @media screen and (${BELOW_W_768}) {
    display: none;
  }
`;

const ControlsSection = styled.div`
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 4px;
`;

const VolumeSection = styled.div`
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
  img {
    cursor: pointer;
  }
  @media screen and (${BELOW_W_768}) {
    display: none;
  }
`;

const PlaybackSection = styled.div`
  width: 100px;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
  padding: 0 10px;
  img {
    cursor: pointer;
  }

  @media screen and (${BELOW_W_768}) {
    padding: 0;
    justify-content: space-between;
  }
`;

const MadeWithWavToolSection = styled.div`
  flex: 1;
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  align-items: center;
  gap: 5px;
  @media screen and (${BELOW_W_768}) {
    margin-right: 5px;
  }
`;

const VolumeDotsWrapper = styled.div`
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  margin-left: 3px;
  padding: 0 3px;
  margin-top: 1px;
  cursor: pointer;
  > * {
    width: 3px;
    height: 5px;
    margin-right: 3px;
  }
`;

const VolumeDots = () => {
  const audioPlayback = useContext(AudioPlaybackContext);
  const [localVolume, setLocalVolume] = useState(audioPlayback.volume);

  useEffect(() => {
    setLocalVolume(audioPlayback.volume);
  }, [audioPlayback.volume]);

  const handleMouseDown = useCallback(
    (e: React.MouseEvent<HTMLDivElement>) => {
      const boundingRect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();
      const progress = Math.min(1, Math.max(0, (e.clientX - boundingRect.left) / boundingRect.width));
      audioPlayback.setVolume(progress, false);
      setLocalVolume(progress);
      audioPlayback.setMuted(false);
      let lastVolume = progress;

      const handleMouseMove = (e: MouseEvent) => {
        const progress = Math.min(1, Math.max(0, (e.clientX - boundingRect.left) / boundingRect.width));
        audioPlayback.setVolume(progress, false);
        setLocalVolume(progress);
        lastVolume = progress;
      };

      const handleMouseUp = (e: MouseEvent) => {
        audioPlayback.setVolume(lastVolume, true);
        window.removeEventListener('mousemove', handleMouseMove);
        window.removeEventListener('mouseup', handleMouseUp);
      };

      window.addEventListener('mousemove', handleMouseMove);
      window.addEventListener('mouseup', handleMouseUp);
    },
    [audioPlayback]
  );

  return (
    <VolumeDotsWrapper onClick={handleMouseDown}>
      {Array.from({ length: 10 }).map((_, i) => (
        <div
          key={i}
          style={{ backgroundColor: !audioPlayback.muted && i < localVolume * 10 ? '#717171' : '#d6d6d6' }}
        />
      ))}
    </VolumeDotsWrapper>
  );
};

const RemixThisButton = styled.button`
  font-family: Architekt;
  position: absolute;
  top: 0;
  right: 0;
  background: ${yellow};
  border: none;
  padding: 0.5rem 1rem;
  cursor: pointer;
  transition:
    background 0.3s,
    color 0.3s;

  &:hover {
    background: ${gray300};
    color: ${white};
  }

  @media screen and (${BELOW_W_768}) {
    display: none;
  }
`;

const PlaybackModal = ({
  selectedTrack,
  setSelectedTrack,
}: {
  selectedTrack?: TrackInfo;
  setSelectedTrack: Dispatch<SetStateAction<TrackInfo | undefined>>;
}) => {
  const router = useRouter();
  const audioPlayback = useContext(AudioPlaybackContext);
  const [transitioningOut, setTransitioningOut] = useState(false);
  const currentTimeRef = useRef<HTMLParagraphElement>(null);
  const fullTimeRef = useRef<HTMLParagraphElement>(null);
  const playheadRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!selectedTrack) return;
    audioPlayback.load(selectedTrack?.audioUrl);
    audioPlayback.play(0);
  }, [selectedTrack]);

  const updateTimeVisuals = useCallback(() => {
    if (currentTimeRef.current) {
      const currentTime = audioPlayback.getCurrentTime();
      const minutes = Math.floor(currentTime / 60);
      const seconds = Math.floor(currentTime % 60);
      currentTimeRef.current.innerText = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
    }
    if (fullTimeRef.current) {
      const fullTime = audioPlayback.duration;
      const minutes = Math.floor(fullTime / 60);
      const seconds = Math.floor(fullTime % 60);
      fullTimeRef.current.innerText = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
    }
    if (playheadRef.current) {
      playheadRef.current.style.width = `${(audioPlayback.getCurrentTime() / audioPlayback.duration) * 100}%`;
    }
  }, [audioPlayback]);

  useEffect(() => {
    const updateInterval = setInterval(() => {
      updateTimeVisuals();
    }, 20);

    return () => {
      clearInterval(updateInterval);
    };
  }, [audioPlayback, updateTimeVisuals]);

  const handleBack = useCallback(() => {
    if (audioPlayback.getCurrentTime() < 5) {
      const currTrackIndex = showcaseTracks.findIndex((track) => track.name === selectedTrack?.name);
      setSelectedTrack(showcaseTracks[(currTrackIndex - 1 + showcaseTracks.length) % showcaseTracks.length]);
    } else {
      audioPlayback.seek(0);
      audioPlayback.stop();
    }
  }, [selectedTrack]);

  const handleForward = useCallback(() => {
    const currTrackIndex = showcaseTracks.findIndex((track) => track.name === selectedTrack?.name);
    setSelectedTrack(showcaseTracks[(currTrackIndex + 1) % showcaseTracks.length]);
  }, [selectedTrack]);

  const handlePlayheadClick = useCallback(
    (e: React.MouseEvent<HTMLDivElement>) => {
      const { x: playheadXPos, width: playheadWidth } = (e.currentTarget as HTMLDivElement).getBoundingClientRect();
      const clickXPos = e.clientX;
      const progress = Math.min(1, Math.max(0, (clickXPos - playheadXPos) / playheadWidth));
      audioPlayback.seek(progress * audioPlayback.duration);
    },
    [audioPlayback]
  );

  if (!selectedTrack) return null;

  return (
    <Container fadeOut={transitioningOut}>
      {selectedTrack.imgUrl && <Artwork url={selectedTrack?.imgUrl} />}
      <div
        style={{
          flex: 1,
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'space-around',
          padding: '4px 0',
        }}
      >
        <ArtistDetails>
          <h1>{selectedTrack?.name}</h1>
          <h2>{selectedTrack?.artist}</h2>
        </ArtistDetails>
        <PlayheadSection>
          <p style={{ minWidth: 28 }} ref={currentTimeRef}>
            0:00
          </p>
          <Playhead onClick={handlePlayheadClick}>
            <PlayheadProgress ref={playheadRef} />
          </Playhead>
          <p style={{ minWidth: 28 }} ref={fullTimeRef}>
            0:00
          </p>
        </PlayheadSection>
        <ControlsSection>
          <VolumeSection>
            <img
              {...(audioPlayback.muted ? VolumeMutedIcon : VolumeIcon)}
              onClick={() => audioPlayback.setMuted(!audioPlayback.muted)}
            />
            <VolumeDots />
          </VolumeSection>
          <PlaybackSection>
            <img {...ForwardIcon} style={{ transform: 'rotate(180deg)' }} onClick={handleBack} />
            {audioPlayback.playing ? (
              <img {...PauseIcon} onClick={() => audioPlayback.stop()} />
            ) : (
              <img {...PlayIcon} onClick={() => audioPlayback.play()} />
            )}
            <img {...ForwardIcon} onClick={handleForward} />
          </PlaybackSection>
          <MadeWithWavToolSection>
            made with <img src="/images/wordmark-black.svg" width={48} alt="WavTool Logo" />
          </MadeWithWavToolSection>
        </ControlsSection>
      </div>
      {!!selectedTrack.remixUrl && (
        <RemixThisButton onClick={() => router.push(selectedTrack.remixUrl || '')}>remix this</RemixThisButton>
      )}
    </Container>
  );
};

export default PlaybackModal;
