import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'clsx';
import {
  Fullscreen,
  FullscreenExit,
  PauseRounded,
  PlayArrowRounded,
  VolumeDown,
  VolumeMute,
  VolumeOff,
  VolumeUp,
} from '@mui/icons-material';

import { getNumberInRange } from '@/modules/@common/helpers/number';

import { IconButton, Slider, Stack, Typography } from '@/mui/components';

import noImage from '@/assets/img/no-image-portrait.svg';

import styles from './VideoPlayer.module.scss';

function VideoPlayer({ poster = noImage, shouldPause = false, ...props }) {
  const videoRef = useRef(null);
  const [playing, setPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [volume, setVolume] = useState(100);
  const [muted, setMuted] = useState(false);
  const [fullScreen, setFullScreen] = useState(false);
  const [showPanelControl, setShowPanelControl] = useState(false);

  let VolumeIcon = volume <= 50 ? VolumeDown : VolumeUp;

  if (muted) {
    VolumeIcon = VolumeOff;
  } else if (volume <= 0) {
    VolumeIcon = VolumeMute;
  }

  const togglePlayPause = () => {
    setShowPanelControl(true);
    const video = videoRef.current;
    if (video.paused) {
      video.play();
      setPlaying(true);
    } else {
      video.pause();
      setPlaying(false);
    }
  };

  const handleSeek = (value) => {
    const resTime = getNumberInRange(value, 0, duration);

    videoRef.current.currentTime = resTime;
    setCurrentTime(resTime);
  };

  const formatTime = (time) => {
    const hours = Math.floor(time / 3600);
    const minutes = Math.floor((time % 3600) / 60);
    const seconds = Math.floor(time % 60);

    if (hours > 0) {
      return `${hours}:${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
    }
    return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
  };

  const handleKeyDown = (event) => {
    if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
      event.preventDefault();

      setCurrentTime((t) => {
        const nextTime = getNumberInRange(t + (event.key === 'ArrowRight' ? 5 : -5), 0, duration);
        videoRef.current.currentTime = nextTime;
        return nextTime;
      });
      setShowPanelControl(true);
    } else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
      event.preventDefault();

      setVolume((t) => {
        const nextTime = getNumberInRange(t + (event.key === 'ArrowUp' ? 10 : -10), 0, 100);
        videoRef.current.volume = nextTime / 100;
        return nextTime;
      });
      setShowPanelControl(true);
    } else if (event.key === 'Escape') {
      event.preventDefault();
      setFullScreen(false);
      setShowPanelControl(true);
    } else if (event.key === 'Enter' || event.key === 'Backspace' || event.key === ' ') {
      event.preventDefault();
      togglePlayPause();
      setShowPanelControl(true);
    }
  };

  useEffect(() => {
    if (fullScreen) {
      document.addEventListener('keydown', handleKeyDown);
    }

    return () => {
      document.removeEventListener('keydown', handleKeyDown);
    };
  }, [fullScreen, duration, setShowPanelControl]);

  useEffect(() => {
    let timer = null;

    if (showPanelControl) {
      timer = setTimeout(() => setShowPanelControl(false), 1000);
    }

    return () => {
      clearTimeout(timer);
    };
  }, [showPanelControl]);

  useEffect(() => {
    if (shouldPause) {
      setTimeout(() => {
        videoRef.current.pause();
        setPlaying(false);
      }, 0);
    }
  }, [shouldPause, videoRef]);

  return (
    <div className={styles.Wrapper}>
      <div
        className={classNames(styles.Content, {
          [styles.Content___fullScreen]: fullScreen,
        })}
      >
        <video
          ref={videoRef}
          onTimeUpdate={() => {
            setCurrentTime(videoRef.current.currentTime);
            props.onTimeUpdate(videoRef.current.currentTime);
          }}
          onLoadedMetadata={() => {
            const video = videoRef.current;
            if (video.duration === Infinity) {
              video.currentTime = 1e101;
              video.ontimeupdate = () => {
                video.ontimeupdate = null;
                setDuration(video.duration);
                video.currentTime = 0;
              };
            } else {
              setDuration(video.duration);
            }
          }}
          controls={false}
          className={styles.Video}
          poster={poster}
          muted={muted}
          onClick={togglePlayPause}
          onEnded={() => {
            setPlaying(false);
          }}
        >
          {props.videoUrl && <source src={props.videoUrl} type="video/mp4" />}
        </video>
        <Stack
          spacing={0}
          fullWidth
          className={classNames(styles.Controls, {
            [styles.Controls___visible]: showPanelControl || !fullScreen,
          })}
        >
          <Stack direction="row" alignItems="center" fullWidth>
            <Stack direction="row" alignItems="center" justifyContent="flex-start" fullWidth>
              <IconButton color="inherit" size="small" onClick={togglePlayPause}>
                {playing ? <PauseRounded /> : <PlayArrowRounded />}
              </IconButton>

              <Typography variant="caption">{`${formatTime(currentTime)} / ${formatTime(duration)}`}</Typography>
            </Stack>

            <Stack spacing={0} direction="row" alignItems="center" justifyContent="flex-end" fullWidth>
              <Slider
                size="small"
                color="inherit"
                orientation="horizontal"
                min={0}
                max={100}
                step={1}
                value={volume}
                className={styles.VolumeRange}
                onChange={(event) => {
                  const volume$ = event.target.value;

                  videoRef.current.volume = volume$ / 100;
                  setVolume(volume$);
                }}
              />
              <IconButton color="inherit" size="small" onClick={() => setMuted(!muted)}>
                <VolumeIcon />
              </IconButton>
              <IconButton color="inherit" size="small" onClick={() => setFullScreen((p) => !p)}>
                {fullScreen ? <FullscreenExit /> : <Fullscreen />}
              </IconButton>
            </Stack>
          </Stack>
          <div className={styles.TimeLine}>
            <Slider
              color="inherit"
              size="small"
              value={currentTime}
              min={0}
              max={duration}
              step={0.1}
              onChange={(event) => handleSeek(event.target.value)}
            />
          </div>
        </Stack>
        {!playing && (
          <PlayArrowRounded
            className={styles.Overlay}
            fontSize="x9Large"
            htmlColor="common.black"
            onClick={togglePlayPause}
          />
        )}
      </div>
    </div>
  );
}

VideoPlayer.propTypes = {
  poster: PropTypes.string,
  shouldPause: PropTypes.bool,
  videoUrl: PropTypes.string.isRequired,
  onTimeUpdate: PropTypes.func.isRequired,
};

export default VideoPlayer;
