import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useState, useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import { useBreadcrumb } from '../hooks/useBreadcrumb'
import { breadcrumbConfig } from '../config/breadcrumbConfig'
import { Play, Trash2, CheckSquare, Square, Download, FolderInput, UserPlus, Eye, GalleryHorizontalEnd, CalendarClock, ImagePlus } from 'lucide-react'
import { FilterBar } from '../components/FilterPopover'
import { api, wsClient, type MediaGalleryItem } from '../lib/api'
import { formatBytes, formatPlatformName, isVideoFile as isVideoFileUtil } from '../lib/utils'
import { notificationManager } from '../lib/notificationManager'
import { invalidateAllFileCaches, optimisticRemoveFromMediaGallery } from '../lib/cacheInvalidation'
import EnhancedLightbox from '../components/EnhancedLightbox'
import { BatchProgressModal, BatchProgressItem } from '../components/BatchProgressModal'
import ThrottledImage from '../components/ThrottledImage'
import { CopyToGalleryModal } from '../components/private-gallery/CopyToGalleryModal'
import { useEnabledFeatures } from '../hooks/useEnabledFeatures'

// Type for navigation state from smart folders and timeline
interface MediaPageState {
  platform?: string
  source?: string
  mediaType?: 'all' | 'image' | 'video'
  sizeMin?: number
  dateFrom?: string
  dateTo?: string
}

