import type { ForwardRefRenderFunction, SyntheticEvent } from 'react'
import {
  useEffect,
  useState,
  useRef,
} from 'react'

import isUndefined from 'lodash/isUndefined'
import isNumber from 'lodash/isNumber'

import { useProgressChange } from './useProgressChange'

type Ref = Parameters<ForwardRefRenderFunction<HTMLVideoElement>>[1]

export type Props = {
  className?: string,
  crossOrigin?: string,
  height?: string,
  hidden?: boolean,
  isFullscreen?: boolean,
  muted?: boolean,
  onDurationChange?: (durationMs: number) => void,
  onEnded?: (e: SyntheticEvent<HTMLVideoElement>) => void,
  onError?: (e?: SyntheticEvent<HTMLVideoElement>) => void,
  onLoadedProgress?: (loadedMs: number) => void,
  onPause?: (e: SyntheticEvent<HTMLVideoElement>) => void,
  onPlayedProgress?: (playedMs: number) => void,
  onReady?: () => void,
  playing?: boolean,
  ref?: Ref,
  seek?: number | null,
  src: string,
  volume?: number,
  width?: string,
}

const useVideoRef = (ref?: Ref) => {
  const videoRef = useRef<HTMLVideoElement>(null)
  if (ref && typeof ref === 'object') return ref
  return videoRef
}

export const useVideoPlayer = ({
  isFullscreen,
  onDurationChange,
  onError,
  onLoadedProgress,
  onPlayedProgress,
  onReady,
  playing,
  ref,
  seek = null,
  src,
  volume,
}: Props) => {
  const [ready, setReady] = useState(false)
  const videoRef = useVideoRef(ref)

  const handleReady = () => {
    setReady(true)
    onReady?.()
  }

  const handleDurationChange = () => {
    onDurationChange?.(videoRef.current?.duration || 0)
  }

  useEffect(() => {
    const video = videoRef.current
    if (!video || !src) return

    video.src = src
    video.load()
  }, [src, videoRef])

  useEffect(() => {
    const video = videoRef.current
    if (video && isNumber(seek)) {
      video.currentTime = seek
    }
  }, [seek, videoRef])

  useEffect(() => {
    const video = videoRef.current
    if (!video?.src || !ready || isUndefined(playing)) return

    if (playing) {
      // автовоспроизведение со звуком иногда может не сработать
      // https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#new-behaviors
      video.play().catch(onError)
    } else {
      video.pause()
    }
  }, [
    ready,
    playing,
    src,
    videoRef,
    onError,
  ])

  useEffect(() => {
    const video = videoRef.current
    if (video) {
      video.volume = volume ?? 1
    }
  }, [volume, videoRef])

  useEffect(() => {
    videoRef.current?.scrollIntoView({ behavior: 'smooth' })
  }, [isFullscreen, videoRef])

  return {
    handleDurationChange,
    handleReady,
    videoRef,
    ...useProgressChange({
      onLoadedProgress,
      onPlayedProgress,
      videoRef,
    }),
  }
}
