import { selectSystemProps } from '@telus-uds/components-base'
import PropTypes from 'prop-types'
import React from 'react'
import YouTube from 'react-youtube'
import styled from 'styled-components'
import VideoSplash from '../shared/VideoSplash/VideoSplash'
import { htmlAttrs } from '../utils'
import { triggerInProgressVideoIntervals, YoutubePlayerState } from './utils'

const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])

const StyledPlayerContainer = styled.div({
  width: '100%',
  minWidth: 288,
  outline: 'none'
})

const StyledYoutubePlayer = styled(YouTube)({
  position: 'absolute',
  top: 0,
  left: 0,
  bottom: 0,
  right: 0
})

const aspectRatios = {
  '16:9': { paddingTop: '56.25%' },
  '4:3': { paddingTop: '75%' },
  '1:1': { paddingTop: '100%' }
}

const AspectLimiter = styled.div((props) => ({
  ...aspectRatios[props.aspectRatio],
  position: 'relative'
}))

const WebVideo = React.forwardRef(
  (
    {
      videoId,
      aspectRatio = '16:9',
      posterSrc,
      defaultVolume = 1,
      beginMuted = false,
      videoLength,
      copy,
      onPlay = () => {},
      onPause = () => {},
      onEnd = () => {},
      onProgress = () => {},
      onStart = () => {},
      ...rest
    },
    ref
  ) => {
    const [started, setStarted] = React.useState(false)
    const videoStateData = React.useRef({
      requestAnimationIds: [],
      state: YoutubePlayerState.UNSTARTED
    })
    const playerRef = React.useRef(null)

    const onPlayCallback = (event) => {
      onPlay(event, videoStateData.current.state === YoutubePlayerState.PAUSED)
      videoStateData.current.state = YoutubePlayerState.PLAYING
      if (onProgress) {
        videoStateData.current.requestAnimationIds = triggerInProgressVideoIntervals(
          onProgress,
          playerRef,
          event
        )
      }
    }

    const initializeYoutubePlayer = (event) => {
      onStart()
      playerRef.current = event.target

      if (beginMuted) {
        event.target.mute()
      }

      event.target.setVolume(defaultVolume)
      event.target.playVideo() // This plays the video after passing the splash screen on mobile.
    }

    const onEndVideoCallback = (event) => {
      onEnd(event)
      videoStateData.current.requestAnimationIds.forEach((id) => cancelAnimationFrame(id))
      videoStateData.current.requestAnimationIds = []
      videoStateData.current.state = YoutubePlayerState.ENDED
      if (onProgress) {
        onProgress(event, 100)
      }
    }

    const onPauseVideoCallback = (event) => {
      videoStateData.current.requestAnimationIds.forEach((id) => cancelAnimationFrame(id))
      onPause(event)
      videoStateData.current.state = YoutubePlayerState.PAUSED
      videoStateData.current.requestAnimationIds = []
    }

    return (
      <StyledPlayerContainer ref={ref} data-testid="web-video-container" {...selectProps(rest)}>
        <AspectLimiter aspectRatio={aspectRatio}>
          {started ? (
            <StyledYoutubePlayer
              videoId={videoId}
              opts={{
                width: '100%',
                height: '100%',
                playerVars: {
                  autoplay: 1,
                  modestbranding: 1,
                  playsinline: 1,
                  rel: 0
                }
              }}
              onReady={initializeYoutubePlayer}
              onPlay={onPlayCallback}
              onPause={onPauseVideoCallback}
              onEnd={onEndVideoCallback}
            />
          ) : (
            <VideoSplash
              poster={posterSrc || `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`}
              videoLength={videoLength}
              copy={copy}
              onClick={() => {
                setStarted(true)
              }}
            />
          )}
        </AspectLimiter>
      </StyledPlayerContainer>
    )
  }
)

WebVideo.displayName = 'WebVideo'

export const VideoProps = {
  ...selectedSystemPropTypes,
  /**
   * The video's ID, typically available via the video's URL.
   */
  videoId: PropTypes.string.isRequired,
  /**
   * The aspect ratio of the player.
   */
  aspectRatio: PropTypes.oneOf(['16:9', '4:3', '1:1']),
  /**
   * A path of the image that will be displayed on the video's splash screen. If this is undefined, it will pull an image from the defined web video if available.
   */
  posterSrc: PropTypes.string,
  /**
   * The video's default volume, defined from 1 to 100. Please use the `beginMuted` prop to have the video start silenced.
   */
  defaultVolume: PropTypes.number,
  /**
   * Defines if the video should start muted.
   */
  beginMuted: PropTypes.bool,
  /**
   * The video's length, which will be displayed on the splash screen. This is defined in seconds.
   */
  videoLength: PropTypes.number.isRequired,
  /**
   * The splash screen UI's language as an ISO language code. It currently supports English and French.
   */
  copy: PropTypes.oneOf(['en', 'fr']),
  /**
   * A function to be run when the play button is pressed on the video splash screen and the video is ready to play.
   */
  onStart: PropTypes.func,

  /**
   * A function to be run when the video is played.
   */
  onPlay: PropTypes.func,

  /**
   * A function to be run when the video is paused.
   */
  onPause: PropTypes.func,

  /**
   * A function to be run when the video ends.
   */
  onEnd: PropTypes.func,

  /**
   * A function to be run when the video resumes.
   */
  onResume: PropTypes.func,

  /**
   * A function to be run when the video progresses. This function will be run at 10%, 25%, 50%, 75% and 100%.
   */
  onProgress: PropTypes.func
}

WebVideo.propTypes = VideoProps

export default WebVideo