export default function Media() {
  const queryClient = useQueryClient()
  const location = useLocation()
  const { isFeatureEnabled } = useEnabledFeatures()
  const navState = location.state as MediaPageState | null
  const [selectedMedia, setSelectedMedia] = useState<MediaGalleryItem | null>(null)

  // Breadcrumb with context for type filter
  const { setBreadcrumbs } = useBreadcrumb(breadcrumbConfig['/media'])

  // Helper function to check if file is a video (uses centralized utility)
  const isVideoFile = (media: MediaGalleryItem): boolean => {
    if (media.media_type === 'video') return true
    return isVideoFileUtil(media.filename)
  }

  // Get thumbnail URL - use stored YouTube thumbnail if available
  const getMediaThumbnailUrl = (media: MediaGalleryItem): string => {
    if (media.platform === 'youtube' && media.video_id) {
      return `/api/video/thumbnail/${media.platform}/${media.video_id}?source=downloads`
    }
    return api.getMediaThumbnailUrl(media.file_path, (media.media_type as 'image' | 'video') || 'image', media.file_token)
  }

  const [, setMediaResolution] = useState<string>('')
  const [platformFilter, setPlatformFilter] = useState<string>('')
  const [sourceFilter, setSourceFilter] = useState<string>('')
  const [typeFilter, setTypeFilter] = useState<'all' | 'image' | 'video'>('all')
  const [faceRecognitionFilter, setFaceRecognitionFilter] = useState<string>('')
  const [searchQuery, setSearchQuery] = useState<string>('')

  // Advanced filters
  const [dateFrom, setDateFrom] = useState<string>('')
  const [dateTo, setDateTo] = useState<string>('')
  const [sizeMin, setSizeMin] = useState<string>('')
  const [sizeMax, setSizeMax] = useState<string>('')
  const [sortBy, setSortBy] = useState<string>('post_date')
  const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc')

  // Apply navigation state from smart folders/timeline on mount
  useEffect(() => {
    if (navState) {
      if (navState.platform) setPlatformFilter(navState.platform)
      if (navState.source) setSourceFilter(navState.source)
      if (navState.mediaType) setTypeFilter(navState.mediaType)
      if (navState.sizeMin) setSizeMin(navState.sizeMin.toString())
      if (navState.dateFrom) setDateFrom(navState.dateFrom)
      if (navState.dateTo) setDateTo(navState.dateTo)
      // Clear state after applying
      window.history.replaceState({}, '')
    }
  }, [navState])

  // Update breadcrumb when filter changes
  useEffect(() => {
    const typeLabel = typeFilter === 'all' ? '' : typeFilter === 'image' ? 'Images' : 'Videos'
    if (typeLabel) {
      setBreadcrumbs([
        { label: 'Home', path: '/' },
        { label: 'Media Library', path: '/media' },
        { label: typeLabel }
      ])
    } else {
      setBreadcrumbs(breadcrumbConfig['/media'])
    }
  }, [typeFilter, setBreadcrumbs])

  const [page, setPage] = useState(0)
  const [selectedItems, setSelectedItems] = useState<Set<number>>(new Set())
  const [selectedPaths, setSelectedPaths] = useState<Map<number, string>>(new Map())
  const [selectMode, setSelectMode] = useState(false)
  const [showMoveModal, setShowMoveModal] = useState(false)
  const [moveDestination, setMoveDestination] = useState('')
  const [showAddModal, setShowAddModal] = useState(false)
  const [addPersonName, setAddPersonName] = useState('')
  const [actioningFile, setActioningFile] = useState<string | null>(null)
  const [showProgressModal, setShowProgressModal] = useState(false)
  const [progressFiles, setProgressFiles] = useState<BatchProgressItem[]>([])
  const [progressTitle, setProgressTitle] = useState('Processing Files')

  // Date edit modal state
  const [showDateModal, setShowDateModal] = useState(false)
  const [dateModalMode, setDateModalMode] = useState<'single' | 'batch'>('single')
  const [editingItemId, setEditingItemId] = useState<number | null>(null)
  const [newDate, setNewDate] = useState('')
  const [updateFileTimestamps, setUpdateFileTimestamps] = useState(true)

  // Copy to Private Gallery modal state
  const [showCopyToGalleryModal, setShowCopyToGalleryModal] = useState(false)

  const limit = 50

  const { data: mediaData, isLoading } = useQuery({
    queryKey: ['media-gallery', platformFilter, sourceFilter, typeFilter, faceRecognitionFilter, page, sortBy, sortOrder, dateFrom, dateTo, sizeMin, sizeMax, searchQuery],
    queryFn: () =>
      api.getMediaGallery({
        platform: platformFilter || undefined,
        source: sourceFilter || undefined,
        media_type: typeFilter,
        face_recognition: faceRecognitionFilter || undefined,
        limit,
        offset: page * limit,
        sort_by: sortBy,
        sort_order: sortOrder,
        date_from: dateFrom || undefined,
        date_to: dateTo || undefined,
        size_min: sizeMin ? parseInt(sizeMin) : undefined,
        size_max: sizeMax ? parseInt(sizeMax) : undefined,
        search: searchQuery || undefined,
      }),
    staleTime: 30000, // Cache for 30 seconds
    gcTime: 5 * 60000, // Keep in memory for 5 minutes
  })

  const { data: filters } = useQuery({
    queryKey: ['download-filters', platformFilter],
    queryFn: () => api.getDownloadFilters(platformFilter || undefined),
  })

  // Clear source filter when platform changes and source is not available
  useEffect(() => {
    if (filters && sourceFilter && !filters.sources.includes(sourceFilter)) {
      setSourceFilter('')
    }
  }, [filters, sourceFilter])

  // Helper function to advance to next/previous item after delete/move
  const advanceToNextItem = () => {
    if (!selectedMedia) return

    const currentIndex = filteredMedia.findIndex(m => m.id === selectedMedia.id)
    if (currentIndex === -1) {
      setSelectedMedia(null)
      return
    }

    // Try next item first
    if (currentIndex + 1 < filteredMedia.length) {
      setSelectedMedia(filteredMedia[currentIndex + 1])
    }
    // If no next item, try previous
    else if (currentIndex - 1 >= 0) {
      setSelectedMedia(filteredMedia[currentIndex - 1])
    }
    // If no items left, close lightbox
    else {
      setSelectedMedia(null)
    }
  }

  // Listen for new downloads and face reference updates via WebSocket
  useEffect(() => {
    const unsubscribeDownload = wsClient.on('download_completed', () => {
      invalidateAllFileCaches(queryClient)
    })

    const unsubscribeFaceRef = wsClient.on('face_reference_added', (data: { success: boolean; filename?: string; error?: string }) => {
      if (data.success) {
        notificationManager.faceReferenceAdded('Unknown', data.filename)
        invalidateAllFileCaches(queryClient)
      } else {
        notificationManager.faceReferenceError(data.error || (data.filename ? `Failed to process ${data.filename}` : 'Failed'))
      }
    })


    return () => {
      unsubscribeDownload()
      unsubscribeFaceRef()
    }
  }, [queryClient])

  const batchDeleteMutation = useMutation({
    mutationFn: async (filePaths: string[]) => {
      // Show progress for batch operations
      if (filePaths.length > 1) {
        const progressItems: BatchProgressItem[] = filePaths.map(fp => ({
          id: fp,
          filename: fp.split('/').pop() || fp,
          status: 'processing' as const
        }))
        setProgressFiles(progressItems)
        setProgressTitle('Deleting Files')
        setShowProgressModal(true)
      }

      const result = await api.batchDeleteMedia(filePaths)
      return { ...result, total: filePaths.length, isBatch: filePaths.length > 1 }
    },
    onSuccess: (data, variables) => {
      // Update progress to show completion
      if (data.isBatch) {
        setProgressFiles(prev => prev.map((f, i) =>
          i < data.deleted_count
            ? { ...f, status: 'success' }
            : { ...f, status: 'error', error: 'Failed to delete' }
        ))

        setTimeout(() => {
          setShowProgressModal(false)
          // Notification handled by websocket batch_delete_completed in App.tsx
        }, 1500)
      }

      // If lightbox is open, advance to next item
      if (selectedMedia) {
        advanceToNextItem()
      }
      optimisticRemoveFromMediaGallery(queryClient, new Set(variables))
      invalidateAllFileCaches(queryClient)
      setSelectedItems(new Set())
      setSelectedPaths(new Map())
      setSelectMode(false)
      // Trigger Immich scan (don't await - fire and forget)
      api.triggerImmichScan().catch(() => {})
    },
    onError: (err: unknown, variables) => {
      setShowProgressModal(false)
      const isBatch = variables.length > 1
      if (isBatch) {
        notificationManager.batchError('Delete', err)
      } else {
        notificationManager.deleteError('item', err)
      }
    },
  })

  const batchMoveMutation = useMutation({
    mutationFn: async ({ filePaths, destination }: { filePaths: string[], destination: string }) => {
      // Show progress
      const progressItems: BatchProgressItem[] = filePaths.map(fp => ({
        id: fp,
        filename: fp.split('/').pop() || fp,
        status: 'processing' as const
      }))
      setProgressFiles(progressItems)
      setProgressTitle('Moving Files')
      setShowProgressModal(true)
      setShowMoveModal(false)

      const result = await api.batchMoveMedia(filePaths, destination)
      return { ...result, total: filePaths.length }
    },
    onSuccess: (data, variables) => {
      // Update progress
      setProgressFiles(prev => prev.map((f, i) =>
        i < data.moved_count
          ? { ...f, status: 'success' }
          : { ...f, status: 'error', error: 'Failed to move' }
      ))

      optimisticRemoveFromMediaGallery(queryClient, new Set(variables.filePaths))
      invalidateAllFileCaches(queryClient)
      setSelectedItems(new Set())
      setSelectedPaths(new Map())
      setSelectMode(false)
      setMoveDestination('')

      setTimeout(() => {
        setShowProgressModal(false)
        // Notification handled by websocket batch_move_completed in App.tsx
      }, 1500)

      // Trigger Immich scan (don't await - fire and forget)
      api.triggerImmichScan().catch(() => {})
    },
    onError: (err: unknown) => {
      setShowProgressModal(false)
      notificationManager.batchError('Move', err)
    },
  })

  const batchDownloadMutation = useMutation({
    mutationFn: async (filePaths: string[]) => {
      // Show progress
      const progressItems: BatchProgressItem[] = filePaths.map(fp => ({
        id: fp,
        filename: fp.split('/').pop() || fp,
        status: 'processing' as const
      }))
      setProgressFiles(progressItems)
      setProgressTitle('Preparing Download')
      setShowProgressModal(true)

      const result = await api.batchDownloadMedia(filePaths)
      return { ...result, total: filePaths.length }
    },
    onSuccess: (data) => {
      // Mark all as success
      setProgressFiles(prev => prev.map(f => ({ ...f, status: 'success' as const })))

      setTimeout(() => {
        setShowProgressModal(false)
        notificationManager.downloadReady(data.total)
      }, 1500)
    },
    onError: (err: unknown) => {
      setShowProgressModal(false)
      notificationManager.apiError('Download Failed', err, `Failed to download ${selectedItems.size} items`)
    },
  })

  const addFaceReferenceMutation = useMutation({
    mutationFn: (file_path: string) => api.addFaceReference(file_path, undefined, true), // background = true
    onSuccess: (data) => {
      setSelectedMedia(null) // Close lightbox immediately
      notificationManager.processing(data.message)
    },
    onError: (err: unknown) => {
      notificationManager.faceReferenceError(err)
    },
  })

  const batchAddFaceReferenceMutation = useMutation({
    mutationFn: async ({ files }: { files: Array<{ path: string; filename: string }> }) => {
      // Show progress modal
      const progressItems: BatchProgressItem[] = files.map(f => ({
        id: f.path,
        filename: f.filename,
        status: 'pending' as const
      }))
      setProgressFiles(progressItems)
      setProgressTitle('Processing Face References')
      setShowProgressModal(true)

      let succeeded = 0
      let failed = 0

      // Process files sequentially with progress updates
      for (const file of files) {
        // Mark current as processing
        setProgressFiles(prev => prev.map(f =>
          f.id === file.path ? { ...f, status: 'processing' } : f
        ))

        try {
          await api.addFaceReference(file.path, undefined, true)
          succeeded++
          setProgressFiles(prev => prev.map(f =>
            f.id === file.path ? { ...f, status: 'success' } : f
          ))
        } catch (err) {
          failed++
          setProgressFiles(prev => prev.map(f =>
            f.id === file.path ? { ...f, status: 'error', error: (err as Error)?.message || 'Failed' } : f
          ))
        }
      }

      return { total: files.length, succeeded, failed }
    },
    onSuccess: (data) => {
      setTimeout(() => {
        setShowProgressModal(false)
        notificationManager.batchSuccess('Add Reference', data.succeeded, 'file')
      }, 1500)
    },
    onError: (err: unknown) => {
      setShowProgressModal(false)
      notificationManager.batchError('Add Reference', err)
    },
  })

  const addReferenceMutation = useMutation({
    mutationFn: ({ filePath, personName }: { filePath: string; personName: string }) =>
      api.addFaceReference(filePath, personName, false), // background = false for immediate feedback
    onSuccess: (data) => {
      invalidateAllFileCaches(queryClient)
      setShowAddModal(false)
      setActioningFile(null)
      setSelectedMedia(null) // Close lightbox
      notificationManager.faceReferenceAdded(data.person_name)
      // Trigger Immich scan (don't await - fire and forget)
      api.triggerImmichScan().catch(() => {})
    },
    onError: (err: unknown) => {
      setActioningFile(null)
      notificationManager.faceReferenceError(err)
    },
  })

  const moveToReviewMutation = useMutation({
    mutationFn: (filePaths: string[]) => api.moveToReview(filePaths),
    onSuccess: (data, variables) => {
      // If lightbox is open, advance to next item
      if (selectedMedia) {
        advanceToNextItem()
      }
      optimisticRemoveFromMediaGallery(queryClient, new Set(variables))
      invalidateAllFileCaches(queryClient)
      setSelectedItems(new Set())
      setSelectedPaths(new Map())
      setSelectMode(false)
      notificationManager.movedToReview(data.moved_count)
      // Trigger Immich scan (don't await - fire and forget)
      api.triggerImmichScan().catch(() => {})
    },
    onError: (err: unknown) => {
      notificationManager.moveError('item', err)
    },
  })

  const updateDateMutation = useMutation({
    mutationFn: ({ ids, newDate, updateFile }: { ids: number[]; newDate: string; updateFile: boolean }) =>
      api.updateMediaDate(ids, newDate, updateFile, 'post_date'),
    onSuccess: (data) => {
      invalidateAllFileCaches(queryClient)
      setShowDateModal(false)
      setNewDate('')
      setEditingItemId(null)
      if (dateModalMode === 'batch') {
        setSelectedItems(new Set())
        setSelectedPaths(new Map())
        setSelectMode(false)
      }
      notificationManager.dateUpdated(`${data.success_count} file${data.success_count !== 1 ? 's' : ''}`)
    },
    onError: (err: unknown) => {
      notificationManager.dateUpdateError(err)
    },
  })

  // All filtering is now server-side
  const filteredMedia = mediaData?.media || []

  // Server-side sorting is now handled by the backend, no client-side sorting needed

  const totalPages = Math.ceil((mediaData?.total || 0) / limit)

  const toggleSelect = (id: number) => {
    const newSelected = new Set(selectedItems)
    const newPaths = new Map(selectedPaths)
    if (newSelected.has(id)) {
      newSelected.delete(id)
      newPaths.delete(id)
    } else {
      newSelected.add(id)
      const item = filteredMedia.find(m => m.id === id)
      if (item) newPaths.set(id, item.file_path)
    }
    setSelectedItems(newSelected)
    setSelectedPaths(newPaths)
  }

  const selectAll = () => {
    if (selectedItems.size === filteredMedia.length) {
      setSelectedItems(new Set())
      setSelectedPaths(new Map())
    } else {
      setSelectedItems(new Set(filteredMedia.map(m => m.id)))
      setSelectedPaths(new Map(filteredMedia.map(m => [m.id, m.file_path])))
    }
  }

  const handleBatchDelete = () => {
    if (selectedItems.size === 0) return

    const selectedPaths = filteredMedia
      .filter(m => selectedItems.has(m.id))
      .map(m => m.file_path)

    if (confirm(`Delete ${selectedItems.size} selected items?`)) {
      batchDeleteMutation.mutate(selectedPaths)
    }
  }

  const handleBatchMove = () => {
    if (selectedItems.size === 0) return
    setShowMoveModal(true)
  }

  const confirmBatchMove = () => {
    if (!moveDestination.trim()) return

    const selectedPaths = filteredMedia
      .filter(m => selectedItems.has(m.id))
      .map(m => m.file_path)

    batchMoveMutation.mutate({ filePaths: selectedPaths, destination: moveDestination })
  }

  const handleBatchDownload = () => {
    if (selectedItems.size === 0) return

    const selectedPaths = filteredMedia
      .filter(m => selectedItems.has(m.id))
      .map(m => m.file_path)

    batchDownloadMutation.mutate(selectedPaths)
  }

  const handleBatchAddFaceReference = () => {
    if (selectedItems.size === 0) return

    const selectedFiles = filteredMedia
      .filter(m => selectedItems.has(m.id))
      .map(m => ({ path: m.file_path, filename: m.filename }))

    if (confirm(`Add ${selectedItems.size} selected items as face references?`)) {
      // Clear selections and show initial toast immediately
      const count = selectedFiles.length
      setSelectedItems(new Set())
      setSelectedPaths(new Map())
      setSelectMode(false)
      notificationManager.processing(`Processing ${count} file${count !== 1 ? 's' : ''} sequentially`)
      // Start processing
      batchAddFaceReferenceMutation.mutate({ files: selectedFiles })
    }
  }

  const handleMoveToReview = () => {
    if (selectedItems.size === 0) return

    const selectedPaths = filteredMedia
      .filter(m => selectedItems.has(m.id))
      .map(m => m.file_path)

    if (confirm(`Move ${selectedItems.size} item${selectedItems.size !== 1 ? 's' : ''} to review queue?`)) {
      moveToReviewMutation.mutate(selectedPaths)
    }
  }

  const handleSingleMoveToReview = (filePath: string) => {
    if (confirm('Move this item to review queue?')) {
      moveToReviewMutation.mutate([filePath])
    }
  }

  // Date editing handlers
  const handleBatchChangeDate = () => {
    if (selectedItems.size === 0) return
    setDateModalMode('batch')
    setNewDate('')
    setShowDateModal(true)
  }

  const handleSingleChangeDate = (media: MediaGalleryItem) => {
    setDateModalMode('single')
    setEditingItemId(media.id)
    // Pre-fill with current post_date if available
    if (media.post_date) {
      // Convert to datetime-local format (YYYY-MM-DDTHH:MM)
      const date = new Date(media.post_date)
      const localDateTime = new Date(date.getTime() - date.getTimezoneOffset() * 60000)
        .toISOString()
        .slice(0, 16)
      setNewDate(localDateTime)
    } else {
      setNewDate('')
    }
    setShowDateModal(true)
  }

  const confirmDateChange = () => {
    if (!newDate) return

    const ids = dateModalMode === 'batch'
      ? Array.from(selectedItems)
      : editingItemId ? [editingItemId] : []

    if (ids.length === 0) return

    // Convert datetime-local value to ISO string
    const isoDate = new Date(newDate).toISOString()
    updateDateMutation.mutate({ ids, newDate: isoDate, updateFile: updateFileTimestamps })
  }

  const handleAddReference = (media: MediaGalleryItem) => {
    setActioningFile(media.file_path)
    setShowAddModal(true)
  }

  const handleDelete = (media: MediaGalleryItem) => {
    if (confirm(`Delete "${media.filename}"?`)) {
      setActioningFile(media.file_path)
      batchDeleteMutation.mutate([media.file_path])
    }
  }

  const confirmAddReference = () => {
    if (!addPersonName.trim() || !actioningFile) return
    addReferenceMutation.mutate({ filePath: actioningFile, personName: addPersonName })
  }

  const openLightbox = (media: MediaGalleryItem) => {
    setSelectedMedia(media)
  }

  // Helper to get current index for lightbox
  const getCurrentLightboxIndex = () => {
    if (!selectedMedia || !filteredMedia) return -1
    return filteredMedia.findIndex((m) => m.id === selectedMedia.id)
  }

  return (
    <div className="space-y-6">
      {/* Header */}
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-2xl sm:text-3xl font-bold flex items-center gap-2 sm:gap-3">
            <GalleryHorizontalEnd className="w-8 h-8 text-purple-500" />
            Media Gallery
          </h1>
          <p className="text-slate-600 dark:text-slate-400 mt-1">
            Browse and preview all downloaded media files
          </p>
        </div>
        <div className="flex items-center space-x-2">
          <button
            onClick={() => {
              setSelectMode(!selectMode)
              setSelectedItems(new Set())
              setSelectedPaths(new Map())
            }}
            className={`px-4 py-2.5 rounded-lg text-sm font-medium transition-colors min-h-[44px] ${
              selectMode
                ? 'bg-blue-600 text-white'
                : 'bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-300 hover:bg-slate-300 dark:hover:bg-slate-600'
            }`}
          >
            {selectMode ? 'Cancel Selection' : 'Select Items'}
          </button>
        </div>
      </div>

      {/* Batch Operations Bar */}
      {selectMode && (
        <div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
          <div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
            <div className="flex flex-wrap items-center gap-3">
              <button
                onClick={selectAll}
                className="flex items-center space-x-2 text-sm font-medium text-blue-700 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-200 min-h-[44px]"
              >
                {selectedItems.size === filteredMedia.length ? (
                  <CheckSquare className="w-5 h-5" />
                ) : (
                  <Square className="w-5 h-5" />
                )}
                <span>{selectedItems.size === filteredMedia.length ? 'Deselect All' : 'Select All'}</span>
              </button>
              <span className="text-sm text-blue-700 dark:text-blue-400">
                {selectedItems.size} item{selectedItems.size !== 1 ? 's' : ''} selected
              </span>
            </div>
            <div className="flex flex-wrap items-center gap-2">
              <button
                onClick={handleBatchDownload}
                disabled={selectedItems.size === 0 || batchDownloadMutation.isPending}
                className="flex items-center space-x-2 px-4 py-2.5 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px] text-sm transition-colors"
              >
                <Download className="w-5 h-5" />
                <span className="hidden sm:inline">Download as ZIP</span>
                <span className="sm:hidden">ZIP</span>
              </button>
              {isFeatureEnabled('/private-gallery') && (
              <button
                onClick={() => setShowCopyToGalleryModal(true)}
                disabled={selectedItems.size === 0}
                className="flex items-center space-x-2 px-4 py-2.5 bg-violet-600 text-white rounded-lg hover:bg-violet-700 disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px] text-sm transition-colors"
              >
                <ImagePlus className="w-5 h-5" />
                <span className="hidden sm:inline">Copy to Private</span>
                <span className="sm:hidden">Private</span>
              </button>
              )}
              <button
                onClick={handleBatchMove}
                disabled={selectedItems.size === 0 || batchMoveMutation.isPending}
                className="flex items-center space-x-2 px-4 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px] text-sm transition-colors"
              >
                <FolderInput className="w-5 h-5" />
                <span className="hidden sm:inline">Move Selected</span>
                <span className="sm:hidden">Move</span>
              </button>
              <button
                onClick={handleBatchAddFaceReference}
                disabled={selectedItems.size === 0 || batchAddFaceReferenceMutation.isPending}
                className="flex items-center space-x-2 px-4 py-2.5 bg-purple-600 text-white rounded-lg hover:bg-purple-700 disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px] text-sm transition-colors"
              >
                <UserPlus className="w-5 h-5" />
                <span className="hidden sm:inline">Add Face References</span>
                <span className="sm:hidden">Faces</span>
              </button>
              <button
                onClick={handleMoveToReview}
                disabled={selectedItems.size === 0 || moveToReviewMutation.isPending}
                className="flex items-center space-x-2 px-4 py-2.5 bg-orange-600 text-white rounded-lg hover:bg-orange-700 disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px] text-sm transition-colors"
              >
                <Eye className="w-5 h-5" />
                <span className="hidden sm:inline">Move to Review</span>
                <span className="sm:hidden">Review</span>
              </button>
              <button
                onClick={handleBatchChangeDate}
                disabled={selectedItems.size === 0 || updateDateMutation.isPending}
                className="flex items-center space-x-2 px-4 py-2.5 bg-amber-600 text-white rounded-lg hover:bg-amber-700 disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px] text-sm transition-colors"
              >
                <CalendarClock className="w-5 h-5" />
                <span className="hidden sm:inline">Change Date</span>
                <span className="sm:hidden">Date</span>
              </button>
              <button
                onClick={handleBatchDelete}
                disabled={selectedItems.size === 0 || batchDeleteMutation.isPending}
                className="flex items-center space-x-2 px-4 py-2.5 bg-red-600 text-white rounded-lg hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px] text-sm transition-colors"
              >
                <Trash2 className="w-5 h-5" />
                <span className="hidden sm:inline">Delete Selected</span>
                <span className="sm:hidden">Delete</span>
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Filters */}
      <FilterBar
        searchValue={searchQuery}
        onSearchChange={(v) => { setSearchQuery(v); setPage(0) }}
        searchPlaceholder="Search filenames..."
        filterSections={[
          {
            id: 'platform',
            label: 'Platform',
            type: 'select',
            options: [{ value: '', label: 'All Platforms' }, ...(filters?.platforms || []).map(p => ({ value: p, label: formatPlatformName(p) }))],
            value: platformFilter,
            onChange: (v) => { setPlatformFilter(v as string); setPage(0) }
          },
          {
            id: 'source',
            label: 'Source',
            type: 'select',
            options: [{ value: '', label: 'All Sources' }, ...(filters?.sources || []).map(s => ({ value: s, label: s }))],
            value: sourceFilter,
            onChange: (v) => { setSourceFilter(v as string); setPage(0) }
          },
          {
            id: 'type',
            label: 'Media Type',
            type: 'select',
            options: [
              { value: 'all', label: 'All Media' },
              { value: 'image', label: 'Images Only' },
              { value: 'video', label: 'Videos Only' }
            ],
            value: typeFilter,
            onChange: (v) => { setTypeFilter(v as 'all' | 'image' | 'video'); setPage(0) }
          },
          {
            id: 'face',
            label: 'Face Recognition',
            type: 'select',
            options: [
              { value: '', label: 'All Files' },
              { value: 'matched', label: 'Matched Only' },
              { value: 'no_match', label: 'No Match Only' },
              { value: 'not_scanned', label: 'Not Scanned' }
            ],
            value: faceRecognitionFilter,
            onChange: (v) => { setFaceRecognitionFilter(v as string); setPage(0) }
          },
          {
            id: 'sortBy',
            label: 'Sort By',
            type: 'select',
            options: [
              { value: 'post_date', label: 'Post Date' },
              { value: 'download_date', label: 'Download Date' },
              { value: 'file_size', label: 'File Size' },
              { value: 'filename', label: 'Filename' },
              { value: 'source', label: 'Source' },
              { value: 'platform', label: 'Platform' }
            ],
            value: sortBy,
            onChange: (v) => { setSortBy(v as string); setPage(0) }
          },
          {
            id: 'sortOrder',
            label: 'Sort Order',
            type: 'select',
            options: [
              { value: 'desc', label: 'Newest First' },
              { value: 'asc', label: 'Oldest First' }
            ],
            value: sortOrder,
            onChange: (v) => { setSortOrder(v as 'asc' | 'desc'); setPage(0) }
          }
        ]}
        activeFilters={[
          ...(platformFilter ? [{
            id: 'platform', label: 'Platform', value: platformFilter,
            displayValue: formatPlatformName(platformFilter),
            onRemove: () => { setPlatformFilter(''); setPage(0) }
          }] : []),
          ...(sourceFilter ? [{
            id: 'source', label: 'Source', value: sourceFilter,
            displayValue: sourceFilter,
            onRemove: () => { setSourceFilter(''); setPage(0) }
          }] : []),
          ...(typeFilter !== 'all' ? [{
            id: 'type', label: 'Type', value: typeFilter,
            displayValue: typeFilter === 'image' ? 'Images' : 'Videos',
            onRemove: () => { setTypeFilter('all'); setPage(0) }
          }] : []),
          ...(faceRecognitionFilter ? [{
            id: 'face', label: 'Face', value: faceRecognitionFilter,
            displayValue: faceRecognitionFilter === 'matched' ? 'Matched' : faceRecognitionFilter === 'no_match' ? 'No Match' : 'Not Scanned',
            onRemove: () => { setFaceRecognitionFilter(''); setPage(0) }
          }] : []),
          ...(dateFrom ? [{
            id: 'dateFrom', label: 'From', value: dateFrom,
            displayValue: dateFrom,
            onRemove: () => { setDateFrom(''); setPage(0) }
          }] : []),
          ...(dateTo ? [{
            id: 'dateTo', label: 'To', value: dateTo,
            displayValue: dateTo,
            onRemove: () => { setDateTo(''); setPage(0) }
          }] : []),
          ...(sizeMin ? [{
            id: 'sizeMin', label: 'Min Size', value: sizeMin,
            displayValue: `${sizeMin} bytes`,
            onRemove: () => { setSizeMin(''); setPage(0) }
          }] : []),
          ...(sizeMax ? [{
            id: 'sizeMax', label: 'Max Size', value: sizeMax,
            displayValue: `${sizeMax} bytes`,
            onRemove: () => { setSizeMax(''); setPage(0) }
          }] : [])
        ]}
        onClearAll={() => {
          setPlatformFilter('')
          setSourceFilter('')
          setTypeFilter('all')
          setFaceRecognitionFilter('')
          setSearchQuery('')
          setDateFrom('')
          setDateTo('')
          setSizeMin('')
          setSizeMax('')
          setPage(0)
        }}
        advancedFilters={{
          dateFrom: { value: dateFrom, onChange: (v) => { setDateFrom(v); setPage(0) } },
          dateTo: { value: dateTo, onChange: (v) => { setDateTo(v); setPage(0) } },
          sizeMin: { value: sizeMin, onChange: (v) => { setSizeMin(v); setPage(0) } },
          sizeMax: { value: sizeMax, onChange: (v) => { setSizeMax(v); setPage(0) } }
        }}
        totalCount={mediaData?.total}
        countLabel="items"
      />

      {/* Stats */}
      <div className="flex items-center justify-between text-sm text-slate-600 dark:text-slate-400">
        <div>
          Showing {filteredMedia.length} of {mediaData?.total || 0} items
        </div>
        <div>
          Page {page + 1} of {totalPages || 1}
        </div>
      </div>

      {/* Gallery Grid */}
      {isLoading ? (
        <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
          {[...Array(20)].map((_, i) => (
            <div key={i} className="aspect-square bg-slate-200 dark:bg-slate-800 rounded-lg animate-pulse" />
          ))}
        </div>
      ) : (
        <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
          {filteredMedia.map((media) => (
            <div
              key={media.id}
              onClick={() => selectMode ? toggleSelect(media.id) : openLightbox(media)}
              className={`group relative aspect-square bg-slate-100 dark:bg-slate-800 rounded-lg overflow-hidden cursor-pointer hover:ring-2 card-lift thumbnail-zoom ${
                selectedItems.has(media.id)
                  ? 'ring-2 ring-blue-500'
                  : 'hover:ring-blue-500'
              }`}
            >
              {/* Thumbnail */}
              <ThrottledImage
                src={getMediaThumbnailUrl(media)}
                alt={media.filename}
                className="w-full h-full object-cover"
              />

                {/* Select Checkbox */}
                {selectMode && (
                  <div className="absolute top-2 left-2 z-10">
                    <div className={`w-6 h-6 rounded border-2 flex items-center justify-center transition-colors ${
                      selectedItems.has(media.id)
                        ? 'bg-blue-600 border-blue-600'
                        : 'bg-white/90 border-slate-300'
                    }`}>
                      {selectedItems.has(media.id) && (
                        <svg className="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
                        </svg>
                      )}
                    </div>
                  </div>
                )}

              {/* Video indicator */}
              {isVideoFile(media) && (
                <div className="absolute top-2 right-2 bg-black/70 rounded-full p-1.5">
                  <Play className="w-4 h-4 text-white fill-white" />
                </div>
              )}

              {/* Action buttons overlay */}
              {!selectMode && (
                <div className="absolute inset-0 bg-black/60 opacity-0 group-hover:opacity-100 transition-opacity flex flex-col items-center justify-center space-y-2 p-2">
                    <button
                      onClick={(e) => {
                        e.stopPropagation()
                        handleSingleMoveToReview(media.file_path)
                      }}
                      disabled={actioningFile === media.file_path}
                      className="w-full px-3 py-2 bg-orange-600 text-white rounded-lg hover:bg-orange-700 disabled:opacity-50 flex items-center justify-center space-x-2 text-sm transition-colors"
                    >
                      <Eye className="w-4 h-4" />
                      <span>Review</span>
                    </button>
                    <button
                      onClick={(e) => {
                        e.stopPropagation()
                        handleAddReference(media)
                      }}
                      disabled={actioningFile === media.file_path}
                      className="w-full px-3 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 flex items-center justify-center space-x-2 text-sm transition-colors"
                    >
                      <UserPlus className="w-4 h-4" />
                      <span>Add Reference</span>
                    </button>
                    <button
                      onClick={(e) => {
                        e.stopPropagation()
                        handleDelete(media)
                      }}
                      disabled={actioningFile === media.file_path}
                      className="w-full px-3 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 disabled:opacity-50 flex items-center justify-center space-x-2 text-sm transition-colors"
                    >
                      <Trash2 className="w-4 h-4" />
                      <span>Delete</span>
                    </button>
                  </div>
                )}

              {/* File info */}
              {!selectMode && (
                <div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-2 opacity-0 group-hover:opacity-100 transition-opacity">
                  <p className="text-white text-xs truncate">{media.filename}</p>
                  <p className="text-white/70 text-xs">{formatBytes(media.file_size)}</p>
                </div>
              )}
            </div>
          ))}
        </div>
      )}

      {/* Pagination */}
      {totalPages > 1 && (
        <div className="flex justify-center space-x-2">
          <button
            onClick={() => setPage((p) => Math.max(0, p - 1))}
            disabled={page === 0}
            className="px-4 py-2.5 border border-slate-300 dark:border-slate-600 rounded-lg disabled:opacity-50 hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors min-h-[44px]"
          >
            Previous
          </button>
          <span className="px-4 py-2 text-slate-600 dark:text-slate-400">
            {page + 1} / {totalPages}
          </span>
          <button
            onClick={() => setPage((p) => Math.min(totalPages - 1, p + 1))}
            disabled={page >= totalPages - 1}
            className="px-4 py-2.5 border border-slate-300 dark:border-slate-600 rounded-lg disabled:opacity-50 hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors min-h-[44px]"
          >
            Next
          </button>
        </div>
      )}

      {/* Lightbox */}
      {selectedMedia && getCurrentLightboxIndex() >= 0 && (
        <EnhancedLightbox
          items={filteredMedia}
          currentIndex={getCurrentLightboxIndex()}
          onClose={() => { setSelectedMedia(null); setMediaResolution('') }}
          onNavigate={(index) => { setSelectedMedia(filteredMedia[index]); setMediaResolution('') }}
          onDelete={handleDelete}
          onEditDate={handleSingleChangeDate}
          getPreviewUrl={(item) => api.getMediaPreviewUrl(item.file_path, item.file_token)}
          getThumbnailUrl={(item: MediaGalleryItem) => getMediaThumbnailUrl(item)}
          isVideo={(item) => isVideoFile(item)}
          hideFaceRecognition={true}
          renderActions={(item) => (
            <>
              <button
                onClick={() => handleSingleMoveToReview(item.file_path)}
                disabled={moveToReviewMutation.isPending || actioningFile === item.file_path}
                className="px-6 py-3 bg-orange-600 text-white rounded-lg hover:bg-orange-700 disabled:opacity-50 flex items-center space-x-2 transition-colors"
              >
                <Eye className="w-5 h-5" />
                <span>{moveToReviewMutation.isPending ? 'Moving...' : 'Move to Review'}</span>
              </button>
              <button
                onClick={() => handleAddReference(item)}
                disabled={actioningFile === item.file_path}
                className="px-3 py-1.5 md:px-6 md:py-3 bg-blue-600 text-white text-sm md:text-base rounded-lg hover:bg-blue-700 disabled:opacity-50 flex items-center space-x-1.5 md:space-x-2 transition-colors"
              >
                <UserPlus className="w-4 h-4 md:w-5 md:h-5" />
                <span>Add Reference</span>
              </button>
              <button
                onClick={() => addFaceReferenceMutation.mutate(item.file_path)}
                disabled={addFaceReferenceMutation.isPending}
                className="px-3 py-1.5 md:px-6 md:py-3 bg-purple-600 text-white text-sm md:text-base rounded-lg hover:bg-purple-700 disabled:opacity-50 flex items-center space-x-1.5 md:space-x-2 transition-colors"
              >
                <UserPlus className="w-4 h-4 md:w-5 md:h-5" />
                <span>{addFaceReferenceMutation.isPending ? 'Adding...' : 'Quick Add Face'}</span>
              </button>
              <button
                onClick={() => handleDelete(item)}
                disabled={actioningFile === item.file_path}
                className="px-3 py-1.5 md:px-6 md:py-3 bg-red-600 text-white text-sm md:text-base rounded-lg hover:bg-red-700 disabled:opacity-50 flex items-center space-x-1.5 md:space-x-2 transition-colors"
              >
                <Trash2 className="w-4 h-4 md:w-5 md:h-5" />
                <span>Delete</span>
              </button>
            </>
          )}
        />
      )}

      {/* Move Modal */}
      {showMoveModal && (
        <div className="fixed inset-0 z-50 bg-black/50 flex items-center justify-center p-4">
          <div className="bg-card border border-border rounded-xl shadow-2xl max-w-md w-full p-6">
            <h3 className="text-lg font-semibold text-slate-900 dark:text-slate-100 mb-4">
              Move {selectedItems.size} items
            </h3>
            <div className="mb-4">
              <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
                Destination Path
              </label>
              <input
                type="text"
                value={moveDestination}
                onChange={(e) => setMoveDestination(e.target.value)}
                placeholder="/path/to/destination"
                className="w-full px-3 py-2 border border-border rounded-lg bg-background text-foreground"
                autoFocus
              />
              <p className="mt-2 text-xs text-slate-500 dark:text-slate-400">
                Enter an absolute path where files should be moved
              </p>
            </div>
            <div className="flex items-center justify-end space-x-3">
              <button
                onClick={() => {
                  setShowMoveModal(false)
                  setMoveDestination('')
                }}
                className="px-4 py-2.5 border border-slate-300 dark:border-slate-600 rounded-lg text-slate-700 dark:text-slate-300 hover:bg-slate-50 dark:hover:bg-slate-700 transition-colors min-h-[44px]"
              >
                Cancel
              </button>
              <button
                onClick={confirmBatchMove}
                disabled={!moveDestination.trim() || batchMoveMutation.isPending}
                className="px-4 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors min-h-[44px]"
              >
                {batchMoveMutation.isPending ? 'Moving...' : 'Move Files'}
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Add Reference Modal */}
      {showAddModal && (
        <div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
          <div className="bg-card border border-border rounded-xl shadow-2xl p-6 max-w-md w-full">
            <h3 className="text-lg font-semibold text-slate-900 dark:text-slate-100 mb-4">
              Add as Face Reference
            </h3>
            <p className="text-sm text-slate-600 dark:text-slate-400 mb-4">
              This will add the face in this image as a reference for future matching.
            </p>
            <div>
              <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
                Person Name
              </label>
              <input
                type="text"
                value={addPersonName}
                onChange={(e) => setAddPersonName(e.target.value)}
                placeholder="Enter person name"
                className="w-full px-3 py-2 border border-border rounded-lg bg-background text-foreground"
                autoFocus
                onKeyDown={(e) => {
                  if (e.key === 'Enter' && addPersonName.trim()) {
                    confirmAddReference()
                  }
                }}
              />
            </div>
            <div className="flex justify-end space-x-2 mt-4">
              <button
                onClick={() => {
                  setShowAddModal(false)
                  setActioningFile(null)
                }}
                className="px-4 py-2.5 text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700 rounded-lg transition-colors min-h-[44px]"
              >
                Cancel
              </button>
              <button
                onClick={confirmAddReference}
                disabled={!addPersonName.trim() || addReferenceMutation.isPending}
                className="px-4 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 transition-colors min-h-[44px]"
              >
                {addReferenceMutation.isPending ? 'Adding...' : 'Add Reference'}
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Progress Modal */}
      <BatchProgressModal
        isOpen={showProgressModal}
        title={progressTitle}
        items={progressFiles}
        onClose={() => setShowProgressModal(false)}
      />

      {/* Date Edit Modal - z-[60] to appear above the lightbox (z-50) */}
      {showDateModal && (
        <div className="fixed inset-0 bg-black/50 z-[60] flex items-center justify-center p-4">
          <div className="bg-card border border-border rounded-xl shadow-2xl p-6 max-w-md w-full">
            <h3 className="text-lg font-semibold text-slate-900 dark:text-slate-100 mb-4 flex items-center space-x-2">
              <CalendarClock className="w-5 h-5 text-amber-500" />
              <span>
                {dateModalMode === 'batch'
                  ? `Change Date for ${selectedItems.size} item${selectedItems.size !== 1 ? 's' : ''}`
                  : 'Edit Post Date'}
              </span>
            </h3>
            <p className="text-sm text-slate-600 dark:text-slate-400 mb-4">
              {dateModalMode === 'batch'
                ? 'Set a new post date for all selected files. This will update the database and optionally update file timestamps.'
                : 'Change the post date for this file. This will update the database and optionally update file timestamps.'}
            </p>
            <div className="space-y-4">
              <div>
                <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
                  New Date and Time
                </label>
                <input
                  type="datetime-local"
                  value={newDate}
                  onChange={(e) => setNewDate(e.target.value)}
                  className="w-full px-3 py-2 border border-border rounded-lg bg-background text-foreground"
                  autoFocus
                />
              </div>
              <div className="flex items-center space-x-2">
                <input
                  type="checkbox"
                  id="updateFileTimestamps"
                  checked={updateFileTimestamps}
                  onChange={(e) => setUpdateFileTimestamps(e.target.checked)}
                  className="w-4 h-4 text-amber-600 border-slate-300 rounded focus:ring-amber-500"
                />
                <label htmlFor="updateFileTimestamps" className="text-sm text-slate-700 dark:text-slate-300">
                  Update file timestamps (EXIF/metadata and filesystem)
                </label>
              </div>
            </div>
            <div className="flex justify-end space-x-2 mt-6">
              <button
                onClick={() => {
                  setShowDateModal(false)
                  setNewDate('')
                  setEditingItemId(null)
                }}
                className="px-4 py-2.5 text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700 rounded-lg transition-colors min-h-[44px]"
              >
                Cancel
              </button>
              <button
                onClick={confirmDateChange}
                disabled={!newDate || updateDateMutation.isPending}
                className="px-4 py-2.5 bg-amber-600 text-white rounded-lg hover:bg-amber-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center space-x-2 transition-colors min-h-[44px]"
              >
                {updateDateMutation.isPending ? (
                  <>
                    <span className="animate-spin">⏳</span>
                    <span>Updating...</span>
                  </>
                ) : (
                  <span>Apply</span>
                )}
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Copy to Private Gallery Modal */}
      <CopyToGalleryModal
        open={showCopyToGalleryModal}
        onClose={() => setShowCopyToGalleryModal(false)}
        sourcePaths={Array.from(selectedPaths.values())}
        sourceType="media"
        onSuccess={() => {
          setShowCopyToGalleryModal(false)
          setSelectedItems(new Set())
          setSelectedPaths(new Map())
          setSelectMode(false)
        }}
      />
    </div>
  )
}
