// frontend/src/components/ui/LiveVideo.tsx

'use client'

import { useEffect, useRef, useState } from 'react'
import { applyInlineVideoPolicy, DEFAULT_INLINE_MUTED } from './videoPolicy'

export default function LiveVideo({
  src,
  muted = DEFAULT_INLINE_MUTED,
  volume = 1,
  className,
  roomStatus,
  onVolumeChange,
  onLoadingStart,
  onReady,
}: {
  src: string
  muted?: boolean
  volume?: number
  className?: string
  roomStatus?: string
  onVolumeChange?: (volume: number, muted: boolean) => void
  onLoadingStart?: () => void
  onReady?: () => void
}) {
  const ref = useRef<HTMLVideoElement>(null)
  const [broken, setBroken] = useState(false)
  const [brokenReason, setBrokenReason] = useState<'private' | 'hidden' | 'away' | 'offline' | 'unknown' | null>(null)

  const onLoadingStartRef = useRef(onLoadingStart)
  const onReadyRef = useRef(onReady)

  useEffect(() => {
    onLoadingStartRef.current = onLoadingStart
  }, [onLoadingStart])

  useEffect(() => {
    onReadyRef.current = onReady
  }, [onReady])

  const normalizeBrokenReason = (
    status?: string
  ): 'private' | 'hidden' | 'away' | 'offline' | 'unknown' => {
    const s = String(status ?? '').trim().toLowerCase()

    if (s === 'private') return 'private'
    if (s === 'hidden') return 'hidden'
    if (s === 'away') return 'away'
    if (s === 'offline') return 'offline'
    return 'unknown'
  }

  const brokenMessage = (
    reason: 'private' | 'hidden' | 'away' | 'offline' | 'unknown' | null
  ): string => {
    switch (reason) {
      case 'hidden':
        return 'Cam is hidden'
      case 'away':
        return 'Model is away'
      case 'private':
        return 'Private show in progress.'
      case 'offline':
        return 'Model is offline'
      case 'unknown':
        return 'Live video unavailable'
      default:
        return 'Live video unavailable'
    }
  }

  useEffect(() => {
    let watchdogTimer: number | null = null
    let readySent = false
    let stalledRetries = 0
    let attemptStartedAt = Date.now()
    let lastProgressAt = Date.now()

    const video = ref.current
    if (!video) return

    setBroken(false)
    setBrokenReason(null)

    applyInlineVideoPolicy(video, { muted })
    video.volume = Math.max(0, Math.min(1, volume))
    video.muted = muted || volume <= 0

    const hardReset = () => {
      try {
        video.pause()
        video.removeAttribute('src')
        video.load()
      } catch {}
    }

    const markBroken = () => {
      const reason = normalizeBrokenReason(roomStatus)
      setBroken(true)
      setBrokenReason(reason)
    }

    const beginLoad = () => {
      readySent = false
      attemptStartedAt = Date.now()
      lastProgressAt = Date.now()

      onLoadingStartRef.current?.()

      hardReset()
      video.src = src
      video.load()

      const playPromise = video.play()
      if (playPromise && typeof playPromise.catch === 'function') {
        playPromise.catch(() => {
          // Nicht sofort abbrechen – Watchdog entscheidet nach Timeout.
        })
      }
    }

    hardReset()

    if (!src) {
      setBroken(false)
      setBrokenReason(null)
      return
    }

    const markReady = () => {
      lastProgressAt = Date.now()

      if (readySent) return
      readySent = true
      onReadyRef.current?.()
    }

    const onTime = () => {
      lastProgressAt = Date.now()
      markReady()
    }

    const onLoadedData = () => {
      lastProgressAt = Date.now()
      markReady()
    }

    const onCanPlay = () => {
      lastProgressAt = Date.now()
      markReady()
    }

    const onPlaying = () => {
      lastProgressAt = Date.now()
      markReady()
    }

    const onError = () => {
      markBroken()
    }

    video.addEventListener('timeupdate', onTime)
    video.addEventListener('loadeddata', onLoadedData)
    video.addEventListener('canplay', onCanPlay)
    video.addEventListener('playing', onPlaying)
    video.addEventListener('error', onError)

    beginLoad()

    watchdogTimer = window.setInterval(() => {
      const now = Date.now()

      // Stream wurde nie ready -> nicht ewig Spinner zeigen
      if (!readySent && now - attemptStartedAt > 12_000) {
        if (stalledRetries < 1) {
          stalledRetries += 1
          beginLoad()
          return
        }

        markBroken()
        return
      }

      // Stream war ready, hängt aber später
      if (readySent && !video.paused && now - lastProgressAt > 12_000) {
        if (stalledRetries < 1) {
          stalledRetries += 1
          beginLoad()
          return
        }

        markBroken()
      }
    }, 1_000)

    return () => {
      if (watchdogTimer) window.clearInterval(watchdogTimer)
      watchdogTimer = null

      video.removeEventListener('timeupdate', onTime)
      video.removeEventListener('loadeddata', onLoadedData)
      video.removeEventListener('canplay', onCanPlay)
      video.removeEventListener('playing', onPlaying)
      video.removeEventListener('error', onError)

      hardReset()
    }
  }, [src, roomStatus])

  useEffect(() => {
    const video = ref.current
    if (!video) return

    const safeVolume = Math.max(0, Math.min(1, volume))
    video.volume = safeVolume
    video.muted = muted || safeVolume <= 0
  }, [volume, muted])

  useEffect(() => {
    const video = ref.current
    if (!video || !onVolumeChange) return

    const emit = () => {
      onVolumeChange(video.volume, video.muted)
    }

    video.addEventListener('volumechange', emit)
    return () => video.removeEventListener('volumechange', emit)
  }, [onVolumeChange])

  if (broken) {
    return (
      <div className="grid h-full w-full place-items-center bg-black/80 px-4 text-center">
        <div className="text-sm font-medium text-white">
          {brokenMessage(brokenReason)}
        </div>
      </div>
    )
  }

  return (
    <video
      ref={ref}
      className={className}
      playsInline
      autoPlay
      muted={muted}
      preload="auto"
      crossOrigin="anonymous"
      onClick={() => {
        const v = ref.current
        if (v) {
          v.play().catch(() => {})
        }
      }}
    />
  )
}