import type { MouseEvent } from 'react'
import {
  useCallback,
  useState,
  useRef,
} from 'react'
import ReactPlayer from 'react-player'

import once from 'lodash/once'
import throttle from 'lodash/throttle'

import { useFullscreen } from './useFullscreen'
import { useVolume } from './useVolume'

type ProgressState = {
  loaded: number,
  loadedSeconds: number,
  played: number,
  playedSeconds: number,
}

export type Props = {
  onPlayingChange: (playing: boolean) => void,
  onProgressChange: (seconds: number) => void,
  url: string,
}

export const useVideoPlayer = ({
  onPlayingChange,
  onProgressChange: progressChangeCallback,
}: Props) => {
  const [ready, setReady] = useState(false)
  const [playing, setPlaying] = useState(false)
  const [duration, setDuration] = useState(0)
  const [loadedProgress, setLoadedProgress] = useState(0)
  const [playedProgress, setPlayedProgress] = useState(0)
  const [playedSeconds, setPlayedSeconds] = useState(0)
  const wrapperRef = useRef<HTMLDivElement>(null)
  const playerRef = useRef<ReactPlayer>(null)

  const startPlaying = useCallback(once(() => {
    setReady(true)
    setPlaying(true)
    onPlayingChange(true)
  }), [])

  const togglePlaying = () => {
    if (ready) {
      setPlaying(!playing)
      onPlayingChange(!playing)
    }
  }

  const onPlayerClick = (e: MouseEvent<HTMLDivElement>) => {
    if (e.target === playerRef.current?.getInternalPlayer()) {
      togglePlaying()
    }
  }

  const setPlayerProgress = useCallback(
    throttle((value: number) => {
      playerRef.current?.seekTo(value, 'fraction')
    }, 100),
    [],
  )

  const onProgressChange = useCallback((progress: number) => {
    setPlayedProgress(progress * 100)
    setPlayerProgress(progress)
  }, [
    setPlayedProgress,
    setPlayerProgress,
  ])

  const setProgress = ({
    loaded,
    played,
    playedSeconds: seconds,
  }: ProgressState) => {
    setLoadedProgress(loaded * 100)
    setPlayedProgress(played * 100)
    setPlayedSeconds(seconds)

    progressChangeCallback(seconds)
  }

  return {
    duration,
    loadedProgress,
    onPlayerClick,
    onProgressChange,
    playedProgress,
    playedSeconds,
    playerRef,
    playing,
    setDuration,
    setProgress,
    setReady,
    startPlaying,
    togglePlaying,
    wrapperRef,
    ...useFullscreen(wrapperRef),
    ...useVolume(),
  }
}
