import { useEffect, useState, useRef, useCallback } from 'react'
import Hls from 'hls.js'
import { useGesture } from '@use-gesture/react'
import {
  ChevronLeft,
  ChevronRight,
  Heart,
  MoreHorizontal,
  X,
  Download,
  Copy,
  ZoomIn,
  ZoomOut,
  RotateCcw,
  Video,
  User,
  Info,
  Image as ImageIcon,
  HardDrive,
  Calendar,
  Clock,
  Play,
  Pause,
  Shuffle,
  PictureInPicture2,
  Lock,
  Trash2,
} from 'lucide-react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { notificationManager } from '../../lib/notificationManager'
import { api, PaidContentPost, PaidContentAttachment } from '../../lib/api'
import { decodeHtmlEntities, THUMB_CACHE_V } from '../../lib/utils'

// Format bytes to human readable
function formatBytes(bytes: number | null | undefined): string {
  if (!bytes || bytes === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`
}

// Format date
function formatDate(dateStr: string | null | undefined): string {
  if (!dateStr) return ''
  const date = new Date(dateStr)
  return date.toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  })
}

// Format video duration
function formatDuration(seconds: number | null | undefined): string {
  if (!seconds || seconds <= 0) return ''
  const h = Math.floor(seconds / 3600)
  const m = Math.floor((seconds % 3600) / 60)
  const s = Math.floor(seconds % 60)
  if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
  return `${m}:${s.toString().padStart(2, '0')}`
}

interface BundleLightboxProps {
  post: PaidContentPost
  attachments: PaidContentAttachment[]
  currentIndex: number
  startTime?: number  // Video start time in seconds
  wasPlaying?: boolean  // Whether video was playing when lightbox opened
  autoPlayVideo?: boolean  // Always autoplay videos when lightbox opens
  onClose: () => void
  onCloseWithVideoState?: (attachmentId: number, time: number, wasPlaying: boolean) => void
  onNavigate: (index: number) => void
  onViewPost?: () => void
  onToggleFavorite?: () => void
  initialSlideshow?: boolean
  initialInterval?: number  // Override default slideshow interval (ms)
  initialShuffle?: boolean  // Override default shuffle setting
  totalCount?: number  // Total items across all pages (for position indicator)
  hasMore?: boolean  // Whether more pages can be loaded
  onLoadMore?: () => void  // Fetch next page
  onDelete?: (attachment: PaidContentAttachment) => void
  onShuffleChange?: (enabled: boolean) => void  // Parent-managed shuffle (backend random)
  isShuffled?: boolean  // Whether items are already in shuffled order from parent
}

export default function BundleLightbox({
  post,
  attachments,
  currentIndex,
  startTime,
  wasPlaying = false,
  autoPlayVideo = false,
  onClose,
  onCloseWithVideoState,
  onNavigate,
  onViewPost,
  onToggleFavorite,
  initialSlideshow = false,
  initialInterval,
  initialShuffle,
  totalCount,
  hasMore,
  onLoadMore,
  onDelete,
  onShuffleChange,
  isShuffled,
}: BundleLightboxProps) {
  const currentItem = attachments[currentIndex]
  // Preview frames are video thumbnails (jpg) for DRM-protected videos — treat as images
  const imageExts = ['jpg', 'jpeg', 'png', 'webp', 'gif']
  const isPreviewFrame = (a: { file_type?: string | null; extension?: string | null }) =>
    a.file_type === 'video' && imageExts.includes(a.extension?.toLowerCase() || '')
  const isCurrentVideo = currentItem?.file_type === 'video' && !isPreviewFrame(currentItem)

  // Mobile detection (landscape phones get desktop layout)
  const [isMobile, setIsMobile] = useState(false)
  const [isLandscape, setIsLandscape] = useState(false)
  useEffect(() => {
    const check = () => {
      const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0
      const portrait = window.innerWidth < 768
      const landscapePhone = hasTouch && window.innerHeight < 500
      setIsMobile(portrait && !landscapePhone)
      setIsLandscape(landscapePhone && !portrait)
    }
    check()
    window.addEventListener('resize', check)
    return () => window.removeEventListener('resize', check)
  }, [])

  // Watch Later
  const queryClient = useQueryClient()
  const { data: watchLaterIds = [] } = useQuery({
    queryKey: ['paid-content-watch-later-ids'],
    queryFn: () => api.paidContent.getWatchLaterAttachmentIds(),
    staleTime: 30000,
  })
  const watchLaterSet = new Set(watchLaterIds)
  const isCurrentInWatchLater = currentItem ? watchLaterSet.has(currentItem.id) : false

  const addWatchLaterMutation = useMutation({
    mutationFn: (attachmentId: number) => api.paidContent.addToWatchLater(attachmentId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['paid-content-watch-later-ids'] })
      notificationManager.success('Added', 'Added to Watch Later')
    },
  })
  const removeWatchLaterMutation = useMutation({
    mutationFn: (attachmentId: number) => api.paidContent.removeFromWatchLater(attachmentId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['paid-content-watch-later-ids'] })
      queryClient.invalidateQueries({ queryKey: ['paid-content-watch-later'] })
      notificationManager.success('Removed', 'Removed from Watch Later')
    },
  })
  const handleToggleWatchLater = () => {
    if (!currentItem) return
    if (isCurrentInWatchLater) {
      removeWatchLaterMutation.mutate(currentItem.id)
    } else {
      addWatchLaterMutation.mutate(currentItem.id)
    }
    setMenuOpen(false)
  }

  // Bundle sidebar state - collapsed by default, user can expand manually
  const [sidebarOpen, setSidebarOpen] = useState(false)
  const [menuOpen, setMenuOpen] = useState(false)
  const [showMetadata, setShowMetadata] = useState(false)
  const showControls = true // Controls always visible (removed tap-to-toggle for better UX)

  // Slideshow state
  const [slideshowPlaying, setSlideshowPlaying] = useState(initialSlideshow)
  const [slideshowInterval, setSlideshowInterval] = useState(initialInterval ?? 5000)
  const slideshowTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  // Shuffle state
  // When parent manages shuffle (onShuffleChange provided), items are already in shuffled order.
  // Internal shuffle state is only used for client-side shuffle (no onShuffleChange).
  const [shuffleEnabled, setShuffleEnabled] = useState(onShuffleChange ? false : (initialShuffle ?? false))
  const [shuffleOrder, setShuffleOrder] = useState<number[]>([])
  const [shufflePosition, setShufflePosition] = useState(0)

  const buildShuffleOrder = useCallback((startIndex: number) => {
    const indices = Array.from({ length: attachments.length }, (_, i) => i)
    for (let i = indices.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [indices[i], indices[j]] = [indices[j], indices[i]]
    }
    const pos = indices.indexOf(startIndex)
    if (pos > 0) {
      [indices[0], indices[pos]] = [indices[pos], indices[0]]
    }
    setShuffleOrder(indices)
    setShufflePosition(0)
  }, [attachments.length])

  const toggleShuffle = useCallback(() => {
    if (onShuffleChange) {
      // Parent-managed shuffle: delegate to parent, skip internal shuffle
      onShuffleChange(!isShuffled)
      return
    }
    if (!shuffleEnabled) {
      buildShuffleOrder(currentIndex)
      setShuffleEnabled(true)
    } else {
      setShuffleEnabled(false)
      setShuffleOrder([])
      setShufflePosition(0)
    }
  }, [shuffleEnabled, currentIndex, buildShuffleOrder, onShuffleChange, isShuffled])

  // Build shuffle order on mount when starting with shuffle enabled (client-side only)
  useEffect(() => {
    if (shuffleEnabled && shuffleOrder.length === 0 && !onShuffleChange) {
      buildShuffleOrder(currentIndex)
    }
  }, []) // eslint-disable-line react-hooks/exhaustive-deps

  // Zoom/pan state for images
  const [zoom, setZoom] = useState(1)
  const [pan, setPan] = useState({ x: 0, y: 0 })
  const [isPanning, setIsPanning] = useState(false)
  const [panStart, setPanStart] = useState({ x: 0, y: 0 })

  // Loading states
  const [imageLoading, setImageLoading] = useState(true)
  const [imageError, setImageError] = useState(false)
  const loadedUrlRef = useRef<string | null>(null)

  // Video aspect ratio for portrait video sizing
  const [videoAspectRatio, setVideoAspectRatio] = useState<number | null>(null)

  // Image dimensions for zoom calculation
  const [naturalSize, setNaturalSize] = useState<{ width: number; height: number } | null>(null)
  const [displayedSize, setDisplayedSize] = useState<{ width: number; height: number } | null>(null)

  // Auto-hide floating zoom controls
  const [zoomControlsVisible, setZoomControlsVisible] = useState(false)
  const zoomControlsTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  const maxZoom = naturalSize && displayedSize
    ? Math.max(5, Math.ceil((naturalSize.width / displayedSize.width) * 1.5))
    : 5

  const containerRef = useRef<HTMLDivElement>(null)
  const imageRef = useRef<HTMLImageElement>(null)
  const thumbnailStripRef = useRef<HTMLDivElement>(null)
  const videoRef = useRef<HTMLVideoElement>(null)
  const hlsRef = useRef<Hls | null>(null)

  // Video playback: try direct file first (instant start), fall back to HLS if it fails
  // (some yt-dlp merged files have timestamp issues that only ffmpeg/HLS can fix)
  useEffect(() => {
    const video = videoRef.current
    if (!video || !isCurrentVideo || !currentItem?.id) return

    // Clean up previous HLS instance
    if (hlsRef.current) {
      hlsRef.current.destroy()
      hlsRef.current = null
    }

    let hlsFallbackUsed = false

    const switchToHls = () => {
      if (hlsFallbackUsed) return
      hlsFallbackUsed = true
      const hlsUrl = `/api/paid-content/files/hls/${currentItem.id}/playlist.m3u8`
      if (Hls.isSupported()) {
        const hls = new Hls({ maxBufferLength: 30, maxMaxBufferLength: 60 })
        hlsRef.current = hls
        hls.loadSource(hlsUrl)
        hls.attachMedia(video)
        hls.on(Hls.Events.MANIFEST_PARSED, () => {
          video.play().catch(() => {})
        })
        hls.on(Hls.Events.ERROR, (_event, data) => {
          if (data.fatal && data.type === Hls.ErrorTypes.NETWORK_ERROR) {
            hls.startLoad()
          }
        })
      }
    }

    // Try direct file first — instant start via range requests
    video.src = getPreviewUrl(currentItem)

    const handleError = () => {
      // Direct playback failed (timestamp/container issues) — fall back to HLS
      if (!hlsFallbackUsed) {
        video.removeEventListener('error', handleError)
        switchToHls()
      }
    }
    video.addEventListener('error', handleError)

    return () => {
      video.removeEventListener('error', handleError)
      if (hlsRef.current) {
        hlsRef.current.destroy()
        hlsRef.current = null
      }
    }
  }, [isCurrentVideo, currentItem?.id])

  // Handle closing with video state
  const handleClose = useCallback(() => {
    if (isCurrentVideo && videoRef.current && onCloseWithVideoState) {
      const video = videoRef.current
      onCloseWithVideoState(currentItem.id, video.currentTime, !video.paused)
    } else {
      onClose()
    }
  }, [isCurrentVideo, currentItem?.id, onCloseWithVideoState, onClose])

  // Show zoom controls with auto-hide timer
  const showZoomControls = useCallback(() => {
    if (isCurrentVideo) return
    setZoomControlsVisible(true)
    if (zoomControlsTimerRef.current) clearTimeout(zoomControlsTimerRef.current)
    zoomControlsTimerRef.current = setTimeout(() => setZoomControlsVisible(false), 2500)
  }, [isCurrentVideo])

  // Cleanup zoom controls timer on unmount
  useEffect(() => {
    return () => { if (zoomControlsTimerRef.current) clearTimeout(zoomControlsTimerRef.current) }
  }, [])

  // Set video bottom offset (simplified - use fixed offset for HLS player)
  // Slideshow: collapse sidebar and hide metadata when starting
  useEffect(() => {
    if (slideshowPlaying) {
      setSidebarOpen(false)
      setShowMetadata(false)
    }
  }, [slideshowPlaying])

  // Preload next page when approaching end of loaded items
  useEffect(() => {
    if (hasMore && onLoadMore && currentIndex >= attachments.length - 5) {
      onLoadMore()
    }
  }, [currentIndex, attachments.length, hasMore, onLoadMore])

  // Slideshow: advance to next item (respects shuffle order)
  const slideshowAdvance = useCallback(() => {
    if (shuffleEnabled && shuffleOrder.length > 0) {
      const nextPos = shufflePosition + 1
      if (nextPos < shuffleOrder.length) {
        setShufflePosition(nextPos)
        onNavigate(shuffleOrder[nextPos])
      } else {
        if (hasMore && onLoadMore) {
          onLoadMore()
        } else {
          setSlideshowPlaying(false)
        }
      }
    } else {
      if (currentIndex < attachments.length - 1) {
        onNavigate(currentIndex + 1)
      } else if (hasMore && onLoadMore) {
        onLoadMore()
      } else {
        setSlideshowPlaying(false)
      }
    }
  }, [shuffleEnabled, shuffleOrder, shufflePosition, currentIndex, attachments.length, onNavigate, hasMore, onLoadMore])

  // Slideshow timer logic for images — wait for load, then start countdown
  useEffect(() => {
    if (slideshowTimerRef.current) {
      clearTimeout(slideshowTimerRef.current)
      slideshowTimerRef.current = null
    }

    if (slideshowPlaying && !isCurrentVideo && !imageLoading) {
      slideshowTimerRef.current = setTimeout(() => {
        slideshowAdvance()
      }, slideshowInterval)
    }

    return () => {
      if (slideshowTimerRef.current) {
        clearTimeout(slideshowTimerRef.current)
        slideshowTimerRef.current = null
      }
    }
  }, [slideshowPlaying, isCurrentVideo, imageLoading, slideshowInterval, slideshowAdvance])

  // Slideshow: handle video ended event to advance
  useEffect(() => {
    if (!slideshowPlaying || !isCurrentVideo) return

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

    const handleEnded = () => {
      slideshowAdvance()
    }

    video.addEventListener('ended', handleEnded)
    return () => video.removeEventListener('ended', handleEnded)
  }, [slideshowPlaying, isCurrentVideo, slideshowAdvance])

  // Auto-hide sidebar for videos
  useEffect(() => {
    if (isCurrentVideo) {
      setSidebarOpen(false)
    }
  }, [isCurrentVideo])

  // Shuffle-aware prev/next navigation
  const canGoPrev = shuffleEnabled ? shufflePosition > 0 : currentIndex > 0
  const canGoNext = shuffleEnabled
    ? shufflePosition < shuffleOrder.length - 1 || !!hasMore
    : currentIndex < attachments.length - 1 || !!hasMore

  const navigatePrev = useCallback(() => {
    if (shuffleEnabled && shuffleOrder.length > 0) {
      if (shufflePosition > 0) {
        const prevPos = shufflePosition - 1
        setShufflePosition(prevPos)
        onNavigate(shuffleOrder[prevPos])
      }
    } else {
      if (currentIndex > 0) onNavigate(currentIndex - 1)
    }
  }, [shuffleEnabled, shuffleOrder, shufflePosition, currentIndex, onNavigate])

  const navigateNext = useCallback(() => {
    if (shuffleEnabled && shuffleOrder.length > 0) {
      const nextPos = shufflePosition + 1
      if (nextPos < shuffleOrder.length) {
        setShufflePosition(nextPos)
        onNavigate(shuffleOrder[nextPos])
      }
    } else {
      if (currentIndex < attachments.length - 1) onNavigate(currentIndex + 1)
    }
  }, [shuffleEnabled, shuffleOrder, shufflePosition, currentIndex, attachments.length, onNavigate])

  // Keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return

      switch (e.key) {
        case ' ':
          e.preventDefault()
          setSlideshowPlaying(p => !p)
          break
        case 'ArrowLeft':
          e.preventDefault()
          navigatePrev()
          break
        case 'ArrowRight':
          e.preventDefault()
          navigateNext()
          break
        case 'Escape':
          e.preventDefault()
          if (slideshowPlaying) {
            setSlideshowPlaying(false)
          } else {
            handleClose()
          }
          break
        case '+':
        case '=':
          e.preventDefault()
          if (!isCurrentVideo) { setZoom(z => Math.min(z + 0.5, maxZoom)); showZoomControls() }
          break
        case '-':
        case '_':
          e.preventDefault()
          if (!isCurrentVideo) { setZoom(z => Math.max(z - 0.5, 1)); showZoomControls() }
          break
        case '0':
          e.preventDefault()
          setZoom(1)
          setPan({ x: 0, y: 0 })
          showZoomControls()
          break
        case 'i':
        case 'I':
          e.preventDefault()
          setShowMetadata(s => !s)
          break
        case 'Delete':
        case 'Backspace':
          e.preventDefault()
          if (onDelete) onDelete(attachments[currentIndex])
          break
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [navigatePrev, navigateNext, handleClose, isCurrentVideo, maxZoom, slideshowPlaying, showZoomControls, onDelete, attachments, currentIndex])

  // Reset zoom/pan when changing items
  useEffect(() => {
    setZoom(1)
    setPan({ x: 0, y: 0 })
    setImageError(false)
    setNaturalSize(null)
    setDisplayedSize(null)
    setMenuOpen(false)
    setVideoAspectRatio(null)
    // Only set loading=true if the image hasn't already loaded (e.g. from cache).
    // onLoad sets loadedUrlRef before this effect runs, so check it.
    const url = currentItem ? getPreviewUrl(currentItem) : null
    if (loadedUrlRef.current !== url) {
      setImageLoading(true)
    }
  }, [currentIndex])

  // Mouse wheel zoom
  const handleWheel = useCallback((e: WheelEvent) => {
    if (isCurrentVideo) return
    if (e.ctrlKey || e.metaKey) {
      e.preventDefault()
      const delta = e.deltaY > 0 ? -0.2 : 0.2
      setZoom(z => Math.max(1, Math.min(maxZoom, z + delta)))
      showZoomControls()
    }
  }, [maxZoom, isCurrentVideo, showZoomControls])

  useEffect(() => {
    const container = containerRef.current
    if (container) {
      container.addEventListener('wheel', handleWheel, { passive: false })
      return () => container.removeEventListener('wheel', handleWheel)
    }
  }, [handleWheel])

  // Pan handling for images
  const handleMouseDown = (e: React.MouseEvent) => {
    if (zoom > 1 && !isCurrentVideo) {
      setIsPanning(true)
      setPanStart({ x: e.clientX - pan.x, y: e.clientY - pan.y })
    }
  }

  const handleMouseMove = (e: React.MouseEvent) => {
    showZoomControls()
    if (isPanning) {
      setPan({
        x: e.clientX - panStart.x,
        y: e.clientY - panStart.y,
      })
    }
  }

  const handleMouseUp = () => {
    setIsPanning(false)
  }

  // Gesture refs for touch support
  const gestureZoomRef = useRef(zoom)
  const gesturePanRef = useRef(pan)

  useEffect(() => {
    gestureZoomRef.current = zoom
    gesturePanRef.current = pan
  }, [zoom, pan])

  // Track swipe state for navigation
  const swipeStartRef = useRef<{ x: number; y: number; time: number } | null>(null)

  // Touch gesture handling for images (pinch zoom, drag pan)
  useGesture(
    {
      onPinch: ({ offset: [scale], last }) => {
        if (isCurrentVideo) return
        const newZoom = Math.max(1, Math.min(maxZoom, scale))
        gestureZoomRef.current = newZoom

        if (imageRef.current) {
          const p = gesturePanRef.current
          imageRef.current.style.transform = `scale3d(${newZoom}, ${newZoom}, 1) translate3d(${p.x / newZoom}px, ${p.y / newZoom}px, 0)`
        }

        if (last) setZoom(newZoom)
      },
      onDrag: ({ offset: [x, y], pinching, last }) => {
        if (isCurrentVideo || pinching) return
        const currentZoom = gestureZoomRef.current
        if (currentZoom <= 1) return

        gesturePanRef.current = { x, y }

        if (imageRef.current) {
          imageRef.current.style.transform = `scale3d(${currentZoom}, ${currentZoom}, 1) translate3d(${x / currentZoom}px, ${y / currentZoom}px, 0)`
        }

        if (last) setPan({ x, y })
      },
    },
    {
      target: imageRef,
      eventOptions: { passive: false },
      pinch: { scaleBounds: { min: 1, max: maxZoom }, rubberband: true },
      drag: { from: () => [gesturePanRef.current.x, gesturePanRef.current.y] },
    }
  )

  // Swipe navigation for mobile (works for both images and videos)
  const handleTouchStart = useCallback((e: React.TouchEvent) => {
    showZoomControls()
    // Don't track swipes that start on interactive elements
    const target = e.target as HTMLElement
    if (target.closest('button, a, video, input, textarea')) {
      swipeStartRef.current = null
      return
    }

    if (e.touches.length === 1) {
      swipeStartRef.current = {
        x: e.touches[0].clientX,
        y: e.touches[0].clientY,
        time: Date.now(),
      }
    }
  }, [showZoomControls])

  const handleTouchEnd = useCallback((e: React.TouchEvent) => {
    if (!swipeStartRef.current || e.changedTouches.length !== 1) return

    const start = swipeStartRef.current
    const end = {
      x: e.changedTouches[0].clientX,
      y: e.changedTouches[0].clientY,
    }

    const deltaX = end.x - start.x
    const deltaY = end.y - start.y
    const deltaTime = Date.now() - start.time

    // Must be a quick swipe (< 300ms) with significant horizontal movement
    const minSwipeDistance = 50
    const maxVerticalDeviation = 100

    if (deltaTime < 300 && Math.abs(deltaX) > minSwipeDistance && Math.abs(deltaY) < maxVerticalDeviation) {
      // Only navigate if not zoomed in (for images)
      if (!isCurrentVideo && zoom > 1) {
        swipeStartRef.current = null
        return
      }

      if (deltaX > 0) {
        // Swipe right = previous
        navigatePrev()
      } else if (deltaX < 0) {
        // Swipe left = next
        navigateNext()
      }
    }
    // Note: Don't toggle controls on tap here - let click events handle buttons naturally

    swipeStartRef.current = null
  }, [navigatePrev, navigateNext, isCurrentVideo, zoom])

  // URL helpers
  const getPreviewUrl = (item: PaidContentAttachment) =>
    item.local_path ? (item.file_token ? `/api/paid-content/files/serve?t=${encodeURIComponent(item.file_token)}` : `/api/paid-content/files/serve?path=${encodeURIComponent(item.local_path)}`) : ''

  const getThumbnailUrl = (item: PaidContentAttachment) =>
    item.id ? `/api/paid-content/files/thumbnail/${item.id}?size=medium&${item.file_hash ? `v=${item.file_hash.slice(0, 8)}` : THUMB_CACHE_V}` : getPreviewUrl(item)

  const isNativePosterPlatform = ['onlyfans', 'fansly', 'youtube'].includes(post.platform?.toLowerCase() || '')

  const getVideoPosterUrl = (item: PaidContentAttachment) =>
    item.id
      ? `/api/paid-content/files/thumbnail/${item.id}?size=${isNativePosterPlatform ? 'native' : 'medium'}&${THUMB_CACHE_V}`
      : getPreviewUrl(item)

  // Actions
  const handleDownload = async () => {
    try {
      const url = getPreviewUrl(currentItem)
      const filename = currentItem.name || currentItem.local_filename || `file_${currentItem.id}`
      const response = await fetch(url)
      const blob = await response.blob()
      const downloadUrl = window.URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = downloadUrl
      a.download = filename
      document.body.appendChild(a)
      a.click()
      document.body.removeChild(a)
      window.URL.revokeObjectURL(downloadUrl)
      notificationManager.success('Downloaded', filename)
      setMenuOpen(false)
    } catch {
      notificationManager.error('Download Failed', 'Could not download file')
    }
  }

  const handleCopyPath = () => {
    navigator.clipboard.writeText(currentItem.local_path || '')
    notificationManager.success('Copied', 'Path copied to clipboard')
    setMenuOpen(false)
  }

  const handlePiP = async () => {
    const video = videoRef.current
    if (!video) return
    setMenuOpen(false)
    try {
      // Standard API
      if (document.pictureInPictureEnabled && video.requestPictureInPicture) {
        await video.requestPictureInPicture()
        return
      }
      // Safari/iOS fallback
      if ((video as any).webkitSupportsPresentationMode?.('picture-in-picture')) {
        ;(video as any).webkitSetPresentationMode('picture-in-picture')
        return
      }
      notificationManager.error('PiP unavailable', 'Picture-in-Picture is not supported on this device')
    } catch {
      notificationManager.error('PiP failed', 'Could not enter Picture-in-Picture mode')
    }
  }

  // Scroll thumbnail into view
  useEffect(() => {
    if (thumbnailStripRef.current) {
      const thumb = thumbnailStripRef.current.children[currentIndex] as HTMLElement
      if (thumb) {
        thumb.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
      }
    }
  }, [currentIndex])

  return (
    <div
      ref={containerRef}
      className="fixed inset-0 z-[60] bg-black flex"
      style={isLandscape ? { height: '100dvh', width: '100vw' } : undefined}
      onMouseMove={handleMouseMove}
      onMouseUp={handleMouseUp}
      onMouseLeave={handleMouseUp}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
    >
      {/* ===== BUNDLE SIDEBAR (Images only, hidden on mobile) ===== */}
      {!isCurrentVideo && !isMobile && sidebarOpen && attachments.length > 1 && (
        <div className="w-24 bg-black flex flex-col flex-shrink-0 border-r border-white/10 pt-8 pl-3 relative z-20">
          {/* Sidebar Header */}
          <div className="p-2 flex items-center justify-between">
            <span className="text-white text-xs font-medium">Bundle</span>
            <button
              onClick={() => setSidebarOpen(false)}
              className="p-1 hover:bg-white/10 rounded text-white/60 hover:text-white transition-colors"
              title="Collapse"
            >
              <ChevronLeft className="w-4 h-4" />
            </button>
          </div>

          {/* Thumbnail Strip */}
          <div ref={thumbnailStripRef} className="flex-1 overflow-y-auto space-y-3 px-1 py-1">
            {attachments.map((att, idx) => {
              const isVideo = att.file_type === 'video' && !isPreviewFrame(att)
              const isCurrent = idx === currentIndex
              return (
                <button
                  key={att.id}
                  onClick={() => onNavigate(idx)}
                  className={`relative w-full aspect-square rounded overflow-hidden transition-all ${
                    isCurrent
                      ? 'ring-2 ring-white ring-offset-2 ring-offset-black'
                      : 'opacity-40 hover:opacity-80'
                  }`}
                >
                  <img
                    src={getThumbnailUrl(att)}
                    alt=""
                    className="w-full h-full object-cover"
                    loading="lazy"
                  />
                  {isVideo && (
                    <div className="absolute inset-0 flex items-center justify-center bg-black/40">
                      <Video className="w-4 h-4 text-white" />
                    </div>
                  )}
                  {isPreviewFrame(att) && (
                    <div className="absolute inset-0 flex items-center justify-center bg-black/30">
                      <Lock className="w-4 h-4 text-white/80" />
                    </div>
                  )}
                </button>
              )
            })}
          </div>
        </div>
      )}
      {/* Bundle sidebar expand button (when sidebar is closed, desktop images only) */}
      {!isCurrentVideo && !isMobile && !sidebarOpen && attachments.length > 1 && (
        <button
          onClick={() => setSidebarOpen(true)}
          className="absolute top-10 left-2 z-20 p-1.5 bg-black/50 hover:bg-black/70 rounded-lg text-white/60 hover:text-white transition-colors"
          title="Show Bundle"
        >
          <ChevronRight className="w-4 h-4" />
        </button>
      )}

      {/* ===== MAIN CONTENT AREA ===== */}
      <div className="flex-1 flex flex-col relative" style={isLandscape ? { height: '100dvh' } : undefined}>
        {/* Top Left: Slideshow Controls */}
        <div
          className={`absolute z-20 flex items-center gap-2 transition-opacity duration-200 ${
            isMobile ? `top-0 ${attachments.length > 1 ? 'left-12' : 'left-4'}` : isLandscape ? 'top-2 left-3' : `top-10 ${sidebarOpen ? 'left-6' : 'left-[7.5rem]'}`
          }`}
          style={isMobile ? { paddingTop: 'env(safe-area-inset-top, 0px)' } : undefined}
        >
          {(totalCount || attachments.length) > 1 && (
            <button
              onClick={() => setSlideshowPlaying(p => !p)}
              className="p-2 bg-black/50 hover:bg-black/70 rounded-lg text-white transition-colors"
              title={slideshowPlaying ? 'Pause Slideshow (Space)' : 'Play Slideshow (Space)'}
            >
              {slideshowPlaying ? (
                <Pause className="w-5 h-5" />
              ) : (
                <Play className="w-5 h-5" />
              )}
            </button>
          )}
          {slideshowPlaying && (totalCount || attachments.length) > 1 && (
            <button
              onClick={toggleShuffle}
              className={`p-2 bg-black/50 hover:bg-black/70 rounded-lg transition-colors ${
                (onShuffleChange ? isShuffled : shuffleEnabled) ? 'text-cyan-400' : 'text-white'
              }`}
              title={(onShuffleChange ? isShuffled : shuffleEnabled) ? 'Disable Shuffle' : 'Enable Shuffle'}
            >
              <Shuffle className="w-5 h-5" />
            </button>
          )}
          {slideshowPlaying && (totalCount || attachments.length) > 1 && (
            <div className="flex items-center gap-1 bg-black/50 rounded-lg p-1">
              {[3000, 5000, 8000, 10000].map(ms => (
                <button
                  key={ms}
                  onClick={() => setSlideshowInterval(ms)}
                  className={`px-2 py-1 rounded text-xs transition-colors ${
                    slideshowInterval === ms
                      ? 'bg-white/30 text-white font-medium'
                      : 'text-white/60 hover:text-white hover:bg-white/10'
                  }`}
                >
                  {ms / 1000}s
                </button>
              ))}
            </div>
          )}
          {/* Position indicator on desktop */}
          {!isMobile && attachments.length > 1 && (
            <span className="text-white/60 text-sm ml-1">
              {(onShuffleChange ? isShuffled : shuffleEnabled)
                ? `${onShuffleChange ? currentIndex + 1 : shufflePosition + 1} / ${totalCount || attachments.length} (shuffled)`
                : `${currentIndex + 1} / ${totalCount || attachments.length}`
              }
              {!totalCount && hasMore && '+'}
            </span>
          )}
        </div>

        {/* Top Right: Info, Menu and Close */}
        <div
          className={`absolute z-20 flex items-center gap-2 transition-opacity duration-200 ${
            isMobile ? 'top-0 right-4 safe-area-inset-top' : isLandscape ? 'top-2 right-3' : 'top-10 right-6'
          } ${isMobile && !showControls ? 'opacity-0 pointer-events-none' : 'opacity-100'}`}
          style={isMobile ? { paddingTop: 'env(safe-area-inset-top, 0px)' } : undefined}
        >
          {/* Delete button - visible icon for quick access */}
          {onDelete && (
            <button
              onClick={() => onDelete(currentItem)}
              className={`p-2 hover:bg-red-500/30 rounded-lg transition-colors drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)] ${
                isMobile || isLandscape ? 'text-red-400/70' : 'text-transparent hover:text-red-400'
              }`}
              title="Delete (Del)"
            >
              <Trash2 className="w-7 h-7 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]" />
            </button>
          )}
          {/* Info toggle button - hidden until hover on desktop, always visible on mobile when controls shown */}
          <button
            onClick={() => setShowMetadata(!showMetadata)}
            className={`p-2 md:p-2 hover:bg-white/10 rounded-lg transition-colors drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)] ${
              showMetadata ? 'text-cyan-400' : isMobile || isLandscape ? 'text-white/70' : 'text-transparent hover:text-white'
            }`}
            title="Toggle Details (I)"
          >
            <Info className="w-7 h-7 md:w-7 md:h-7 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]" />
          </button>
          <div className="relative">
            <button
              onClick={() => setMenuOpen(!menuOpen)}
              className="p-2 hover:bg-white/10 rounded-lg text-white transition-colors drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)]"
            >
              <MoreHorizontal className="w-7 h-7 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]" />
            </button>
            {menuOpen && (
              <div className="absolute top-full right-0 mt-1 w-44 bg-zinc-900 border border-white/10 rounded-lg shadow-xl overflow-hidden">
                <button
                  onClick={handleDownload}
                  className="w-full px-4 py-2.5 text-left text-white text-sm hover:bg-white/10 flex items-center gap-3"
                >
                  <Download className="w-4 h-4" />
                  Download
                </button>
                <button
                  onClick={handleCopyPath}
                  className="w-full px-4 py-2.5 text-left text-white text-sm hover:bg-white/10 flex items-center gap-3"
                >
                  <Copy className="w-4 h-4" />
                  Copy path
                </button>
                <button
                  onClick={handleToggleWatchLater}
                  className="w-full px-4 py-2.5 text-left text-white text-sm hover:bg-white/10 flex items-center gap-3"
                >
                  <Clock className="w-4 h-4" />
                  {isCurrentInWatchLater ? 'Remove from Watch Later' : 'Add to Watch Later'}
                </button>
                {isCurrentVideo && isMobile && (
                  <>
                    <div className="border-t border-white/10" />
                    <button
                      onClick={handlePiP}
                      className="w-full px-4 py-2.5 text-left text-white text-sm hover:bg-white/10 flex items-center gap-3"
                    >
                      <PictureInPicture2 className="w-4 h-4" />
                      Picture-in-Picture
                    </button>
                  </>
                )}
                {onDelete && (
                  <button
                    onClick={() => { onDelete(currentItem); setMenuOpen(false) }}
                    className="w-full px-4 py-2.5 text-left text-red-400 text-sm hover:bg-white/10 flex items-center gap-3"
                  >
                    <Trash2 className="w-4 h-4" />
                    Delete
                  </button>
                )}
              </div>
            )}
          </div>
          {/* Heart - in top controls for landscape */}
          {isLandscape && onToggleFavorite && (
            <button
              onClick={onToggleFavorite}
              className="p-2 text-white/70 hover:text-red-400 transition-colors drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)]"
              title={post.is_favorited ? 'Remove from favorites' : 'Add to favorites'}
            >
              <Heart className={`w-7 h-7 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)] ${post.is_favorited ? 'fill-red-500 text-red-500' : ''}`} />
            </button>
          )}
          {/* Close button - always visible on mobile, hidden until hover on desktop */}
          <button
            onClick={handleClose}
            className={`p-2 hover:bg-white/10 rounded-lg transition-colors drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)] ${
              isMobile || isLandscape ? 'text-white/70' : 'text-transparent hover:text-white'
            }`}
          >
            <X className="w-7 h-7 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]" />
          </button>
        </div>

        {/* Right Side Action: Favorite Heart - desktop only (mobile has it in bottom bar) */}
        {onToggleFavorite && (
          <div className={`${isMobile || isLandscape ? 'hidden' : 'block'} absolute right-4 top-[60%] z-20`}>
            <button
              onClick={onToggleFavorite}
              className="p-2 text-white hover:text-red-400 transition-colors drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)]"
              title={post.is_favorited ? 'Remove from favorites' : 'Add to favorites'}
            >
              <Heart className={`w-7 h-7 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)] ${post.is_favorited ? 'fill-red-500 text-red-500' : ''}`} />
            </button>
          </div>
        )}

        {/* Mobile position indicator */}
        {isMobile && attachments.length > 1 && (
          <div
            className={`absolute top-12 left-1/2 -translate-x-1/2 z-10 px-3 py-1 bg-black/50 rounded-full text-white text-sm transition-opacity duration-200 ${
              showControls ? 'opacity-100' : 'opacity-0'
            }`}
            style={{ paddingTop: 'env(safe-area-inset-top, 0px)' }}
          >
            {(onShuffleChange ? isShuffled : shuffleEnabled) ? (onShuffleChange ? currentIndex + 1 : shufflePosition + 1) : currentIndex + 1} / {totalCount || attachments.length}{!totalCount && hasMore && '+'}
          </div>
        )}

        {/* Navigation Arrow - Previous */}
        {canGoPrev && (
          <button
            onClick={navigatePrev}
            className={`absolute top-1/2 -translate-y-1/2 z-20 transition-colors drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)] ${
              isMobile
                ? 'left-2 p-3 bg-black/40 rounded-full text-white/80 active:bg-white/20'
                : isLandscape
                  ? 'left-1 p-3 bg-black/40 rounded-full text-white/80 active:bg-white/20'
                  : 'left-0 px-6 py-16 hover:bg-white/5 rounded-r-2xl text-transparent hover:text-white'
            }`}
          >
            <ChevronLeft className={`${isMobile ? 'w-8 h-8' : isLandscape ? 'w-7 h-7' : 'w-6 h-6'} drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]`} />
          </button>
        )}

        {/* Navigation Arrow - Next */}
        {canGoNext && (
          <button
            onClick={navigateNext}
            className={`absolute top-1/2 -translate-y-1/2 z-20 transition-colors drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)] ${
              isMobile
                ? 'right-2 p-3 bg-black/40 rounded-full text-white/80 active:bg-white/20'
                : isLandscape
                  ? 'right-1 p-3 bg-black/40 rounded-full text-white/80 active:bg-white/20'
                  : 'right-0 px-6 py-16 hover:bg-white/5 rounded-l-2xl text-transparent hover:text-white'
            }`}
          >
            <ChevronRight className={`${isMobile ? 'w-8 h-8' : isLandscape ? 'w-7 h-7' : 'w-6 h-6'} drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]`} />
          </button>
        )}

        {/* Floating Zoom Controls Pill */}
        {!isCurrentVideo && (
          <div
            className={`absolute ${isMobile ? 'bottom-24' : 'bottom-8'} left-1/2 -translate-x-1/2 z-30
              flex items-center gap-1 px-2 py-1.5 bg-black/70 backdrop-blur-sm rounded-full
              transition-opacity duration-300
              ${zoomControlsVisible ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
            onMouseEnter={() => {
              if (zoomControlsTimerRef.current) clearTimeout(zoomControlsTimerRef.current)
              setZoomControlsVisible(true)
            }}
            onMouseLeave={() => {
              zoomControlsTimerRef.current = setTimeout(() => setZoomControlsVisible(false), 2500)
            }}
          >
            <button onClick={() => { setZoom(z => Math.max(1, z - 0.5)); showZoomControls() }}
              disabled={zoom <= 1}
              className="p-1.5 text-white/80 hover:text-white disabled:text-white/30" title="Zoom out (-)">
              <ZoomOut className="w-4 h-4" />
            </button>
            <span className="text-white/90 text-xs font-mono min-w-[3rem] text-center select-none">
              {naturalSize && displayedSize
                ? `${Math.round((displayedSize.width / naturalSize.width) * zoom * 100)}%`
                : `${Math.round(zoom * 100)}%`}
            </span>
            <button onClick={() => { setZoom(z => Math.min(maxZoom, z + 0.5)); showZoomControls() }}
              disabled={zoom >= maxZoom}
              className="p-1.5 text-white/80 hover:text-white disabled:text-white/30" title="Zoom in (+)">
              <ZoomIn className="w-4 h-4" />
            </button>
            {naturalSize && displayedSize && (
              <button
                onClick={() => { setZoom(naturalSize.width / displayedSize.width); showZoomControls() }}
                disabled={Math.abs(zoom - naturalSize.width / displayedSize.width) < 0.01}
                className="px-1.5 py-0.5 text-white/80 hover:text-white disabled:text-white/30 text-xs font-medium"
                title="Actual size (1)">
                100%
              </button>
            )}
            <button onClick={() => { setZoom(1); setPan({ x: 0, y: 0 }); showZoomControls() }}
              disabled={zoom === 1 && pan.x === 0 && pan.y === 0}
              className="p-1.5 text-white/80 hover:text-white disabled:text-white/30" title="Reset view (0)">
              <RotateCcw className="w-4 h-4" />
            </button>
          </div>
        )}

        {/* Media Display Area */}
        <div
          className={`flex-1 flex items-center justify-center ${isCurrentVideo ? '' : isMobile ? 'px-2 pb-16 pt-2' : isLandscape ? 'px-2 pb-2 pt-1' : 'px-16 pb-20 pt-4'}`}
          onClick={() => menuOpen && setMenuOpen(false)}
        >
          {isCurrentVideo ? (
            /* ===== FULLSCREEN VIDEO PLAYER ===== */
            <div className={`fixed z-10 inset-0 flex ${isMobile ? 'items-center pb-[72px]' : videoAspectRatio && videoAspectRatio > 1 ? 'items-center pt-[30px]' : 'items-start'} justify-center bg-black`}>
              {/* Blurred background for mobile (all videos) and portrait videos on desktop */}
              <div
                className="absolute inset-0 scale-150"
                style={{
                  backgroundImage: `url(${getThumbnailUrl(currentItem)})`,
                  backgroundSize: 'cover',
                  backgroundPosition: 'center',
                  filter: 'blur(30px) brightness(0.75)',
                }}
              />
              <video
                ref={videoRef}
                key={currentItem.id}
                poster={getVideoPosterUrl(currentItem)}
                className={`object-contain relative z-10 ${
                  // Mobile: fill width for all videos (controls follow video)
                  isMobile ? 'w-full' :
                  // Landscape phone: size to fit viewport using max dimensions
                  isLandscape ? 'max-w-full max-h-full' :
                  // Desktop portrait/square: fill height, constrain width
                  videoAspectRatio && videoAspectRatio <= 1 ? 'h-full' :
                  // Desktop landscape: fill width, constrain to container
                  'w-full max-h-full'
                }`}
                style={isMobile && videoAspectRatio
                  ? { aspectRatio: videoAspectRatio }
                  : isLandscape && videoAspectRatio
                    ? { aspectRatio: videoAspectRatio, height: '100%' }
                    : videoAspectRatio && videoAspectRatio <= 1
                      ? { aspectRatio: videoAspectRatio }
                      : undefined
                }
                // @ts-ignore - Safari attributes
                x-webkit-airplay="allow"
                airplay="allow"
                controls
                autoPlay={isMobile || wasPlaying || slideshowPlaying || autoPlayVideo}
                muted={isMobile}
                playsInline
                preload="auto"
                disablePictureInPicture={false}
                onLoadStart={() => setImageLoading(true)}
                onLoadedData={(e) => {
                  setImageLoading(false)
                  const video = e.currentTarget
                  // Set start time if provided
                  if (typeof startTime === 'number' && startTime > 0) {
                    if (video.duration && startTime < video.duration) {
                      video.currentTime = startTime
                    }
                  }
                  // Autoplay on mobile: start muted for autoplay policy, then unmute
                  if ((isMobile || wasPlaying || slideshowPlaying || autoPlayVideo) && video.paused) {
                    video.play().then(() => {
                      if (isMobile && video.muted) {
                        video.muted = false
                      }
                    }).catch(() => {})
                  } else if (isMobile && !video.paused && video.muted) {
                    video.muted = false
                  }
                  // Detect video aspect ratio for portrait videos
                  if (video.videoWidth && video.videoHeight) {
                    setVideoAspectRatio(video.videoWidth / video.videoHeight)
                  }
                }}
                onCanPlay={() => setImageLoading(false)}
              />
            </div>
          ) : (
            /* ===== FULLSCREEN IMAGE DISPLAY ===== */
            <div
              className="fixed inset-0 flex items-center justify-center bg-black z-10"
              onMouseDown={handleMouseDown}
              style={{
                cursor: zoom > 1 ? 'grab' : 'default',
              }}
            >
              {imageLoading && (
                <div className="absolute inset-0 flex items-center justify-center">
                  <div className="w-10 h-10 border-4 border-white/20 border-t-white rounded-full animate-spin" />
                </div>
              )}
              {imageError ? (
                <div className="text-white text-center p-8">
                  <p className="mb-4">Failed to load image</p>
                  <button
                    onClick={() => { setImageError(false); loadedUrlRef.current = null; setImageLoading(true) }}
                    className="px-4 py-2 bg-white/20 hover:bg-white/30 rounded-lg transition-colors"
                  >
                    Retry
                  </button>
                </div>
              ) : (
                <img
                  ref={imageRef}
                  key={getPreviewUrl(currentItem)}
                  src={getPreviewUrl(currentItem)}
                  alt={currentItem.name || ''}
                  className="w-full h-full object-contain select-none"
                  style={{
                    transform: `scale3d(${zoom}, ${zoom}, 1) translate3d(${pan.x / zoom}px, ${pan.y / zoom}px, 0)`,
                    transformOrigin: 'center',
                    opacity: imageLoading ? 0 : 1,
                    transition: 'opacity 0.2s',
                    touchAction: 'none',
                  }}
                  onLoad={(e) => {
                    loadedUrlRef.current = getPreviewUrl(currentItem)
                    setImageLoading(false)
                    const img = e.target as HTMLImageElement
                    setNaturalSize({ width: img.naturalWidth, height: img.naturalHeight })
                    // Calculate actual rendered size accounting for object-contain
                    // clientWidth/clientHeight report the CSS box, not the visible image
                    const containerAspect = img.clientWidth / img.clientHeight
                    const imageAspect = img.naturalWidth / img.naturalHeight
                    if (imageAspect > containerAspect) {
                      // Image is wider — width fills container, height is letterboxed
                      setDisplayedSize({ width: img.clientWidth, height: img.clientWidth / imageAspect })
                    } else {
                      // Image is taller — height fills container, width is pillarboxed
                      setDisplayedSize({ width: img.clientHeight * imageAspect, height: img.clientHeight })
                    }
                  }}
                  onError={() => { setImageLoading(false); setImageError(true) }}
                  draggable={false}
                />
              )}
            </div>
          )}
        </div>

        {/* ===== METADATA PANEL ===== */}
        <div
          className={`absolute transition-all duration-300 ease-in-out z-30 ${
            isMobile
              ? `inset-x-0 bottom-0 top-[62px] ${showMetadata ? 'opacity-100' : 'opacity-0 pointer-events-none'}`
              : `right-6 bottom-16 w-80 ${showMetadata ? 'translate-x-0 opacity-100' : 'translate-x-[110%] opacity-0 pointer-events-none'}`
          }`}
          style={isMobile ? { paddingTop: 'env(safe-area-inset-top, 0px)' } : { top: '5.5rem' }}
          onClick={(e) => e.stopPropagation()}
        >
          <div className={`h-full bg-gradient-to-br from-gray-900/95 to-black/95 backdrop-blur-xl overflow-hidden ${
            isMobile ? 'rounded-t-2xl' : 'rounded-2xl border border-white/30 shadow-[0_20px_60px_rgba(0,0,0,0.8)]'
          }`}>
            <div className="p-6 h-full overflow-y-auto">
              <div className="flex items-center justify-between mb-6 pb-4 border-b border-white/20">
                <h3 className="text-white font-semibold text-lg">Details</h3>
                {isMobile && (
                  <button
                    onClick={() => setShowMetadata(false)}
                    className="p-2 hover:bg-white/10 rounded-lg text-white/70"
                  >
                    <X className="w-5 h-5" />
                  </button>
                )}
              </div>

              <div className="space-y-3 text-sm">
                {/* Post Content */}
                {post.content && (
                  <div>
                    <div className="text-white/60 mb-1">Post Content</div>
                    <div className="text-white text-xs max-h-32 overflow-y-auto whitespace-pre-wrap">
                      {decodeHtmlEntities(post.content)}
                    </div>
                  </div>
                )}

                {post.content && <div className="border-t border-white/10 pt-3 mt-3" />}

                {/* Filename */}
                <div>
                  <div className="text-white/60 mb-1 flex items-center gap-2">
                    <ImageIcon className="w-4 h-4" />
                    Filename
                  </div>
                  <div className="text-white break-all">
                    {currentItem.local_filename || currentItem.name || `Attachment ${currentItem.id}`}
                  </div>
                </div>

                {/* Resolution */}
                {(currentItem.width && currentItem.height) || naturalSize ? (
                  <div>
                    <div className="text-white/60 mb-1 flex items-center gap-2">
                      <ImageIcon className="w-4 h-4" />
                      Resolution
                    </div>
                    <div className="text-white">
                      {currentItem.width && currentItem.height
                        ? `${currentItem.width} x ${currentItem.height}`
                        : naturalSize
                          ? `${naturalSize.width} x ${naturalSize.height}`
                          : 'Loading...'}
                    </div>
                  </div>
                ) : null}

                {/* File Size */}
                {currentItem.file_size && currentItem.file_size > 0 && (
                  <div>
                    <div className="text-white/60 mb-1 flex items-center gap-2">
                      <HardDrive className="w-4 h-4" />
                      Size
                    </div>
                    <div className="text-white">{formatBytes(currentItem.file_size)}</div>
                  </div>
                )}

                {/* Duration (for videos) */}
                {isCurrentVideo && currentItem.duration && currentItem.duration > 0 && (
                  <div>
                    <div className="text-white/60 mb-1 flex items-center gap-2">
                      <Clock className="w-4 h-4" />
                      Duration
                    </div>
                    <div className="text-white">{formatDuration(currentItem.duration)}</div>
                  </div>
                )}

                {/* Post Date */}
                {post.published_at && (
                  <div>
                    <div className="text-white/60 mb-1 flex items-center gap-2">
                      <Calendar className="w-4 h-4" />
                      Post Date
                    </div>
                    <div className="text-white">{formatDate(post.published_at)}</div>
                  </div>
                )}

                {/* Download Date */}
                <div>
                  <div className="text-white/60 mb-1 flex items-center gap-2">
                    <Calendar className="w-4 h-4" />
                    Download Date
                  </div>
                  <div className="text-white">
                    {formatDate(currentItem.downloaded_at || post.download_date || post.added_at)}
                  </div>
                </div>

                {/* Platform */}
                {post.platform && (
                  <div>
                    <div className="text-white/60 mb-1">Platform</div>
                    <div className="text-white capitalize">{post.platform}</div>
                  </div>
                )}

                {/* Post ID */}
                {post.post_id && (
                  <div>
                    <div className="text-white/60 mb-1">Post ID</div>
                    <div className="text-white font-mono">{post.post_id}</div>
                  </div>
                )}

                {/* Source/Creator */}
                {post.username && (
                  <div>
                    <div className="text-white/60 mb-1">Source</div>
                    <div className="text-white">@{post.username}</div>
                  </div>
                )}

                {/* Path */}
                {currentItem.local_path && (
                  <div>
                    <div className="text-white/60 mb-1">Path</div>
                    <div className="text-white text-xs break-all font-mono">
                      {currentItem.local_path}
                    </div>
                  </div>
                )}
              </div>
            </div>
          </div>
        </div>

        {/* ===== MOBILE BUNDLE SIDEBAR (Fansly-style) ===== */}
        {isMobile && attachments.length > 1 && (
          <div
            className="fixed left-0 z-20 bg-black/80 backdrop-blur-sm rounded-r-lg transition-all duration-200"
            style={{ top: 'env(safe-area-inset-top, 0px)' }}
          >
            {/* Bundle Header */}
            <button
              onClick={(e) => { e.stopPropagation(); setSidebarOpen(!sidebarOpen) }}
              className="px-2 py-2 flex items-center gap-1 hover:bg-white/10 w-full"
            >
              <span className="text-white text-xs font-medium">{sidebarOpen ? 'Bundle' : ''}</span>
              <ChevronLeft className={`w-4 h-4 text-white transition-transform ${sidebarOpen ? '' : 'rotate-180'}`} />
            </button>

            {/* Thumbnail Strip - vertical, collapsible */}
            {sidebarOpen && (
              <div className="px-2 pb-2 space-y-2 max-h-[60vh] overflow-y-auto">
                {attachments.map((att, idx) => {
                  const isVideo = att.file_type === 'video' && !isPreviewFrame(att)
                  const isCurrent = idx === currentIndex
                  return (
                    <button
                      key={att.id}
                      onClick={(e) => { e.stopPropagation(); onNavigate(idx) }}
                      className={`relative w-16 h-16 rounded-lg overflow-hidden transition-all ${
                        isCurrent
                          ? 'ring-2 ring-blue-500'
                          : 'opacity-50'
                      }`}
                    >
                      <img
                        src={getThumbnailUrl(att)}
                        alt=""
                        className="w-full h-full object-cover"
                      />
                      {isVideo && (
                        <div className="absolute inset-0 flex items-center justify-center bg-black/40">
                          <Video className="w-4 h-4 text-white" />
                        </div>
                      )}
                      {isPreviewFrame(att) && (
                        <div className="absolute inset-0 flex items-center justify-center bg-black/30">
                          <Lock className="w-4 h-4 text-white/80" />
                        </div>
                      )}
                    </button>
                  )
                })}
              </div>
            )}
          </div>
        )}

        {/* ===== BOTTOM BAR (Fansly-style) ===== */}
        {/* Videos: positioned based on video size. Images: bottom left corner of screen */}
        <div
          className={`fixed flex items-center transition-opacity duration-200 z-20 ${
            isCurrentVideo && !isLandscape && videoAspectRatio && videoAspectRatio > 1
              ? 'left-4 right-4'
              : `left-3 right-3 ${!isMobile ? 'bottom-4 right-auto max-w-md justify-start' : 'bottom-1 justify-between'}`
          }`}
          style={{
            ...(isCurrentVideo && !isLandscape && videoAspectRatio && videoAspectRatio > 1 ? { bottom: isMobile ? '4px' : '104px' } : {}),
            paddingBottom: 'env(safe-area-inset-bottom, 0px)',
          }}
        >
          <div className="flex items-start gap-3 min-w-0 flex-1">
            {/* Creator Avatar */}
            <div className="w-9 h-9 rounded-full bg-gradient-to-br from-pink-500 to-violet-500 p-0.5 flex-shrink-0 mt-0.5">
              <div className="w-full h-full rounded-full overflow-hidden bg-black">
                {post.profile_image_url ? (
                  <img src={post.profile_image_url} alt="" className="w-full h-full object-cover" />
                ) : (
                  <div className="w-full h-full flex items-center justify-center">
                    <User className="w-4 h-4 text-white/50" />
                  </div>
                )}
              </div>
            </div>

            {/* Creator name and post text */}
            <div className="min-w-0 flex-1">
              <div className="flex items-center gap-2">
                <span className="text-white text-sm font-medium drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]">{post.display_name || post.username}</span>
                <span className="text-white/60 text-xs drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]">@{post.username}</span>
              </div>
              <p className="text-white/70 text-sm drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)] leading-relaxed">
                {(() => {
                  // For YouTube/Twitch, use title instead of content
                  const isVideoService = ['youtube', 'twitch', 'pornhub'].includes(post.platform?.toLowerCase() || '')
                  const displayText = isVideoService && post.title ? post.title : (post.content || post.title)
                  const maxLen = isCurrentVideo ? 50 : 80
                  return displayText ? (
                    <>
                      {decodeHtmlEntities(displayText).slice(0, maxLen)}
                      {displayText.length > maxLen && '...'}
                    </>
                  ) : null
                })()}
                {onViewPost && (
                  <>
                    {' '}
                    <button
                      onClick={onViewPost}
                      className="text-white/70 hover:text-white hover:underline"
                    >
                      (View Post)
                    </button>
                  </>
                )}
              </p>
            </div>
          </div>

          {/* Favorite Heart - right side of bottom bar (mobile only, desktop uses center-right position) */}
          {onToggleFavorite && (
            <button
              onClick={onToggleFavorite}
              className={`${isMobile ? '' : 'hidden'} p-2 hover:text-red-400 transition-colors drop-shadow-[0_2px_4px_rgba(0,0,0,0.8)] flex-shrink-0 ml-2`}
              title={post.is_favorited ? 'Remove from favorites' : 'Add to favorites'}
            >
              <Heart className={`w-8 h-8 drop-shadow-[0_2px_4px_rgba(0,0,0,0.9)] ${post.is_favorited ? 'fill-red-500 text-red-500' : 'text-white stroke-2'}`} />
            </button>
          )}
        </div>
      </div>
    </div>
  )
}
