import React, { ReactEventHandler, useRef, useState } from 'react';
import { CgSpinner } from 'react-icons/cg';
import { MdPause, MdPlayArrow, MdVolumeOff, MdVolumeUp } from 'react-icons/md';

import AudioProgressBar from './components/audio-progress-bar';
import VolumeInput from './components/audio-volume';
import IconButton from './components/icon-button';

import './index.css';

function formatDurationDisplay(duration: number) {
  const min = Math.floor(duration / 60);
  const sec = Math.floor(duration - min * 60);

  const formatted = [min, sec].map((n) => (n < 10 ? '0' + n : n)).join(':');

  return formatted;
}

interface AudioPlayerProps {
  url: string;
  name: string;
}

export function AudioPlayer({ url, name }: AudioPlayerProps) {
  const audioRef = useRef<HTMLAudioElement | null>(null);
  const volumeRef = useRef<any>();
  const [isReady, setIsReady] = useState(false);
  const [duration, setDuration] = useState(0);
  const [currrentProgress, setCurrrentProgress] = useState(0);
  const [buffered, setBuffered] = useState(0);
  const [volume, setVolume] = useState(0.2);
  const [isPlaying, setIsPlaying] = useState(false);

  const durationDisplay = formatDurationDisplay(duration);
  const elapsedDisplay = formatDurationDisplay(currrentProgress);

  const [showVolumeProgress, setShowVolumeProgress] = useState(false);

  const togglePlayPause = () => {
    if (isPlaying) {
      audioRef.current?.pause();
      setIsPlaying(false);
    } else {
      audioRef.current?.play();
      setIsPlaying(true);
    }
  };

  const handleBufferProgress: ReactEventHandler<HTMLAudioElement> = (e) => {
    const audio = e.currentTarget;
    const dur = audio.duration;
    if (dur > 0) {
      for (let i = 0; i < audio.buffered.length; i++) {
        if (
          audio.buffered.start(audio.buffered.length - 1 - i) <
          audio.currentTime
        ) {
          const bufferedLength = audio.buffered.end(
            audio.buffered.length - 1 - i
          );
          setBuffered(bufferedLength);
          break;
        }
      }
    }
  };

  const handleMuteUnmute = () => {
    if (!audioRef.current) return;

    audioRef.current.volume = audioRef.current.volume === 0 ? 1 : 0;
  };

  const handleVolumeChange = (volumeValue: number) => {
    if (!audioRef.current) return;
    audioRef.current.volume = volumeValue;
    setVolume(volumeValue);
  };

  const onMouseEnter = () => {
    setShowVolumeProgress(true);
    if (volumeRef.current) {
      clearTimeout(volumeRef.current);
    }
  };

  const onMouseLeave = () => {
    volumeRef.current = setTimeout(() => {
      setShowVolumeProgress(false);
    }, 200);
  };

  return (
    <div className="relative flex gap-2 bg-[#F6F6FE] p-3 text-slate-400">
      {url && (
        <audio
          ref={audioRef}
          preload="metadata"
          onDurationChange={(e) => setDuration(e.currentTarget.duration)}
          onPlaying={() => setIsPlaying(true)}
          onPause={() => setIsPlaying(false)}
          onCanPlay={(e) => {
            e.currentTarget.volume = volume;
            setIsReady(true);
          }}
          onTimeUpdate={(e) => {
            setCurrrentProgress(e.currentTarget.currentTime);
            handleBufferProgress(e);
          }}
          onProgress={handleBufferProgress}
          onVolumeChange={(e) => setVolume(e.currentTarget.volume)}
        >
          <source type="audio/mpeg" src={url} />
        </audio>
      )}
      <div className="flex items-center justify-self-center">
        <IconButton
          className="border border-solid border-[#E2E4E9] bg-[#fff]"
          disabled={!isReady}
          onClick={togglePlayPause}
          aria-label={isPlaying ? 'Pause' : 'Play'}
          size="lg"
        >
          {!isReady && url ? (
            <CgSpinner size={24} className="animate-spin" />
          ) : isPlaying ? (
            <MdPause size={30} color="#A9ADBC" />
          ) : (
            <MdPlayArrow size={30} color="#A9ADBC" />
          )}
        </IconButton>
      </div>
      <div className="relative flex flex-auto justify-between">
        <div className="flex flex-1 justify-between leading-[22px]">
          <span className="text-[14px] font-medium text-[#272B35]">{name}</span>
          <span className="text-[12px]">
            {elapsedDisplay} / {durationDisplay}
          </span>
        </div>
        <AudioProgressBar
          duration={duration}
          currentProgress={currrentProgress}
          buffered={buffered}
          onChange={(e) => {
            if (!audioRef.current) return;

            audioRef.current.currentTime = e.currentTarget.valueAsNumber;

            setCurrrentProgress(e.currentTarget.valueAsNumber);
          }}
        />
      </div>
      <div className="grid items-center">
        <div className="relative flex items-center gap-3 justify-self-end">
          <IconButton
            className="bg-[#F6F6FE]"
            intent="secondary"
            size="sm"
            onClick={handleMuteUnmute}
            onMouseEnter={onMouseEnter}
            onMouseLeave={onMouseLeave}
            aria-label={volume === 0 ? 'unmute' : 'mute'}
          >
            {volume === 0 ? (
              <MdVolumeOff size={20} />
            ) : (
              <MdVolumeUp size={20} />
            )}
          </IconButton>
          <VolumeInput
            show={showVolumeProgress}
            onMouseLeave={onMouseLeave}
            onMouseEnter={onMouseEnter}
            volume={volume}
            onVolumeChange={handleVolumeChange}
          />
        </div>
      </div>
    </div>
  );
}
