/**
 * Private Gallery Upload Modal
 *
 * Upload files with person, tags, date, and description
 * Two-phase progress: upload bytes transfer, then server-side processing
 */

import { useState, useRef, useCallback, useEffect } from 'react'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import {
  X,
  Upload,
  Image as ImageIcon,
  Video,
  Trash2,
  Loader2,
  Calendar,
  FileText,
  CheckCircle,
  Link,
  FolderOpen,
} from 'lucide-react'
import { api } from '../../lib/api'
import PersonSelector from './PersonSelector'
import TagSearchSelector from './TagSearchSelector'
import ThumbnailProgressModal, { ThumbnailProgressItem } from '../ThumbnailProgressModal'

interface UploadModalProps {
  open: boolean
  onClose: () => void
  onSuccess?: (postId?: number) => void
}

interface SelectedFile {
  file: File
  preview?: string
  type: 'image' | 'video' | 'other'
}

export function PrivateGalleryUploadModal({ open, onClose, onSuccess }: UploadModalProps) {
  const queryClient = useQueryClient()
  const fileInputRef = useRef<HTMLInputElement>(null)

  const [files, setFiles] = useState<SelectedFile[]>([])
  const [personId, setPersonId] = useState<number | undefined>()
  const [selectedTags, setSelectedTags] = useState<number[]>([])
  const [tagsManuallyModified, setTagsManuallyModified] = useState(false)
  const [mediaDate, setMediaDate] = useState('')
  const [description, setDescription] = useState('')
  const [urls, setUrls] = useState('')
  const [isDragging, setIsDragging] = useState(false)
  const [serverPath, setServerPath] = useState('')
  const [recursive, setRecursive] = useState(false)
  const [directoryPreview, setDirectoryPreview] = useState<{ file_count: number; total_size: number; files: Array<{ name: string; size: number; type: string }>; subdirectories: string[] } | null>(null)
  const [directoryPreviewLoading, setDirectoryPreviewLoading] = useState(false)
  const [directoryPreviewError, setDirectoryPreviewError] = useState<string | null>(null)
  const [selectedExistingMedia, setSelectedExistingMedia] = useState<number[]>([])
  const [uploadProgress, setUploadProgress] = useState<{ loaded: number; total: number; percent: number } | null>(null)
  const [processingJobId, setProcessingJobId] = useState<string | null>(null)
  const [processingItems, setProcessingItems] = useState<ThumbnailProgressItem[]>([])
  const [showProcessingProgress, setShowProcessingProgress] = useState(false)
  const [jobStatusText, setJobStatusText] = useState<string | undefined>()
  const [jobDownloadProgress, setJobDownloadProgress] = useState<{ downloaded: number; total: number } | null>(null)
  const [uploadedPostId, setUploadedPostId] = useState<number | undefined>()

  const { data: tags = [] } = useQuery({
    queryKey: ['private-gallery-tags'],
    queryFn: () => api.privateGallery.getTags(),
    enabled: open,
  })

  const uploadMutation = useMutation({
    mutationFn: (data: {
      files: File[]
      person_id: number
      tag_ids: number[]
      media_date?: string
      description?: string
      onProgress?: (progress: { loaded: number; total: number; percent: number }) => void
    }) => api.privateGallery.upload(data),
    onSuccess: async (result) => {
      setUploadProgress(null)
      if (result.post_id) setUploadedPostId(result.post_id)

      // If there are existing media to attach, use the post_id from the result
      if (selectedExistingMedia.length > 0 && result.post_id) {
        try {
          await api.privateGallery.attachMediaToPost(result.post_id, selectedExistingMedia)
        } catch (err) {
          console.error('Failed to attach existing media:', err)
        }
      }

      // Build processing items and start polling
      const items: ThumbnailProgressItem[] = files.map((f, idx) => ({
        id: `upload-${idx}`,
        filename: f.file.name,
        status: 'pending' as const,
        localPreview: f.preview,
        fileType: f.type === 'video' ? 'video' as const : 'image' as const,
      }))
      setProcessingItems(items)
      setShowProcessingProgress(true)
      setProcessingJobId(result.job_id)
    },
  })

  const createPostMutation = useMutation({
    mutationFn: (data: {
      person_id: number
      tag_ids?: number[]
      media_date?: string
      description?: string
      media_ids?: number[]
    }) => api.privateGallery.createPost(data),
    onSuccess: (result) => {
      queryClient.invalidateQueries({ queryKey: ['private-gallery-media'] })
      queryClient.invalidateQueries({ queryKey: ['private-gallery-albums'] })
      queryClient.invalidateQueries({ queryKey: ['private-gallery-stats'] })
      queryClient.invalidateQueries({ queryKey: ['private-gallery-posts'] })
      const postId = (result as any)?.post_id ?? (result as any)?.id
      setTimeout(() => {
        handleClose()
        onSuccess?.(postId)
      }, 500)
    },
  })

  const importUrlsMutation = useMutation({
    mutationFn: (data: {
      urls: string[]
      person_id: number
      tag_ids: number[]
      media_date?: string
      description?: string
    }) => api.privateGallery.importUrls(data),
    onSuccess: (result) => {
      const parsedUrls = urls.split('\n').map(u => u.trim()).filter(u => u.length > 0)
      const items: ThumbnailProgressItem[] = parsedUrls.map((url, idx) => {
        const urlFilename = url.split('/').pop()?.split('?')[0] || `url-${idx + 1}`
        return {
          id: `import-${idx}`,
          filename: urlFilename,
          status: 'pending' as const,
          fileType: 'image' as const,
        }
      })
      setProcessingItems(items)
      setShowProcessingProgress(true)
      setProcessingJobId(result.job_id)
    },
  })

  const importDirectoryMutation = useMutation({
    mutationFn: (data: {
      directory_path: string
      person_id: number
      tag_ids: number[]
      media_date?: string
      description?: string
      recursive?: boolean
    }) => api.privateGallery.importDirectory(data),
    onSuccess: (result) => {
      const items: ThumbnailProgressItem[] = (directoryPreview?.files || []).map((f, idx) => ({
        id: `dir-${idx}`,
        filename: f.name,
        status: 'pending' as const,
        fileType: f.type === 'video' ? 'video' as const : 'image' as const,
      }))
      setProcessingItems(items)
      setShowProcessingProgress(true)
      setProcessingJobId(result.job_id)
    },
  })


  // Keep session alive during upload/import (large files can take minutes to transfer)
  useEffect(() => {
    if (!uploadMutation.isPending && !importUrlsMutation.isPending && !importDirectoryMutation.isPending && !processingJobId) return

    const keepalive = setInterval(() => {
      api.privateGallery.getStatus().catch(() => {})
    }, 30_000)

    return () => clearInterval(keepalive)
  }, [uploadMutation.isPending, importUrlsMutation.isPending, importDirectoryMutation.isPending, processingJobId])

  // Poll processing job status
  useEffect(() => {
    if (!processingJobId) return

    const pollInterval = setInterval(async () => {
      try {
        const status = await api.privateGallery.getJobStatus(processingJobId)

        const phase = status.current_phase
        setJobStatusText(
          phase === 'resolving' ? 'Resolving forum thread...' :
          phase === 'scraping' ? 'Scraping thread pages...' :
          phase === 'filtering' ? 'Checking for duplicates...' :
          phase === 'downloading' ? 'Downloading...' :
          phase === 'thumbnail' ? 'Generating thumbnail...' :
          phase === 'encrypting' ? 'Encrypting...' :
          phase === 'processing' ? 'Processing...' :
          undefined
        )

        if (phase === 'downloading' && (status.bytes_downloaded > 0 || status.bytes_total > 0)) {
          setJobDownloadProgress({ downloaded: status.bytes_downloaded, total: status.bytes_total })
        } else {
          setJobDownloadProgress(null)
        }

        // Rebuild items when backend resolves thread URLs into individual images
        setProcessingItems(prev => {
          if (status.resolved_filenames && status.resolved_filenames.length > 0 && prev.length !== status.resolved_filenames.length) {
            prev = status.resolved_filenames.map((fname, idx) => ({
              id: `import-${idx}`,
              filename: fname,
              status: 'pending' as const,
              fileType: 'image' as const,
            }))
          }

          return prev.map(item => {
            const result = status.results.find(r => r.filename === item.filename)
            if (result) {
              const mediaId = result.id || result.existing_id
              return {
                ...item,
                status: result.status === 'created' ? 'success'
                  : result.status === 'duplicate' ? 'duplicate'
                  : result.status === 'failed' ? 'error'
                  : item.status,
                error: result.error,
                thumbnailUrl: mediaId
                  ? api.privateGallery.getThumbnailUrl(mediaId)
                  : item.thumbnailUrl,
              }
            }
            if (status.current_file === item.filename) {
              return { ...item, status: phase === 'downloading' ? 'downloading' as const : 'processing' as const }
            }
            return item
          })
        })

        if (status.status === 'completed') {
          clearInterval(pollInterval)
          setProcessingJobId(null)

          queryClient.invalidateQueries({ queryKey: ['private-gallery-media'] })
          queryClient.invalidateQueries({ queryKey: ['private-gallery-albums'] })
          queryClient.invalidateQueries({ queryKey: ['private-gallery-stats'] })
          queryClient.invalidateQueries({ queryKey: ['private-gallery-posts'] })

          if (status.failed_count === 0) {
            const postId = uploadedPostId
            setTimeout(() => {
              handleClose()
              onSuccess?.(postId)
            }, 1500)
          }
        }
      } catch (error) {
        console.error('Error polling job status:', error)
      }
    }, 500)

    return () => clearInterval(pollInterval)
  }, [processingJobId, queryClient, onSuccess, uploadedPostId])

  const handleClose = () => {
    setFiles([])
    setUrls('')
    setServerPath('')
    setRecursive(false)
    setDirectoryPreview(null)
    setDirectoryPreviewLoading(false)
    setDirectoryPreviewError(null)
    setPersonId(undefined)
    setSelectedTags([])
    setTagsManuallyModified(false)
    setMediaDate('')
    setDescription('')
    setSelectedExistingMedia([])
    setUploadProgress(null)
    setProcessingJobId(null)
    setProcessingItems([])
    setShowProcessingProgress(false)
    setJobStatusText(undefined)
    setJobDownloadProgress(null)
    setUploadedPostId(undefined)
    uploadMutation.reset()
    importUrlsMutation.reset()
    importDirectoryMutation.reset()
    onClose()
  }

  const addFiles = useCallback((newFiles: File[]) => {
    const videoExtensions = ['.mkv', '.avi', '.wmv', '.flv', '.webm', '.mov', '.mp4', '.m4v', '.ts']
    const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.tiff', '.avif']

    const mediaFiles = newFiles.filter(file => {
      const type = file.type.toLowerCase()
      const ext = ('.' + file.name.split('.').pop()?.toLowerCase()) || ''
      return type.startsWith('image/') || type.startsWith('video/') || videoExtensions.includes(ext) || imageExtensions.includes(ext)
    })

    const processed: SelectedFile[] = mediaFiles.map(file => {
      const type = file.type.toLowerCase()
      const ext = ('.' + file.name.split('.').pop()?.toLowerCase()) || ''
      const isImage = type.startsWith('image/') || imageExtensions.includes(ext)
      const isVideo = type.startsWith('video/') || videoExtensions.includes(ext)
      return {
        file,
        preview: isImage ? URL.createObjectURL(file) : undefined,
        type: isImage ? 'image' : isVideo ? 'video' : 'other',
      }
    })

    setFiles(prev => [...prev, ...processed])
  }, [])

  const handleFileDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault()
    setIsDragging(false)

    const droppedFiles = Array.from(e.dataTransfer.files)
    addFiles(droppedFiles)
  }, [addFiles])

  const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files) {
      addFiles(Array.from(e.target.files))
    }
  }, [addFiles])

  const removeFile = (index: number) => {
    setFiles(prev => {
      const file = prev[index]
      if (file.preview) {
        URL.revokeObjectURL(file.preview)
      }
      return prev.filter((_, i) => i !== index)
    })
  }

  // Query existing media for the selected person (for attach-existing feature)
  const { data: existingMedia } = useQuery({
    queryKey: ['private-gallery-media', 'person', personId],
    queryFn: () => api.privateGallery.getMedia({ person_id: personId, limit: 500, include_attached: true }),
    enabled: open && personId !== undefined,
  })

  const toggleExistingMedia = (mediaId: number) => {
    setSelectedExistingMedia(prev =>
      prev.includes(mediaId) ? prev.filter(id => id !== mediaId) : [...prev, mediaId]
    )
  }

  const parsedUrls = urls.split('\n').map(u => u.trim()).filter(u => u.length > 0)

  const handleSubmit = () => {
    if (!personId) {
      alert('Please select a person')
      return
    }
    if (files.length === 0 && parsedUrls.length === 0 && selectedExistingMedia.length === 0 && !serverPath) {
      alert('Please select files, enter URLs, enter a server path, or select existing media')
      return
    }

    if (files.length > 0) {
      uploadMutation.mutate({
        files: files.map(f => f.file),
        person_id: personId,
        tag_ids: selectedTags,
        media_date: mediaDate || undefined,
        description: description || undefined,
        onProgress: (progress) => setUploadProgress(progress),
      })
    } else if (serverPath && directoryPreview && directoryPreview.file_count > 0) {
      importDirectoryMutation.mutate({
        directory_path: serverPath,
        person_id: personId,
        tag_ids: selectedTags,
        media_date: mediaDate || undefined,
        description: description || undefined,
        recursive,
      })
    } else if (parsedUrls.length > 0) {
      importUrlsMutation.mutate({
        urls: parsedUrls,
        person_id: personId,
        tag_ids: selectedTags,
        media_date: mediaDate || undefined,
        description: description || undefined,
      })
    } else if (selectedExistingMedia.length > 0) {
      createPostMutation.mutate({
        person_id: personId,
        tag_ids: selectedTags.length > 0 ? selectedTags : undefined,
        media_date: mediaDate || undefined,
        description: description || undefined,
        media_ids: selectedExistingMedia,
      })
    }
  }

  if (!open) return null

  // Show processing progress modal
  if (showProcessingProgress) {
    return (
      <ThumbnailProgressModal
        isOpen={true}
        title={processingItems.some(i => i.id.startsWith('dir-')) ? 'Importing from Server' : processingItems.some(i => i.id.startsWith('import-')) ? 'Importing URLs' : 'Processing Uploads'}
        items={processingItems}
        statusText={jobStatusText}
        downloadProgress={jobDownloadProgress}
        onClose={handleClose}
      />
    )
  }

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm">
      <div className="w-full max-w-2xl bg-card rounded-xl shadow-2xl border border-border max-h-[90vh] flex flex-col">
        {/* Header */}
        <div className="flex items-center justify-between px-4 sm:px-6 py-4 border-b border-border">
          <h2 className="text-lg font-semibold">Upload to Private Gallery</h2>
          <button
            onClick={handleClose}
            className="p-2 rounded-lg hover:bg-secondary transition-colors"
          >
            <X className="w-5 h-5" />
          </button>
        </div>

        {/* Content */}
        <div className="flex-1 overflow-y-auto p-4 sm:p-6 space-y-6">
          {/* Upload Progress Bar (bytes transfer phase) */}
          {uploadMutation.isPending && uploadProgress && (
            <div className="space-y-2">
              <div className="flex items-center justify-between text-sm">
                <span className="text-muted-foreground flex items-center gap-2">
                  <Loader2 className="w-4 h-4 animate-spin" />
                  Uploading files...
                </span>
                <span className="font-medium">{uploadProgress.percent}%</span>
              </div>
              <div className="h-2 bg-secondary rounded-full overflow-hidden">
                <div
                  className="h-full bg-primary transition-all duration-300 rounded-full"
                  style={{ width: `${uploadProgress.percent}%` }}
                />
              </div>
            </div>
          )}

          {/* File Previews - Show first when files exist */}
          {files.length > 0 && !uploadMutation.isPending && (
            <div className="space-y-3">
              <div className="grid grid-cols-3 sm:grid-cols-4 gap-2">
                {files.map((file, index) => (
                  <div key={index} className="relative group aspect-square rounded-lg overflow-hidden bg-secondary">
                    {file.type === 'image' && file.preview ? (
                      <img
                        src={file.preview}
                        alt={file.file.name}
                        className="w-full h-full object-cover"
                      />
                    ) : (
                      <div className="w-full h-full flex items-center justify-center">
                        {file.type === 'video' ? (
                          <Video className="w-8 h-8 text-muted-foreground" />
                        ) : (
                          <ImageIcon className="w-8 h-8 text-muted-foreground" />
                        )}
                      </div>
                    )}
                    <button
                      onClick={(e) => {
                        e.stopPropagation()
                        removeFile(index)
                      }}
                      className="absolute top-1 right-1 p-1.5 rounded-full bg-destructive text-destructive-foreground opacity-0 group-hover:opacity-100 transition-opacity"
                    >
                      <Trash2 className="w-3 h-3" />
                    </button>
                    <div className="absolute inset-x-0 bottom-0 p-1.5 bg-gradient-to-t from-black/80 to-transparent">
                      <p className="text-xs text-white truncate">{file.file.name}</p>
                    </div>
                  </div>
                ))}
                {/* Add more button */}
                <div
                  onClick={() => fileInputRef.current?.click()}
                  className="aspect-square rounded-lg border-2 border-dashed border-border hover:border-primary/50 flex items-center justify-center cursor-pointer transition-colors"
                >
                  <Upload className="w-6 h-6 text-muted-foreground" />
                </div>
              </div>
            </div>
          )}

          {/* Drop Zone - Only show large when no files */}
          {files.length === 0 && !uploadMutation.isPending && (
            <div
              onDragOver={(e) => {
                e.preventDefault()
                setIsDragging(true)
              }}
              onDragLeave={() => setIsDragging(false)}
              onDrop={handleFileDrop}
              onClick={() => fileInputRef.current?.click()}
              className={`border-2 border-dashed rounded-xl p-8 text-center cursor-pointer transition-colors ${
                isDragging
                  ? 'border-primary bg-primary/10'
                  : 'border-border hover:border-primary/50 hover:bg-secondary/50'
              }`}
            >
              <Upload className="w-10 h-10 mx-auto mb-3 text-muted-foreground" />
              <p className="text-foreground font-medium">
                Drag and drop files here, or click to select
              </p>
              <p className="text-sm text-muted-foreground mt-1">
                Supports images and videos
              </p>
            </div>
          )}

          <input
            ref={fileInputRef}
            type="file"
            multiple
            accept="image/*,video/*,.mkv,.avi,.wmv,.flv,.webm,.mov,.m4v,.ts"
            onChange={handleFileSelect}
            className="hidden"
          />

          {/* URL Import */}
          {files.length === 0 && !serverPath && !uploadMutation.isPending && !importUrlsMutation.isPending && !importDirectoryMutation.isPending && (
            <div>
              <label className="flex items-center gap-2 text-sm font-medium mb-2">
                <Link className="w-4 h-4" />
                Or import from URLs
              </label>
              <textarea
                value={urls}
                onChange={(e) => setUrls(e.target.value)}
                rows={3}
                className="w-full px-4 py-2.5 rounded-lg border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary resize-none text-sm"
                placeholder={"Paste URLs here (one per line)\nSupports Bunkr, Pixeldrain, Gofile, Cyberdrop, or direct image/video links"}
              />
            </div>
          )}

          {/* Server Directory Import */}
          {files.length === 0 && parsedUrls.length === 0 && !uploadMutation.isPending && !importUrlsMutation.isPending && !importDirectoryMutation.isPending && (
            <div>
              <label className="flex items-center gap-2 text-sm font-medium mb-2">
                <FolderOpen className="w-4 h-4" />
                Or import from server path
              </label>
              <div className="flex gap-2">
                <input
                  type="text"
                  value={serverPath}
                  onChange={(e) => {
                    setServerPath(e.target.value)
                    setDirectoryPreview(null)
                    setDirectoryPreviewError(null)
                  }}
                  className="flex-1 px-4 py-2.5 rounded-lg border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary text-sm"
                  placeholder="/path/to/media/folder"
                />
                <button
                  type="button"
                  onClick={async () => {
                    if (!serverPath.trim()) return
                    setDirectoryPreviewLoading(true)
                    setDirectoryPreviewError(null)
                    try {
                      const result = await api.privateGallery.listDirectory(serverPath.trim(), recursive)
                      setDirectoryPreview(result)
                    } catch (err: any) {
                      setDirectoryPreviewError(err.message || 'Failed to list directory')
                      setDirectoryPreview(null)
                    } finally {
                      setDirectoryPreviewLoading(false)
                    }
                  }}
                  disabled={!serverPath.trim() || directoryPreviewLoading}
                  className="px-4 py-2.5 rounded-lg bg-secondary hover:bg-secondary/80 text-sm font-medium disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
                >
                  {directoryPreviewLoading ? <Loader2 className="w-4 h-4 animate-spin" /> : 'Scan'}
                </button>
              </div>

              <label className="flex items-center gap-2 mt-2 text-sm text-muted-foreground cursor-pointer">
                <input
                  type="checkbox"
                  checked={recursive}
                  onChange={async (e) => {
                    const newRecursive = e.target.checked
                    setRecursive(newRecursive)
                    if (serverPath.trim()) {
                      setDirectoryPreviewLoading(true)
                      setDirectoryPreviewError(null)
                      try {
                        const result = await api.privateGallery.listDirectory(serverPath.trim(), newRecursive)
                        setDirectoryPreview(result)
                      } catch (err: any) {
                        setDirectoryPreviewError(err.message || 'Failed to list directory')
                        setDirectoryPreview(null)
                      } finally {
                        setDirectoryPreviewLoading(false)
                      }
                    } else {
                      setDirectoryPreview(null)
                    }
                  }}
                  className="rounded border-border"
                />
                Include subdirectories (recursive)
              </label>

              {directoryPreviewError && (
                <p className="text-sm text-destructive mt-2">{directoryPreviewError}</p>
              )}

              {directoryPreview && (
                <div className="mt-2 p-3 rounded-lg bg-secondary/50 border border-border text-sm">
                  <div className="flex items-center justify-between">
                    <span className="font-medium">
                      {directoryPreview.file_count} media {directoryPreview.file_count === 1 ? 'file' : 'files'} found
                    </span>
                    <span className="text-muted-foreground">
                      {directoryPreview.total_size < 1024 * 1024
                        ? `${(directoryPreview.total_size / 1024).toFixed(1)} KB`
                        : directoryPreview.total_size < 1024 * 1024 * 1024
                          ? `${(directoryPreview.total_size / (1024 * 1024)).toFixed(1)} MB`
                          : `${(directoryPreview.total_size / (1024 * 1024 * 1024)).toFixed(2)} GB`}
                    </span>
                  </div>
                  {directoryPreview.subdirectories.length > 0 && !recursive && (
                    <p className="text-muted-foreground mt-1">
                      {directoryPreview.subdirectories.length} subdirector{directoryPreview.subdirectories.length === 1 ? 'y' : 'ies'} (enable recursive to include)
                    </p>
                  )}
                </div>
              )}
            </div>
          )}

          {/* Person Selector */}
          {!uploadMutation.isPending && !importUrlsMutation.isPending && !importDirectoryMutation.isPending && (
            <>
              <div>
                <label className="flex items-center gap-2 text-sm font-medium mb-2">
                  <span className="text-red-500">*</span>
                  Person
                </label>
                <PersonSelector
                  value={personId}
                  onChange={(id, person) => {
                    setPersonId(id)
                    setSelectedExistingMedia([])
                    // Auto-populate tags from person defaults if not manually modified
                    if (!tagsManuallyModified && person?.default_tag_ids?.length) {
                      setSelectedTags(person.default_tag_ids)
                    }
                  }}
                  required
                />
              </div>

              {/* Attach Existing Media */}
              {personId && existingMedia?.items && (existingMedia.items as Array<{ id: number; filename: string; file_type: string }>).length > 0 && (
                <div>
                  <label className="flex items-center gap-2 text-sm font-medium mb-2">
                    <ImageIcon className="w-4 h-4" />
                    Attach existing media ({selectedExistingMedia.length} selected)
                  </label>
                  <div className="grid grid-cols-4 sm:grid-cols-6 gap-1.5 max-h-40 overflow-y-auto p-1 rounded-lg border border-border bg-background">
                    {(existingMedia.items as Array<{ id: number; filename: string; file_type: string }>).map((item) => (
                      <button
                        key={item.id}
                        type="button"
                        onClick={() => toggleExistingMedia(item.id)}
                        className={`relative aspect-square rounded overflow-hidden border-2 transition-colors ${
                          selectedExistingMedia.includes(item.id)
                            ? 'border-primary ring-1 ring-primary'
                            : 'border-transparent hover:border-primary/30'
                        }`}
                      >
                        <img
                          src={api.privateGallery.getThumbnailUrl(item.id)}
                          alt={item.filename}
                          className="w-full h-full object-cover"
                        />
                        {item.file_type === 'video' && (
                          <div className="absolute bottom-0.5 left-0.5 bg-black/70 rounded px-1">
                            <Video className="w-3 h-3 text-white" />
                          </div>
                        )}
                        {selectedExistingMedia.includes(item.id) && (
                          <div className="absolute inset-0 bg-primary/20 flex items-center justify-center">
                            <CheckCircle className="w-5 h-5 text-primary" />
                          </div>
                        )}
                      </button>
                    ))}
                  </div>
                </div>
              )}

              {/* Tags */}
              <TagSearchSelector
                tags={tags}
                selectedTagIds={selectedTags}
                onChange={(ids) => {
                  setTagsManuallyModified(true)
                  setSelectedTags(ids)
                }}
                label="Tags (optional)"
              />

              {/* Date */}
              <div>
                <label className="flex items-center gap-2 text-sm font-medium mb-2">
                  <Calendar className="w-4 h-4" />
                  Date (optional)
                </label>
                <input
                  type="date"
                  value={mediaDate}
                  onChange={(e) => setMediaDate(e.target.value)}
                  className="w-full px-4 py-2.5 rounded-lg border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary"
                />
                <p className="text-xs text-muted-foreground mt-1">
                  Leave empty to auto-detect from EXIF or filename
                </p>
              </div>

              {/* Description */}
              <div>
                <label className="flex items-center gap-2 text-sm font-medium mb-2">
                  <FileText className="w-4 h-4" />
                  Description (optional)
                </label>
                <textarea
                  value={description}
                  onChange={(e) => setDescription(e.target.value)}
                  rows={2}
                  className="w-full px-4 py-2.5 rounded-lg border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary resize-none"
                  placeholder="Add a description..."
                />
              </div>
            </>
          )}
        </div>

        {/* Footer */}
        <div className="flex flex-col-reverse sm:flex-row sm:items-center sm:justify-between gap-3 px-4 sm:px-6 py-4 border-t border-border">
          <p className="text-sm text-muted-foreground text-center sm:text-left">
            {files.length > 0
              ? `${files.length} ${files.length === 1 ? 'file' : 'files'} selected`
              : directoryPreview && directoryPreview.file_count > 0
                ? `${directoryPreview.file_count} ${directoryPreview.file_count === 1 ? 'file' : 'files'} in directory`
                : parsedUrls.length > 0
                  ? `${parsedUrls.length} ${parsedUrls.length === 1 ? 'URL' : 'URLs'} entered`
                  : `0 files selected`}
            {selectedExistingMedia.length > 0 ? ` + ${selectedExistingMedia.length} existing` : ''}
          </p>
          <div className="flex gap-3">
            <button
              onClick={handleClose}
              className="flex-1 sm:flex-none px-4 py-2 rounded-lg border border-border hover:bg-secondary transition-colors"
            >
              Cancel
            </button>
            <button
              onClick={handleSubmit}
              disabled={uploadMutation.isPending || createPostMutation.isPending || importUrlsMutation.isPending || importDirectoryMutation.isPending || (files.length === 0 && parsedUrls.length === 0 && selectedExistingMedia.length === 0 && !(serverPath && directoryPreview && directoryPreview.file_count > 0)) || !personId}
              className="flex-1 sm:flex-none px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 transition-colors"
            >
              {(uploadMutation.isPending || createPostMutation.isPending || importUrlsMutation.isPending || importDirectoryMutation.isPending) ? (
                <>
                  <Loader2 className="w-4 h-4 animate-spin" />
                  {createPostMutation.isPending ? 'Creating...' : importUrlsMutation.isPending ? 'Importing...' : importDirectoryMutation.isPending ? 'Importing...' : 'Uploading...'}
                </>
              ) : (
                <>
                  {serverPath && directoryPreview ? (
                    <FolderOpen className="w-4 h-4" />
                  ) : parsedUrls.length > 0 && files.length === 0 ? (
                    <Link className="w-4 h-4" />
                  ) : (
                    <Upload className="w-4 h-4" />
                  )}
                  {files.length > 0 ? 'Upload' : serverPath && directoryPreview ? 'Import' : parsedUrls.length > 0 ? 'Import' : selectedExistingMedia.length > 0 ? 'Create Post' : 'Upload'}
                </>
              )}
            </button>
          </div>
        </div>
      </div>
    </div>
  )
}

export default PrivateGalleryUploadModal
