import Feather from '@expo/vector-icons/Feather'
import { BlurView } from 'expo-blur'
import { Image as ExpoImage, type ImageLoadEventData } from 'expo-image'
import { type VideoSource, VideoView } from 'expo-video'
import { useState } from 'react'
import { StyleSheet, View } from 'react-native'
import { PressableOpacity } from 'src/components/common/PressableOpacity'
import { useVideo } from 'src/hooks/playback/PlaybackScope'
import { useScopedPlayer } from 'src/hooks/playback/useScopedPlayer'
import { ICON } from 'src/lib/icons'
import { useTheme } from 'tamagui'

type Props = {
  source: VideoSource
  width: number
  /**
   * Intrinsic aspect ratio (width / height) from the server's `meta.original`,
   * when known. Pass `undefined` when the server didn't report dimensions:
   * VideoPlayer then adopts the poster frame's natural aspect once it loads
   * (Pixelfed posters carry the video's own aspect), falling back to 4/3 until
   * then. This is the fix for portrait videos with missing server dims, which
   * used to pillarbox inside a guessed 4/3 box (`contentFit="contain"` letter-
   * boxes whenever the box aspect doesn't match the video).
   */
  aspectRatio?: number
  /** Optional height ceiling for embedded cards (quoted status / comment). */
  maxHeight?: number
  videoId: string
  previewUrl?: string | null
  blurhash?: string | null
}

const FALLBACK_ASPECT = 4 / 3

const hasRealThumbnail = (url?: string | null): url is string =>
  typeof url === 'string' && url.length > 0 && !url.includes('no-preview.png')

const VideoPlayer = ({
  source,
  width,
  aspectRatio,
  maxHeight,
  videoId,
  previewUrl,
  blurhash,
}: Props) => {
  const { currentVideoId, playVideo } = useVideo()
  const theme = useTheme()
  const isCurrent = currentVideoId === videoId
  const { player, isPlaying } = useScopedPlayer({
    source,
    videoId,
    mode: 'feed',
    audible: true,
  })

  // Aspect resolution: server meta wins (no layout jump); otherwise adopt the
  // poster's measured aspect; otherwise 4/3 until the poster loads. The box
  // MUST match the video's aspect or `contentFit="contain"` bars it.
  const [measuredAspect, setMeasuredAspect] = useState<number | null>(null)
  const aspect = aspectRatio ?? measuredAspect ?? FALLBACK_ASPECT
  const rawHeight = width / aspect
  const height =
    typeof maxHeight === 'number' && rawHeight > maxHeight ? maxHeight : rawHeight

  const onPosterLoad = (e: ImageLoadEventData) => {
    if (aspectRatio) return // server gave us real dims; don't second-guess them
    const { width: w, height: h } = e.source
    if (w > 0 && h > 0) setMeasuredAspect(w / h)
  }

  const onTogglePress = () => {
    if (isCurrent) playVideo(null)
    else playVideo(videoId)
  }

  // Show the poster whenever the video isn't actively rendering frames:
  // outside the preload window, paused, or not yet tapped. Unmount once
  // playback begins so the Image is not kept in memory over the VideoView.
  const showPoster = !isPlaying
  const posterUri = hasRealThumbnail(previewUrl) ? previewUrl : null
  const posterPlaceholder = blurhash ? { blurhash } : undefined

  return (
    // Self-sized box ({ width, height }) like every image leaf, so the
    // SaveableMedia wrapper never has to stretch it to fill its slot. (The
    // old `flex: 1` + no-width contract was the structural cause of the feed
    // video side-bar regression — the wrapper had to compensate.)
    <View
      style={{
        width,
        height,
        justifyContent: 'center',
        alignItems: 'center',
      }}
    >
      <PressableOpacity
        style={{
          width: '100%',
          height: '100%',
          justifyContent: 'center',
          alignItems: 'center',
        }}
        onPress={onTogglePress}
        activeOpacity={0.98}
      >
        <VideoView
          player={player}
          style={{ width: '100%', height: '100%' }}
          contentFit="contain"
          nativeControls={false}
          allowsPictureInPicture
        />

        {showPoster && (posterUri || posterPlaceholder) && (
          <ExpoImage
            source={posterUri ? { uri: posterUri } : null}
            placeholder={posterPlaceholder}
            placeholderContentFit="contain"
            contentFit="contain"
            transition={150}
            onLoad={onPosterLoad}
            style={StyleSheet.absoluteFillObject}
            pointerEvents="none"
          />
        )}

        {!isPlaying && (
          <View
            style={{
              position: 'absolute',
              justifyContent: 'center',
              alignItems: 'center',
              borderRadius: 50,
              overflow: 'hidden',
              width: 60,
              height: 60,
            }}
          >
            <BlurView
              style={{
                position: 'absolute',
                top: 0,
                left: 0,
                right: 0,
                bottom: 0,
              }}
              tint="dark"
              intensity={40}
            />
            <Feather
              name="play"
              size={ICON.xl}
              color={theme.colorInverse.val}
              style={{ marginLeft: 4 }}
            />
          </View>
        )}
      </PressableOpacity>
    </View>
  )
}

export default VideoPlayer
