'use client'

import { cx } from 'class-variance-authority'
import { useCallback, useEffect, useRef, useState } from 'react'

import { languages } from '@scandic-hotels/common/constants/language'
import { useIntl } from 'react-intl'
import Image from '../Image'
import { VideoPlayerButton } from './Button'
import { VideoPlayerProps } from './types'
import { useVideoDimensions } from './useVideoDimensions'
import { getVideoPropsByVariant } from './utils'
import { variants } from './variants'
import styles from './videoPlayer.module.css'

export function VideoPlayer({
  sources,
  captions,
  focalPoint = { x: 50, y: 50 },
  className,
  variant = 'inline',
  poster,
  autoPlay,
  hasOverlay,
}: VideoPlayerProps) {
  const intl = useIntl()
  const videoRef = useRef<HTMLVideoElement>(null)
  const shouldAutoPlay =
    (variant === 'hero' && (autoPlay ?? true)) || !!autoPlay
  const [hasManuallyPlayed, setHasManuallyPlayed] = useState(false)
  const [hasToggledMute, setHasToggledMute] = useState(false)
  const [isPlaying, setIsPlaying] = useState(shouldAutoPlay)
  const [isMuted, setIsMuted] = useState(true)
  const [userPaused, setUserPaused] = useState(false)
  const [showPoster, setShowPoster] = useState(!shouldAutoPlay)
  const {
    containerRef,
    handleMetadataLoaded,
    containerWidth,
    hasError,
    handleError,
  } = useVideoDimensions()
  const defaultProps = getVideoPropsByVariant(
    variant,
    hasManuallyPlayed,
    shouldAutoPlay
  )
  const classNames = variants({
    className,
    variant,
  })
  const showPlayButton =
    !hasError &&
    (variant === 'hero' || (variant === 'inline' && !hasManuallyPlayed))
  const showMuteButton =
    !hasError && variant === 'inline' && hasManuallyPlayed && !hasToggledMute

  const handleIntersection = useCallback(
    (entries: IntersectionObserverEntry[]) => {
      entries.forEach((entry) => {
        if (entry.intersectionRatio >= 0.1 && !userPaused) {
          videoRef.current?.play()
        } else if (entry.intersectionRatio < 0.1) {
          videoRef.current?.pause()
        }
      })
    },
    [userPaused]
  )

  function togglePlay() {
    const videoElement = videoRef.current
    if (videoElement) {
      if (variant === 'hero') {
        if (videoElement.paused) {
          setUserPaused(false)
          videoElement.play()
        } else {
          setUserPaused(true)
          videoElement.pause()
        }
      } else {
        setHasManuallyPlayed(true)
        videoElement.play()
      }
    }
  }

  function handleMuteToggle() {
    const videoElement = videoRef.current
    if (videoElement) {
      const currentlyMuted = videoElement.muted
      videoElement.muted = !currentlyMuted
      setIsMuted(!currentlyMuted)
      setHasToggledMute(true)
    }
  }

  function handleVolumeChangeEvent(event: React.UIEvent<HTMLVideoElement>) {
    if (event.currentTarget.muted && !isMuted) {
      setIsMuted(true)
    } else if (!event.currentTarget.muted && isMuted) {
      setIsMuted(false)
    }
  }

  function handlePlay() {
    setShowPoster(false)
    setIsPlaying(true)
  }

  useEffect(() => {
    const videoElement = videoRef.current

    if (!videoElement || variant !== 'hero') {
      return
    }

    const observer = new IntersectionObserver(handleIntersection, {
      // Play video when at least 10% of it is visible
      threshold: [0, 0.1, 1],
    })

    observer.observe(videoElement)
    return () => {
      observer.disconnect()
    }
  }, [variant, handleIntersection])

  if (!sources.length) {
    return null
  }

  // Sort sources to prioritize WebM format for better compression
  const sortedSources = [...sources].sort((a, b) => {
    const aIsWebM = a.type.includes('webm')
    const bIsWebM = b.type.includes('webm')

    return aIsWebM === bIsWebM ? 0 : aIsWebM ? -1 : 1
  })

  return (
    <div
      ref={containerRef}
      className={cx(classNames, {
        [styles.hasOverlay]: hasOverlay,
        [styles.hasError]: hasError,
      })}
    >
      <video
        ref={videoRef}
        className={styles.video}
        style={{
          objectPosition: focalPoint
            ? `${focalPoint.x}% ${focalPoint.y}%`
            : undefined,
        }}
        onLoadedMetadata={handleMetadataLoaded}
        onPlay={handlePlay}
        onPause={() => setIsPlaying(false)}
        onVolumeChange={handleVolumeChangeEvent}
        onError={handleError}
        crossOrigin="anonymous"
        {...defaultProps}
      >
        {sortedSources.map(({ src, type }) => (
          <source key={src} src={src} type={type} />
        ))}
        {captions?.length
          ? captions.map(({ src, srcLang, isDefault }) => (
              <track
                key={src}
                src={src}
                kind="captions"
                srcLang={srcLang}
                label={languages[srcLang] || srcLang}
                default={isDefault}
              />
            ))
          : null}
      </video>
      {(showPoster || hasError) && poster ? (
        <Image
          src={poster.src}
          alt=""
          aria-hidden="true"
          focalPoint={focalPoint}
          dimensions={poster.dimensions}
          fill
          sizes={
            containerWidth
              ? `${containerWidth}px`
              : `(min-width: 1367px) ${variant === 'inline' ? '700px' : '100vw'}, 100vw`
          }
        />
      ) : null}
      {showPlayButton ? (
        <VideoPlayerButton
          className={styles.playButton}
          onPress={togglePlay}
          iconName={isPlaying ? 'pause' : 'play_arrow'}
          size={variant === 'hero' ? 'sm' : 'lg'}
          aria-label={
            isPlaying
              ? intl.formatMessage({
                  id: 'videoPlayer.pause',
                  defaultMessage: 'Pause video',
                })
              : intl.formatMessage({
                  id: 'videoPlayer.play',
                  defaultMessage: 'Play video',
                })
          }
        />
      ) : null}
      {showMuteButton ? (
        <VideoPlayerButton
          className={styles.muteButton}
          onPress={handleMuteToggle}
          iconName={isMuted ? 'volume_off' : 'volume_up'}
          size="sm"
          aria-label={
            isMuted
              ? intl.formatMessage({
                  id: 'videoPlayer.mute',
                  defaultMessage: 'Mute video',
                })
              : intl.formatMessage({
                  id: 'videoPlayer.unmute',
                  defaultMessage: 'Unmute video',
                })
          }
        />
      ) : null}
    </div>
  )
}
