{"version":3,"sources":["../src/components/VideoPlayer/VideoPlayer.tsx"],"sourcesContent":["import {\n  useRef,\n  useState,\n  useEffect,\n  useCallback,\n  MouseEvent,\n  KeyboardEvent,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { PlayIcon } from '@phosphor-icons/react/dist/csr/Play';\nimport { PauseIcon } from '@phosphor-icons/react/dist/csr/Pause';\nimport { SpeakerHighIcon } from '@phosphor-icons/react/dist/csr/SpeakerHigh';\nimport { SpeakerSlashIcon } from '@phosphor-icons/react/dist/csr/SpeakerSlash';\nimport { ArrowsOutSimpleIcon } from '@phosphor-icons/react/dist/csr/ArrowsOutSimple';\nimport { ArrowsInSimpleIcon } from '@phosphor-icons/react/dist/csr/ArrowsInSimple';\nimport { ClosedCaptioningIcon } from '@phosphor-icons/react/dist/csr/ClosedCaptioning';\nimport { DotsThreeVerticalIcon } from '@phosphor-icons/react/dist/csr/DotsThreeVertical';\nimport { cn } from '../../utils/utils';\nimport IconButton from '../IconButton/IconButton';\nimport Text from '../Text/Text';\nimport { useMobile } from '../../hooks/useMobile';\nimport DownloadButton, {\n  DownloadContent,\n} from '../DownloadButton/DownloadButton';\n\n// Constants for timeout durations\nconst CONTROLS_HIDE_TIMEOUT = 3000; // 3 seconds for normal control hiding\nconst LEAVE_HIDE_TIMEOUT = 1000; // 1 second when mouse leaves the video area\nconst INIT_DELAY = 100; // ms delay to initialize controls on mount\n\n/**\n * VideoPlayer component props interface\n */\ninterface VideoPlayerProps {\n  /** Video source URL */\n  src: string;\n  /** Video poster/thumbnail URL */\n  poster?: string;\n  /** Subtitles URL */\n  subtitles?: string;\n  /** Video title */\n  title?: string;\n  /** Video subtitle/description */\n  subtitle?: string;\n  /** Initial playback time in seconds */\n  initialTime?: number;\n  /** Callback fired when video time updates (seconds) */\n  onTimeUpdate?: (seconds: number) => void;\n  /** Callback fired with progress percentage (0-100) */\n  onProgress?: (progress: number) => void;\n  /** Callback fired when video completes (>95% watched) */\n  onVideoComplete?: () => void;\n  /** Additional CSS classes */\n  className?: string;\n  /** Auto-save progress to localStorage */\n  autoSave?: boolean;\n  /** localStorage key for saving progress */\n  storageKey?: string;\n  /** User ID used to scope localStorage keys — prevents progress leaking between users */\n  userId?: string;\n  /** Download content URLs for lesson materials */\n  downloadContent?: DownloadContent;\n  /** Show download button in header */\n  showDownloadButton?: boolean;\n  /** Callback fired when download starts */\n  onDownloadStart?: (contentType: string) => void;\n  /** Callback fired when download completes */\n  onDownloadComplete?: (contentType: string) => void;\n  /** Callback fired when download fails */\n  onDownloadError?: (contentType: string, error: Error) => void;\n}\n\n/**\n * Format seconds to MM:SS display format\n * @param seconds - Time in seconds\n * @returns Formatted time string\n */\nconst formatTime = (seconds: number): string => {\n  if (!seconds || Number.isNaN(seconds)) return '0:00';\n  const mins = Math.floor(seconds / 60);\n  const secs = Math.floor(seconds % 60);\n  return `${mins}:${secs.toString().padStart(2, '0')}`;\n};\n\n/**\n * Progress bar component props\n */\ninterface ProgressBarProps {\n  currentTime: number;\n  duration: number;\n  progressPercentage: number;\n  onSeek: (time: number) => void;\n}\n\n/**\n * Progress bar subcomponent\n */\nconst ProgressBar = ({\n  currentTime,\n  duration,\n  progressPercentage,\n  onSeek,\n  className = 'px-4 pb-2',\n}: ProgressBarProps & { className?: string }) => (\n  <div className={className}>\n    <input\n      type=\"range\"\n      min={0}\n      max={duration || 100}\n      value={currentTime}\n      onChange={(e) => onSeek(Number.parseFloat(e.target.value))}\n      className=\"w-full h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer slider:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500\"\n      aria-label=\"Video progress\"\n      style={{\n        background: `linear-gradient(to right, var(--color-primary-700) ${progressPercentage}%, var(--color-secondary-300) ${progressPercentage}%)`,\n      }}\n    />\n  </div>\n);\n\n/**\n * Volume controls component props\n */\ninterface VolumeControlsProps {\n  volume: number;\n  isMuted: boolean;\n  onVolumeChange: (volume: number) => void;\n  onToggleMute: () => void;\n  iconSize?: number;\n  showSlider?: boolean;\n}\n\n/**\n * Volume controls subcomponent\n */\nconst VolumeControls = ({\n  volume,\n  isMuted,\n  onVolumeChange,\n  onToggleMute,\n  iconSize = 24,\n  showSlider = true,\n}: VolumeControlsProps) => (\n  <div className=\"flex items-center gap-2\">\n    <IconButton\n      icon={\n        isMuted ? (\n          <SpeakerSlashIcon size={iconSize} />\n        ) : (\n          <SpeakerHighIcon size={iconSize} />\n        )\n      }\n      onClick={onToggleMute}\n      aria-label={isMuted ? 'Unmute' : 'Mute'}\n      className=\"!bg-transparent !text-white hover:!bg-white/20\"\n    />\n\n    {showSlider && (\n      <input\n        type=\"range\"\n        min={0}\n        max={100}\n        value={Math.round(volume * 100)}\n        onChange={(e) => onVolumeChange(Number.parseInt(e.target.value))}\n        className=\"w-20 h-1 bg-neutral-600 rounded-full appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary-500\"\n        aria-label=\"Volume control\"\n        style={{\n          background: `linear-gradient(to right, var(--color-primary-700) ${volume * 100}%, var(--color-secondary-300) ${volume * 100}%)`,\n        }}\n      />\n    )}\n  </div>\n);\n\n/**\n * Speed menu component props\n */\ninterface SpeedMenuProps {\n  showSpeedMenu: boolean;\n  playbackRate: number;\n  onToggleMenu: () => void;\n  onSpeedChange: (speed: number) => void;\n  isFullscreen: boolean;\n  iconSize?: number;\n  isTinyMobile?: boolean;\n}\n\n/**\n * Speed menu subcomponent\n */\nconst SpeedMenu = ({\n  showSpeedMenu,\n  playbackRate,\n  onToggleMenu,\n  onSpeedChange,\n  isFullscreen,\n  iconSize = 24,\n  isTinyMobile = false,\n}: SpeedMenuProps) => {\n  const buttonRef = useRef<HTMLButtonElement>(null);\n  const speedMenuContainerRef = useRef<HTMLDivElement>(null);\n  const speedMenuRef = useRef<HTMLDivElement>(null);\n\n  const getMenuPosition = () => {\n    if (!buttonRef.current) return { top: 0, left: 0 };\n    const rect = buttonRef.current.getBoundingClientRect();\n\n    // Adjust positioning for tiny mobile screens\n    const menuHeight = isTinyMobile ? 150 : 180;\n    const menuWidth = isTinyMobile ? 60 : 80;\n    const padding = isTinyMobile ? 4 : 8;\n\n    return {\n      // Fixed coords are viewport-based — no scroll offsets.\n      top: Math.max(padding, rect.top - menuHeight),\n      left: Math.max(padding, rect.right - menuWidth),\n    };\n  };\n\n  const position = getMenuPosition();\n\n  useEffect(() => {\n    const handleClickOutside = (event: Event) => {\n      const target = event.target as Node;\n\n      // Check if click is outside both the container and the menu\n      const isOutsideContainer =\n        speedMenuContainerRef.current &&\n        !speedMenuContainerRef.current.contains(target);\n      const isOutsideMenu =\n        speedMenuRef.current && !speedMenuRef.current.contains(target);\n\n      // Only close if click is outside both refs (null-safe checks)\n      if (isOutsideContainer && isOutsideMenu) {\n        onToggleMenu();\n      }\n    };\n\n    if (showSpeedMenu) {\n      document.addEventListener('mousedown', handleClickOutside);\n    }\n\n    return () => {\n      document.removeEventListener('mousedown', handleClickOutside);\n    };\n  }, [showSpeedMenu, onToggleMenu]);\n\n  const menuContent = (\n    <div\n      ref={speedMenuRef}\n      role=\"menu\"\n      aria-label=\"Playback speed\"\n      className={\n        isFullscreen\n          ? 'absolute bottom-12 right-0 bg-background border border-border-100 rounded-lg shadow-lg p-2 min-w-24 z-[9999]'\n          : 'fixed bg-background border border-border-100 rounded-lg shadow-lg p-2 min-w-24 z-[9999]'\n      }\n      style={\n        isFullscreen\n          ? undefined\n          : {\n              top: `${position.top}px`,\n              left: `${position.left}px`,\n            }\n      }\n    >\n      {[0.5, 0.75, 1, 1.25, 1.5, 2].map((speed) => (\n        <button\n          key={speed}\n          role=\"menuitemradio\"\n          aria-checked={playbackRate === speed}\n          onClick={() => onSpeedChange(speed)}\n          className={`block w-full text-left px-3 py-1 text-sm rounded hover:bg-border-50 transition-colors ${\n            playbackRate === speed\n              ? 'bg-primary-950 text-secondary-100 font-medium'\n              : 'text-text-950'\n          }`}\n        >\n          {speed}x\n        </button>\n      ))}\n    </div>\n  );\n\n  // SSR-safe portal content\n  const portalContent =\n    showSpeedMenu &&\n    globalThis.window !== undefined &&\n    globalThis.document !== undefined &&\n    !!globalThis.document?.body\n      ? createPortal(menuContent, globalThis.document.body)\n      : null;\n\n  return (\n    <div className=\"relative\" ref={speedMenuContainerRef}>\n      <IconButton\n        ref={buttonRef}\n        icon={<DotsThreeVerticalIcon size={iconSize} />}\n        onClick={onToggleMenu}\n        aria-label=\"Playback speed\"\n        aria-haspopup=\"menu\"\n        aria-expanded={showSpeedMenu}\n        className=\"!bg-transparent !text-white hover:!bg-white/20\"\n      />\n      {showSpeedMenu && (isFullscreen ? menuContent : portalContent)}\n    </div>\n  );\n};\n\n/**\n * Video player component with controls and progress tracking\n * Integrates with backend lesson progress system\n *\n * @param props - VideoPlayer component props\n * @returns Video player element with controls\n */\nconst VideoPlayer = ({\n  src,\n  poster,\n  subtitles,\n  title,\n  subtitle: subtitleText,\n  initialTime = 0,\n  onTimeUpdate,\n  onProgress,\n  onVideoComplete,\n  className,\n  autoSave = true,\n  storageKey = 'video-progress',\n  userId,\n  downloadContent,\n  showDownloadButton = false,\n  onDownloadStart,\n  onDownloadComplete,\n  onDownloadError,\n}: VideoPlayerProps) => {\n  const videoRef = useRef<HTMLVideoElement>(null);\n  const { isUltraSmallMobile, isTinyMobile } = useMobile();\n  const [isPlaying, setIsPlaying] = useState(false);\n  const [hasStarted, setHasStarted] = useState(false);\n  const [currentTime, setCurrentTime] = useState(0);\n  const [duration, setDuration] = useState(0);\n  const [isMuted, setIsMuted] = useState(false);\n  const [volume, setVolume] = useState(1);\n  const [isFullscreen, setIsFullscreen] = useState(false);\n  const [showControls, setShowControls] = useState(true);\n  const [hasCompleted, setHasCompleted] = useState(false);\n  const [showCaptions, setShowCaptions] = useState(false);\n  const [subtitlesValidation, setSubtitlesValidation] = useState<\n    'idle' | 'validating' | 'valid' | 'invalid'\n  >('idle');\n\n  // Reset completion flag when changing videos\n  useEffect(() => {\n    setHasCompleted(false);\n    setHasStarted(false);\n  }, [src]);\n  const [playbackRate, setPlaybackRate] = useState(1);\n  const [showSpeedMenu, setShowSpeedMenu] = useState(false);\n  const lastSaveTimeRef = useRef(0);\n  const trackRef = useRef<HTMLTrackElement>(null);\n  const controlsTimeoutRef = useRef<number | null>(null);\n  const lastMousePositionRef = useRef({ x: 0, y: 0 });\n\n  /**\n   * Check if user is currently interacting with controls\n   */\n  const isUserInteracting = useCallback(() => {\n    // Check if speed menu is open\n    if (showSpeedMenu) {\n      return true;\n    }\n\n    // Check if any control element has focus\n    const activeElement = document.activeElement;\n    const videoContainer = videoRef.current?.parentElement;\n\n    if (activeElement && videoContainer?.contains(activeElement)) {\n      // Ignore the video element itself - it should not prevent control hiding\n      if (activeElement === videoRef.current) {\n        return false;\n      }\n\n      // Check if focused element is a control (button, input, etc.)\n      const isControl = activeElement.matches('button, input, [tabindex]');\n      if (isControl) {\n        return true;\n      }\n    }\n\n    return false;\n  }, [showSpeedMenu]);\n\n  /**\n   * Clear controls timeout\n   */\n  const clearControlsTimeout = useCallback(() => {\n    if (controlsTimeoutRef.current) {\n      clearTimeout(controlsTimeoutRef.current);\n      controlsTimeoutRef.current = null;\n    }\n  }, []);\n\n  /**\n   * Show controls and set auto-hide timer\n   */\n  const showControlsWithTimer = useCallback(() => {\n    setShowControls(true);\n    clearControlsTimeout();\n\n    // In fullscreen mode, only hide if video is playing\n    if (isFullscreen) {\n      if (isPlaying) {\n        controlsTimeoutRef.current = globalThis.setTimeout(() => {\n          setShowControls(false);\n        }, CONTROLS_HIDE_TIMEOUT) as unknown as number;\n      }\n    } else {\n      // In normal mode, always set a timer to hide controls\n      controlsTimeoutRef.current = globalThis.setTimeout(() => {\n        setShowControls(false);\n      }, CONTROLS_HIDE_TIMEOUT) as unknown as number;\n    }\n  }, [isFullscreen, isPlaying, clearControlsTimeout]);\n\n  /**\n   * Handle mouse move with position detection\n   */\n  const handleMouseMove = useCallback(\n    (event: MouseEvent) => {\n      const currentX = event.clientX;\n      const currentY = event.clientY;\n      const lastPos = lastMousePositionRef.current;\n\n      // Check if mouse actually moved (minimum 5px threshold)\n      const hasMoved =\n        Math.abs(currentX - lastPos.x) > 5 ||\n        Math.abs(currentY - lastPos.y) > 5;\n\n      if (hasMoved) {\n        lastMousePositionRef.current = { x: currentX, y: currentY };\n        showControlsWithTimer();\n      }\n    },\n    [showControlsWithTimer]\n  );\n\n  /**\n   * Handle mouse enter to show controls with appropriate timer logic\n   */\n  const handleMouseEnter = useCallback(() => {\n    showControlsWithTimer();\n  }, [showControlsWithTimer]);\n\n  /**\n   * Handle mouse leave to hide controls faster\n   */\n  const handleMouseLeave = useCallback(() => {\n    const userInteracting = isUserInteracting();\n    clearControlsTimeout();\n\n    // Hide controls when mouse leaves, except when in fullscreen or user is interacting\n    if (!isFullscreen && !userInteracting) {\n      // Use shorter timeout when mouse leaves\n      controlsTimeoutRef.current = globalThis.setTimeout(() => {\n        setShowControls(false);\n      }, LEAVE_HIDE_TIMEOUT) as unknown as number;\n    }\n  }, [isFullscreen, clearControlsTimeout, isUserInteracting]);\n\n  /**\n   * Initialize video element properties\n   */\n  useEffect(() => {\n    // Set initial volume\n    if (videoRef.current) {\n      videoRef.current.volume = volume;\n      videoRef.current.muted = isMuted;\n    }\n  }, [volume, isMuted]);\n\n  /**\n   * Synchronize isPlaying state with media events\n   */\n  useEffect(() => {\n    const video = videoRef.current;\n    if (!video) return;\n\n    const onPlay = () => {\n      setIsPlaying(true);\n      setHasStarted(true);\n    };\n    const onPause = () => setIsPlaying(false);\n    const onEnded = () => setIsPlaying(false);\n\n    video.addEventListener('play', onPlay);\n    video.addEventListener('pause', onPause);\n    video.addEventListener('ended', onEnded);\n\n    return () => {\n      video.removeEventListener('play', onPlay);\n      video.removeEventListener('pause', onPause);\n      video.removeEventListener('ended', onEnded);\n    };\n  }, []);\n\n  /**\n   * Set iOS/Safari inline playback attributes imperatively\n   */\n  useEffect(() => {\n    const video = videoRef.current;\n    if (!video) return;\n\n    // Ensure inline playback on iOS/Safari\n    video.setAttribute('playsinline', '');\n    video.setAttribute('webkit-playsinline', '');\n  }, []);\n\n  /**\n   * Handle controls auto-hide when play state changes\n   */\n  useEffect(() => {\n    if (isPlaying) {\n      // Start timer when video starts playing\n      showControlsWithTimer();\n    } else {\n      // Keep controls visible when paused only in fullscreen\n      clearControlsTimeout();\n      if (isFullscreen) {\n        setShowControls(true);\n      } else {\n        // In normal mode (not fullscreen), initialize timer even when paused\n        // This ensures controls will hide properly from the start\n        showControlsWithTimer();\n      }\n    }\n  }, [isPlaying, isFullscreen, showControlsWithTimer, clearControlsTimeout]);\n\n  /**\n   * Handle fullscreen state changes from browser events\n   */\n  useEffect(() => {\n    const video = videoRef.current;\n    if (!video) return;\n\n    const handleFullscreenChange = () => {\n      const isCurrentlyFullscreen = !!document.fullscreenElement;\n      setIsFullscreen(isCurrentlyFullscreen);\n\n      // Show controls when entering fullscreen, hide after timeout if playing\n      if (isCurrentlyFullscreen) {\n        showControlsWithTimer();\n      }\n    };\n\n    // Safari iOS-specific fullscreen event handlers\n    const handleWebkitBeginFullscreen = () => {\n      setIsFullscreen(true);\n      showControlsWithTimer();\n    };\n\n    const handleWebkitEndFullscreen = () => {\n      setIsFullscreen(false);\n    };\n\n    // Standard fullscreen events\n    document.addEventListener('fullscreenchange', handleFullscreenChange);\n\n    // Safari iOS fullscreen events\n    video.addEventListener(\n      'webkitbeginfullscreen',\n      handleWebkitBeginFullscreen\n    );\n    video.addEventListener('webkitendfullscreen', handleWebkitEndFullscreen);\n\n    return () => {\n      document.removeEventListener('fullscreenchange', handleFullscreenChange);\n      video.removeEventListener(\n        'webkitbeginfullscreen',\n        handleWebkitBeginFullscreen\n      );\n      video.removeEventListener(\n        'webkitendfullscreen',\n        handleWebkitEndFullscreen\n      );\n    };\n  }, [showControlsWithTimer]);\n\n  /**\n   * Initialize controls behavior on component mount\n   * This ensures controls work correctly from the first load\n   */\n  useEffect(() => {\n    const init = () => {\n      if (!isFullscreen) {\n        showControlsWithTimer();\n      }\n    };\n    // Prefer rAF to avoid arbitrary timing if available; fall back to INIT_DELAY.\n    let raf1 = 0,\n      raf2 = 0,\n      tid: number | undefined;\n    if (globalThis.requestAnimationFrame === undefined) {\n      tid = globalThis.setTimeout(init, INIT_DELAY) as unknown as number;\n      return () => {\n        if (tid) clearTimeout(tid);\n      };\n    } else {\n      raf1 = requestAnimationFrame(() => {\n        raf2 = requestAnimationFrame(init);\n      });\n      return () => {\n        cancelAnimationFrame(raf1);\n        cancelAnimationFrame(raf2);\n      };\n    }\n  }, []); // Run only once on mount\n\n  /**\n   * Get initial time from props or localStorage\n   */\n  const getInitialTime = useCallback((): number | undefined => {\n    if (!autoSave || !storageKey) {\n      return Number.isFinite(initialTime) && initialTime >= 0\n        ? initialTime\n        : undefined;\n    }\n\n    const scopedKey = userId ? `${storageKey}-${userId}` : storageKey;\n    const saved = Number(\n      localStorage.getItem(`${scopedKey}-${src}`) || Number.NaN\n    );\n    const hasValidInitial = Number.isFinite(initialTime) && initialTime >= 0;\n    const hasValidSaved = Number.isFinite(saved) && saved >= 0;\n\n    if (hasValidInitial) return initialTime;\n    if (hasValidSaved) return saved;\n    return undefined;\n  }, [autoSave, storageKey, userId, src, initialTime]);\n\n  /**\n   * Load saved progress from localStorage\n   */\n  useEffect(() => {\n    const start = getInitialTime();\n    if (start !== undefined && Number.isFinite(start) && videoRef.current) {\n      videoRef.current.currentTime = start;\n      setCurrentTime(start);\n    }\n  }, [getInitialTime]);\n\n  /**\n   * Save progress to localStorage periodically\n   */\n  const saveProgress = useCallback(\n    (time: number) => {\n      if (!autoSave || !storageKey) return;\n\n      const now = Date.now();\n      if (now - lastSaveTimeRef.current > 5000) {\n        const scopedKey = userId ? `${storageKey}-${userId}` : storageKey;\n        localStorage.setItem(`${scopedKey}-${src}`, time.toString());\n        lastSaveTimeRef.current = now;\n      }\n    },\n    [autoSave, storageKey, userId, src]\n  );\n\n  /**\n   * Handle play/pause toggle\n   */\n  const togglePlayPause = useCallback(async () => {\n    const video = videoRef.current;\n    if (!video) return;\n\n    if (!video.paused) {\n      video.pause();\n      return;\n    }\n\n    try {\n      await video.play();\n    } catch {\n      // Playback prevented (e.g., autoplay policy); keep state unchanged.\n    }\n  }, []);\n\n  /**\n   * Handle volume change\n   */\n  const handleVolumeChange = useCallback(\n    (newVolume: number) => {\n      const video = videoRef.current;\n      if (!video) return;\n\n      const volumeValue = newVolume / 100; // Convert 0-100 to 0-1\n      video.volume = volumeValue;\n      setVolume(volumeValue);\n\n      // Auto mute/unmute based on volume\n      const shouldMute = volumeValue === 0;\n      const shouldUnmute = volumeValue > 0 && isMuted;\n\n      if (shouldMute) {\n        video.muted = true;\n        setIsMuted(true);\n      } else if (shouldUnmute) {\n        video.muted = false;\n        setIsMuted(false);\n      }\n    },\n    [isMuted]\n  );\n\n  /**\n   * Handle mute toggle\n   */\n  const toggleMute = useCallback(() => {\n    const video = videoRef.current;\n    if (!video) return;\n\n    if (isMuted) {\n      // Unmute: restore volume or set to 50% if it was 0\n      const restoreVolume = volume > 0 ? volume : 0.5;\n      video.volume = restoreVolume;\n      video.muted = false;\n      setVolume(restoreVolume);\n      setIsMuted(false);\n    } else {\n      // Mute: set volume to 0 and mute\n      video.muted = true;\n      setIsMuted(true);\n    }\n  }, [isMuted, volume]);\n\n  /**\n   * Handle video seek\n   */\n  const handleSeek = useCallback((newTime: number) => {\n    const video = videoRef.current;\n    if (video && Number.isFinite(newTime)) {\n      video.currentTime = newTime;\n    }\n  }, []);\n\n  /**\n   * Detect if running on Safari iOS\n   */\n  const isSafariIOS = useCallback((): boolean => {\n    const ua = navigator.userAgent;\n    const isIOS = /iPad|iPhone|iPod/.test(ua);\n    const isWebKit = /WebKit/.test(ua);\n    const isNotChrome = !/CriOS|Chrome/.test(ua);\n    return isIOS && isWebKit && isNotChrome;\n  }, []);\n\n  /**\n   * Handle fullscreen toggle\n   */\n  const toggleFullscreen = useCallback(() => {\n    const video = videoRef.current;\n    const container = video?.parentElement;\n    if (!video || !container) return;\n\n    // Safari iOS requires using webkitEnterFullscreen on video element\n    if (isSafariIOS()) {\n      // Type assertion for Safari-specific API\n      const videoElement = video as HTMLVideoElement & {\n        webkitEnterFullscreen?: () => void;\n        webkitExitFullscreen?: () => void;\n        webkitDisplayingFullscreen?: boolean;\n      };\n\n      if (!isFullscreen && videoElement.webkitEnterFullscreen) {\n        videoElement.webkitEnterFullscreen();\n      } else if (isFullscreen && videoElement.webkitExitFullscreen) {\n        videoElement.webkitExitFullscreen();\n      }\n    } else if (!isFullscreen && container.requestFullscreen) {\n      // Standard fullscreen API for other browsers. The returned promise can\n      // reject (e.g. document not active after a tab switch); swallow it.\n      container.requestFullscreen().catch(() => {});\n    } else if (isFullscreen && document.exitFullscreen) {\n      document.exitFullscreen().catch(() => {});\n    }\n  }, [isFullscreen, isSafariIOS]);\n\n  /**\n   * Handle playback speed change\n   */\n  const handleSpeedChange = useCallback((speed: number) => {\n    if (videoRef.current) {\n      videoRef.current.playbackRate = speed;\n      setPlaybackRate(speed);\n      setShowSpeedMenu(false);\n    }\n  }, []);\n\n  /**\n   * Toggle speed menu visibility\n   */\n  const toggleSpeedMenu = useCallback(() => {\n    setShowSpeedMenu(!showSpeedMenu);\n  }, [showSpeedMenu]);\n\n  /**\n   * Toggle captions visibility\n   */\n  const toggleCaptions = useCallback(() => {\n    if (\n      !trackRef.current?.track ||\n      !subtitles ||\n      subtitlesValidation !== 'valid'\n    )\n      return;\n\n    const newShowCaptions = !showCaptions;\n    setShowCaptions(newShowCaptions);\n\n    // Control track mode programmatically - we already validated subtitles above\n    trackRef.current.track.mode = newShowCaptions ? 'showing' : 'hidden';\n  }, [showCaptions, subtitles, subtitlesValidation]);\n\n  /**\n   * Check video completion and fire callback\n   */\n  const checkVideoCompletion = useCallback(\n    (progressPercent: number) => {\n      if (progressPercent >= 95 && !hasCompleted) {\n        setHasCompleted(true);\n        onVideoComplete?.();\n      }\n    },\n    [hasCompleted, onVideoComplete]\n  );\n\n  /**\n   * Handle time update\n   */\n  const handleTimeUpdate = useCallback(() => {\n    const video = videoRef.current;\n    if (!video) return;\n\n    const current = video.currentTime;\n    setCurrentTime(current);\n\n    // Save progress periodically\n    saveProgress(current);\n\n    // Fire callbacks\n    onTimeUpdate?.(current);\n\n    if (duration > 0) {\n      const progressPercent = (current / duration) * 100;\n      onProgress?.(progressPercent);\n      checkVideoCompletion(progressPercent);\n    }\n  }, [duration, saveProgress, onTimeUpdate, onProgress, checkVideoCompletion]);\n\n  /**\n   * Handle loaded metadata\n   */\n  const handleLoadedMetadata = useCallback(() => {\n    if (videoRef.current) {\n      setDuration(videoRef.current.duration);\n    }\n  }, []);\n\n  /**\n   * Validate subtitles URL before showing the button\n   */\n  useEffect(() => {\n    const controller = new AbortController();\n\n    const validateSubtitles = async () => {\n      // If no subtitles, mark as idle\n      if (!subtitles) {\n        setSubtitlesValidation('idle');\n        return;\n      }\n\n      // Start validation\n      setSubtitlesValidation('validating');\n\n      try {\n        // Check if it's a data URL (inline VTT)\n        if (subtitles.startsWith('data:')) {\n          setSubtitlesValidation('valid');\n          return;\n        }\n\n        // Fetch the subtitles file to validate it\n        const response = await fetch(subtitles, {\n          method: 'HEAD',\n          signal: controller.signal,\n        });\n\n        if (response.ok) {\n          // Optionally check content type\n          const contentType = response.headers.get('content-type');\n          const isValidType =\n            !contentType ||\n            contentType.includes('text/vtt') ||\n            contentType.includes('text/plain') ||\n            contentType.includes('application/octet-stream');\n\n          if (isValidType) {\n            setSubtitlesValidation('valid');\n          } else {\n            setSubtitlesValidation('invalid');\n            console.warn(\n              `Subtitles URL has invalid content type: ${contentType}`\n            );\n          }\n        } else {\n          setSubtitlesValidation('invalid');\n          console.warn(\n            `Subtitles URL returned status: ${response.status} ${response.statusText}`\n          );\n        }\n      } catch (error) {\n        // Ignore AbortError - it's expected when cleaning up\n        if (error instanceof Error && error.name === 'AbortError') {\n          return;\n        }\n        console.warn('Subtitles URL validation failed:', error);\n        setSubtitlesValidation('invalid');\n      }\n    };\n\n    validateSubtitles();\n\n    // Cleanup: abort ongoing fetch to prevent stale updates\n    return () => {\n      controller.abort();\n    };\n  }, [subtitles]);\n\n  /**\n   * Initialize track mode when track is available\n   */\n  useEffect(() => {\n    if (trackRef.current?.track) {\n      // Set initial mode based on showCaptions state and subtitle availability\n      trackRef.current.track.mode =\n        showCaptions && subtitles && subtitlesValidation === 'valid'\n          ? 'showing'\n          : 'hidden';\n    }\n  }, [subtitles, showCaptions, subtitlesValidation]);\n\n  /**\n   * Handle visibility change and blur to pause video when losing focus\n   */\n  useEffect(() => {\n    const handleVisibilityChange = () => {\n      if (document.hidden && isPlaying && videoRef.current) {\n        videoRef.current.pause();\n        setIsPlaying(false);\n      }\n    };\n\n    const handleBlur = () => {\n      if (isPlaying && videoRef.current) {\n        videoRef.current.pause();\n        setIsPlaying(false);\n      }\n    };\n\n    document.addEventListener('visibilitychange', handleVisibilityChange);\n    globalThis.addEventListener('blur', handleBlur);\n\n    return () => {\n      document.removeEventListener('visibilitychange', handleVisibilityChange);\n      globalThis.removeEventListener('blur', handleBlur);\n      // Clean up timers on unmount\n      clearControlsTimeout();\n    };\n  }, [isPlaying, clearControlsTimeout]);\n\n  const progressPercentage = duration > 0 ? (currentTime / duration) * 100 : 0;\n\n  /**\n   * Get responsive icon size based on screen size\n   */\n  const getIconSize = useCallback(() => {\n    if (isTinyMobile) return 18;\n    if (isUltraSmallMobile) return 20;\n    return 24;\n  }, [isTinyMobile, isUltraSmallMobile]);\n\n  /**\n   * Get responsive padding classes for controls\n   */\n  const getControlsPadding = useCallback(() => {\n    if (isTinyMobile) return 'px-2 pb-2 pt-1';\n    if (isUltraSmallMobile) return 'px-3 pb-3 pt-1';\n    return 'px-4 pb-4';\n  }, [isTinyMobile, isUltraSmallMobile]);\n\n  /**\n   * Get responsive gap classes for controls\n   */\n  const getControlsGap = useCallback(() => {\n    if (isTinyMobile) return 'gap-1';\n    if (isUltraSmallMobile) return 'gap-2';\n    return 'gap-4';\n  }, [isTinyMobile, isUltraSmallMobile]);\n\n  /**\n   * Get responsive padding for progress bar\n   */\n  const getProgressBarPadding = useCallback(() => {\n    if (isTinyMobile) return 'px-2 pb-1';\n    if (isUltraSmallMobile) return 'px-3 pb-1';\n    return 'px-4 pb-2';\n  }, [isTinyMobile, isUltraSmallMobile]);\n\n  /**\n   * Get responsive positioning classes for center play button\n   */\n  const getCenterPlayButtonPosition = useCallback(() => {\n    if (isTinyMobile) return 'items-center justify-center -translate-y-12';\n    if (isUltraSmallMobile) return 'items-center justify-center -translate-y-8';\n    return 'items-center justify-center';\n  }, [isTinyMobile, isUltraSmallMobile]);\n\n  /**\n   * Calculate top controls opacity based on state\n   */\n  const getTopControlsOpacity = useCallback(() => {\n    return showControls ? 'opacity-100' : 'opacity-0';\n  }, [showControls]);\n\n  /**\n   * Calculate bottom controls opacity based on state\n   */\n  const getBottomControlsOpacity = useCallback(() => {\n    return showControls ? 'opacity-100' : 'opacity-0';\n  }, [showControls]);\n\n  /**\n   * Seek video backward\n   */\n  const seekBackward = useCallback(() => {\n    if (videoRef.current) {\n      videoRef.current.currentTime -= 10;\n    }\n  }, []);\n\n  /**\n   * Seek video forward\n   */\n  const seekForward = useCallback(() => {\n    if (videoRef.current) {\n      videoRef.current.currentTime += 10;\n    }\n  }, []);\n\n  /**\n   * Increase volume\n   */\n  const increaseVolume = useCallback(() => {\n    handleVolumeChange(Math.min(100, volume * 100 + 10));\n  }, [handleVolumeChange, volume]);\n\n  /**\n   * Decrease volume\n   */\n  const decreaseVolume = useCallback(() => {\n    handleVolumeChange(Math.max(0, volume * 100 - 10));\n  }, [handleVolumeChange, volume]);\n\n  /**\n   * Handle video element keyboard events\n   */\n  const handleVideoKeyDown = useCallback(\n    (e: KeyboardEvent) => {\n      if (!e.key) return;\n\n      // Prevent bubbling to parent handlers to avoid double toggles\n      e.stopPropagation();\n      showControlsWithTimer();\n\n      // Map of key handlers for better maintainability and reduced complexity\n      const keyHandlers: Record<string, () => void | Promise<void>> = {\n        ' ': togglePlayPause,\n        Enter: togglePlayPause,\n        ArrowLeft: seekBackward,\n        ArrowRight: seekForward,\n        ArrowUp: increaseVolume,\n        ArrowDown: decreaseVolume,\n        m: toggleMute,\n        M: toggleMute,\n        f: toggleFullscreen,\n        F: toggleFullscreen,\n      };\n\n      const handler = keyHandlers[e.key];\n      if (handler) {\n        e.preventDefault();\n        handler();\n      }\n    },\n    [\n      showControlsWithTimer,\n      togglePlayPause,\n      seekBackward,\n      seekForward,\n      increaseVolume,\n      decreaseVolume,\n      toggleMute,\n      toggleFullscreen,\n    ]\n  );\n\n  const groupedSubTitleValid = subtitles && subtitlesValidation === 'valid';\n  const showPoster = Boolean(poster) && !hasStarted;\n\n  return (\n    <div className={cn('flex flex-col', className)}>\n      {/* Integrated Header */}\n      {(title || subtitleText) && (\n        <div className=\"bg-subject-1 px-8 py-4 flex items-end justify-between min-h-20\">\n          <div className=\"flex flex-col gap-1\">\n            {title && (\n              <Text\n                as=\"h2\"\n                size=\"lg\"\n                weight=\"bold\"\n                color=\"text-text-900\"\n                className=\"leading-5 tracking-wide\"\n              >\n                {title}\n              </Text>\n            )}\n            {subtitleText && (\n              <Text\n                as=\"p\"\n                size=\"sm\"\n                weight=\"normal\"\n                color=\"text-text-600\"\n                className=\"leading-5\"\n              >\n                {subtitleText}\n              </Text>\n            )}\n          </div>\n\n          {/* Download Button */}\n          {showDownloadButton && downloadContent && (\n            <DownloadButton\n              content={downloadContent}\n              lessonTitle={title}\n              onDownloadStart={onDownloadStart}\n              onDownloadComplete={onDownloadComplete}\n              onDownloadError={onDownloadError}\n              className=\"flex-shrink-0\"\n            />\n          )}\n        </div>\n      )}\n\n      {/* Video Container */}\n      <section\n        className={cn(\n          'relative w-full bg-background overflow-hidden group',\n          'rounded-b-xl',\n          // Hide cursor when controls are hidden and video is playing\n          isPlaying && !showControls\n            ? 'cursor-none group-hover:cursor-default'\n            : 'cursor-default'\n        )}\n        aria-label={title ? `Video player: ${title}` : 'Video player'}\n        onMouseMove={handleMouseMove}\n        onMouseEnter={handleMouseEnter}\n        onTouchStart={handleMouseEnter}\n        onMouseLeave={handleMouseLeave}\n      >\n        {/* Video Element */}\n        <video\n          ref={videoRef}\n          src={src}\n          crossOrigin=\"anonymous\"\n          className=\"w-full h-full object-contain analytica-video\"\n          controlsList=\"nodownload\"\n          playsInline\n          onTimeUpdate={handleTimeUpdate}\n          onLoadedMetadata={handleLoadedMetadata}\n          onClick={togglePlayPause}\n          onKeyDown={handleVideoKeyDown}\n          tabIndex={0}\n          aria-label={title ? `Video: ${title}` : 'Video player'}\n        >\n          <track\n            ref={trackRef}\n            kind=\"captions\"\n            src={\n              groupedSubTitleValid\n                ? subtitles\n                : 'data:text/vtt;charset=utf-8,WEBVTT'\n            }\n            srcLang=\"pt-br\"\n            label={\n              groupedSubTitleValid\n                ? 'Legendas em Português'\n                : 'Sem legendas disponíveis'\n            }\n            default={false}\n          />\n        </video>\n\n        {showPoster && (\n          <img\n            src={poster}\n            alt={title ? `Capa: ${title}` : 'Capa do vídeo'}\n            className=\"absolute inset-0 w-full h-full object-cover\"\n            aria-hidden=\"true\"\n          />\n        )}\n\n        {/* Center Play Button */}\n        {!isPlaying && (\n          <div\n            className={cn(\n              'absolute inset-0 flex bg-black/30 transition-opacity',\n              getCenterPlayButtonPosition()\n            )}\n          >\n            <IconButton\n              icon={<PlayIcon size={32} weight=\"regular\" className=\"ml-1\" />}\n              onClick={togglePlayPause}\n              aria-label=\"Play video\"\n              className=\"!bg-transparent !text-white !w-auto !h-auto hover:!bg-transparent hover:!text-gray-200\"\n            />\n          </div>\n        )}\n\n        {/* Top Controls */}\n        <div\n          className={cn(\n            'absolute top-0 left-0 right-0 p-4 bg-gradient-to-b from-black/70 to-transparent transition-opacity',\n            getTopControlsOpacity()\n          )}\n        >\n          <div className=\"flex justify-start\">\n            <IconButton\n              icon={\n                isFullscreen ? (\n                  <ArrowsInSimpleIcon size={24} />\n                ) : (\n                  <ArrowsOutSimpleIcon size={24} />\n                )\n              }\n              onClick={toggleFullscreen}\n              aria-label={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n              className=\"!bg-transparent !text-white hover:!bg-white/20\"\n            />\n          </div>\n        </div>\n\n        {/* Bottom Controls */}\n        <div\n          className={cn(\n            'absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/90 to-transparent transition-opacity',\n            getBottomControlsOpacity()\n          )}\n        >\n          {/* Progress Bar */}\n          <ProgressBar\n            currentTime={currentTime}\n            duration={duration}\n            progressPercentage={progressPercentage}\n            onSeek={handleSeek}\n            className={getProgressBarPadding()}\n          />\n\n          {/* Control Buttons */}\n          <div\n            className={cn(\n              'flex items-center justify-between',\n              getControlsPadding()\n            )}\n          >\n            {/* Left Controls */}\n            <div className={cn('flex items-center', getControlsGap())}>\n              {/* Play/Pause */}\n              <IconButton\n                icon={\n                  isPlaying ? (\n                    <PauseIcon size={getIconSize()} />\n                  ) : (\n                    <PlayIcon size={getIconSize()} />\n                  )\n                }\n                onClick={togglePlayPause}\n                aria-label={isPlaying ? 'Pause' : 'Play'}\n                className=\"!bg-transparent !text-white hover:!bg-white/20\"\n              />\n\n              {/* Volume */}\n              <VolumeControls\n                volume={volume}\n                isMuted={isMuted}\n                onVolumeChange={handleVolumeChange}\n                onToggleMute={toggleMute}\n                iconSize={getIconSize()}\n                showSlider={!isUltraSmallMobile}\n              />\n\n              {/* Captions - Only show after validation is complete and valid */}\n              {groupedSubTitleValid && (\n                <IconButton\n                  icon={<ClosedCaptioningIcon size={getIconSize()} />}\n                  onClick={toggleCaptions}\n                  aria-label={showCaptions ? 'Hide captions' : 'Show captions'}\n                  className={cn(\n                    '!bg-transparent hover:!bg-white/20',\n                    showCaptions ? '!text-primary-400' : '!text-white'\n                  )}\n                />\n              )}\n\n              {/* Time Display */}\n              <Text size=\"sm\" weight=\"medium\" color=\"text-white\">\n                {formatTime(currentTime)} / {formatTime(duration)}\n              </Text>\n            </div>\n\n            {/* Right Controls */}\n            <div className=\"flex items-center gap-4\">\n              {/* Speed Control */}\n              <SpeedMenu\n                showSpeedMenu={showSpeedMenu}\n                playbackRate={playbackRate}\n                onToggleMenu={toggleSpeedMenu}\n                onSpeedChange={handleSpeedChange}\n                iconSize={getIconSize()}\n                isTinyMobile={isTinyMobile}\n                isFullscreen={isFullscreen}\n              />\n            </div>\n          </div>\n        </div>\n      </section>\n    </div>\n  );\n};\n\nexport default VideoPlayer;\n"],"mappings":"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","names":[]}