import { useState, useEffect, useCallback, useRef } from 'react'
import { getGalleryFolders, getGalleryFiles, getSettings, deleteMediaFile, markGallerySeen } from '../api'
import Spinner from '../components/Spinner'
import LoadMoreButton from '../components/LoadMoreButton'
import HlsVideo from '../components/HlsVideo'
import GridWall, { GridWallPicker } from '../components/GridWall'

const PAGE_SIZE = 50

function GalleryThumbnail({ file }) {
  const [loaded, setLoaded] = useState(false)
  const [errored, setErrored] = useState(false)
  const [retries, setRetries] = useState(0)

  const imgSrc = `/api/gallery/thumb/${encodeURIComponent(file.folder)}/${encodeURIComponent(file.filename)}${retries > 0 ? `?r=${retries}` : ''}`

  // Images — lazy load with retry
  const handleError = () => {
    if (retries < 4) {
      setTimeout(() => setRetries(r => r + 1), 2000 + retries * 2000)
    } else {
      setErrored(true)
    }
  }

  return (
    <>
      {!loaded && !errored && (
        <div className="absolute inset-0 bg-[#1a1a1a] animate-pulse" />
      )}
      {errored ? (
        <div className="w-full h-full bg-[#1a1a1a] flex items-center justify-center">
          {file.type === 'video' ? (
            <svg className="w-10 h-10 text-white/20" fill="currentColor" viewBox="0 0 24 24">
              <path d="M8 5v14l11-7z" />
            </svg>
          ) : (
            <svg className="w-6 h-6 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
              <path strokeLinecap="round" strokeLinejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909M18 3.75H6A2.25 2.25 0 003.75 6v12A2.25 2.25 0 006 20.25h12A2.25 2.25 0 0020.25 18V6A2.25 2.25 0 0018 3.75z" />
            </svg>
          )}
        </div>
      ) : (
        <img
          key={retries}
          src={imgSrc}
          alt=""
          loading="lazy"
          onLoad={() => setLoaded(true)}
          onError={handleError}
          className={`w-full h-full object-cover transition-opacity duration-300 ${loaded ? 'opacity-100' : 'opacity-0'}`}
        />
      )}
    </>
  )
}

function formatShortDate(dateStr) {
  if (!dateStr) return ''
  const d = new Date(dateStr)
  return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
}

const TYPE_OPTIONS = [
  { value: 'all', label: 'All' },
  { value: 'image', label: 'Images' },
  { value: 'video', label: 'Videos' },
]

const SORT_OPTIONS = [
  { value: 'latest', label: 'Latest' },
  { value: 'oldest', label: 'Oldest' },
  { value: 'largest', label: 'Largest' },
  { value: 'smallest', label: 'Smallest' },
  { value: 'name', label: 'Name' },
  { value: 'shuffle', label: 'Shuffle' },
]

function VideoPreviewThumbnail({ file, children }) {
  const [hovering, setHovering] = useState(false)
  const videoRef = useRef(null)
  const hoverTimerRef = useRef(null)
  const stopTimerRef = useRef(null)
  const isTouchDevice = typeof window !== 'undefined' && 'ontouchstart' in window

  if (file.type !== 'video' || isTouchDevice) return children

  const handleMouseEnter = () => {
    hoverTimerRef.current = setTimeout(() => setHovering(true), 400)
  }

  const handleMouseLeave = () => {
    clearTimeout(hoverTimerRef.current)
    clearTimeout(stopTimerRef.current)
    setHovering(false)
    if (videoRef.current) {
      videoRef.current.pause()
      videoRef.current.removeAttribute('src')
      videoRef.current.load()
    }
  }

  const handleLoadedMetadata = () => {
    const video = videoRef.current
    if (!video) return
    if (video.duration > 15) {
      video.currentTime = video.duration / 2
      stopTimerRef.current = setTimeout(() => {
        if (videoRef.current) {
          videoRef.current.pause()
        }
      }, 7000)
    }
  }

  return (
    <div onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} className="relative w-full h-full">
      {children}
      {hovering && (
        <video
          ref={videoRef}
          src={`/api/gallery/media/${encodeURIComponent(file.folder)}/${encodeURIComponent(file.filename)}`}
          muted
          autoPlay
          playsInline
          onLoadedMetadata={handleLoadedMetadata}
          className="absolute inset-0 w-full h-full object-cover z-[5]"
        />
      )}
    </div>
  )
}

function SortDropdown({ value, onChange }) {
  const [open, setOpen] = useState(false)
  const ref = useRef(null)
  const current = SORT_OPTIONS.find((o) => o.value === value)

  useEffect(() => {
    if (!open) return
    const handleClick = (e) => {
      if (ref.current && !ref.current.contains(e.target)) setOpen(false)
    }
    document.addEventListener('mousedown', handleClick)
    return () => document.removeEventListener('mousedown', handleClick)
  }, [open])

  return (
    <div className="relative" ref={ref}>
      <button
        onClick={() => setOpen((v) => !v)}
        className="flex items-center gap-2 px-3 py-2 text-sm rounded-lg border border-[#333] bg-[#161616] text-gray-400 hover:text-white transition-colors"
      >
        {current?.label || 'Sort'}
        <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
          <path strokeLinecap="round" strokeLinejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
        </svg>
      </button>
      {open && (
        <div className="absolute top-full left-0 mt-1 w-36 bg-[#1a1a1a] border border-[#333] rounded-lg shadow-xl z-50 overflow-hidden py-1">
          {SORT_OPTIONS.map((opt) => (
            <button
              key={opt.value}
              onClick={() => { onChange(opt.value); setOpen(false) }}
              className={`w-full text-left px-3 py-2 text-sm transition-colors ${
                opt.value === value
                  ? 'text-[#0095f6] bg-[#0095f6]/10'
                  : 'text-gray-400 hover:text-white hover:bg-[#252525]'
              }`}
            >
              {opt.label}
            </button>
          ))}
        </div>
      )}
    </div>
  )
}

export default function Gallery() {
  const [folders, setFolders] = useState([])
  const [files, setFiles] = useState([])
  const [total, setTotal] = useState(0)
  const [loading, setLoading] = useState(true)
  const [loadingMore, setLoadingMore] = useState(false)
  const [error, setError] = useState(null)

  const [activeFolder, setActiveFolder] = useState(null) // kept for API compat
  const [checkedFolders, setCheckedFolders] = useState(new Set())
  const [typeFilter, setTypeFilter] = useState('all')
  const [sortOption, setSortOption] = useState('latest')
  const [lightboxIndex, setLightboxIndex] = useState(null)
  const [slideshow, setSlideshow] = useState(false)
  const [hlsEnabled, setHlsEnabled] = useState(false)
  const [userFilterOpen, setUserFilterOpen] = useState(false)
  const [userSearch, setUserSearch] = useState('')
  const [filtersExpanded, setFiltersExpanded] = useState(false)
  const [dateFrom, setDateFrom] = useState('')
  const [dateTo, setDateTo] = useState('')
  const [searchText, setSearchText] = useState('')
  const [gridWallLayout, setGridWallLayout] = useState(null)
  const [gridPickerOpen, setGridPickerOpen] = useState(false)
  const gridPickerRef = useRef(null)
  const filterRef = useRef(null)

  useEffect(() => {
    getSettings().then((data) => {
      if (!data.error) setHlsEnabled(data.hls_enabled === 'true')
    })
    getGalleryFolders().then((data) => {
      if (!data.error) setFolders(Array.isArray(data) ? data : [])
    })
    markGallerySeen()
  }, [])

  // Close popover on click outside
  useEffect(() => {
    if (!userFilterOpen) return
    const handleClick = (e) => {
      if (filterRef.current && !filterRef.current.contains(e.target)) {
        setUserFilterOpen(false)
        setUserSearch('')
      }
    }
    document.addEventListener('mousedown', handleClick)
    return () => document.removeEventListener('mousedown', handleClick)
  }, [userFilterOpen])

  const togglePill = (name) => {
    setActiveFolder(null)
    setCheckedFolders((prev) => {
      const next = new Set(prev)
      if (next.has(name)) next.delete(name)
      else next.add(name)
      return next
    })
  }

  const clearFilters = () => {
    setActiveFolder(null)
    setCheckedFolders(new Set())
  }

  // Build the folder/folders param for the API
  // Checked folders take priority over active (clicked) folder
  const getFilterParams = useCallback(() => {
    if (checkedFolders.size > 0) {
      return { folders: Array.from(checkedFolders) }
    }
    if (activeFolder) {
      return { folder: activeFolder }
    }
    return {}
  }, [activeFolder, checkedFolders])

  const loadFiles = useCallback(async (reset = true) => {
    if (reset) {
      setLoading(true)
      setError(null)
    } else {
      setLoadingMore(true)
    }

    const offset = reset ? 0 : files.length
    const data = await getGalleryFiles({
      ...getFilterParams(),
      type: typeFilter !== 'all' ? typeFilter : undefined,
      sort: sortOption,
      offset,
      limit: PAGE_SIZE,
      dateFrom: dateFrom || undefined,
      dateTo: dateTo || undefined,
      search: searchText || undefined,
    })

    if (data.error) {
      setError(data.error)
    } else {
      setFiles((prev) => (reset ? data.files : [...prev, ...data.files]))
      setTotal(data.total)
    }

    setLoading(false)
    setLoadingMore(false)
  }, [getFilterParams, typeFilter, sortOption, dateFrom, dateTo, searchText, files.length])

  useEffect(() => {
    loadFiles(true)
  }, [activeFolder, checkedFolders, typeFilter, sortOption, dateFrom, dateTo, searchText])

  const handleReshuffle = () => {
    loadFiles(true)
  }

  // Grid wall: fetch shuffled items from current filter
  const fetchGridItems = useCallback(async (limit) => {
    const data = await getGalleryFiles({
      ...getFilterParams(),
      type: typeFilter !== 'all' ? typeFilter : undefined,
      sort: 'shuffle',
      limit,
      dateFrom: dateFrom || undefined,
      dateTo: dateTo || undefined,
      search: searchText || undefined,
    })
    return data.error ? [] : data.files
  }, [getFilterParams, typeFilter, dateFrom, dateTo, searchText])

  const hasAdvancedFilters = dateFrom || dateTo || searchText
  const clearAdvancedFilters = () => {
    setDateFrom('')
    setDateTo('')
    setSearchText('')
  }

  const hasMore = files.length < total

  return (
    <div>
      {/* Header */}
      <div className="mb-4">
        <div className="flex items-baseline justify-between">
          <h1 className="text-xl md:text-2xl font-bold text-white">Gallery</h1>
          <p className="text-gray-500 text-sm">
            {total} file{total !== 1 ? 's' : ''}{checkedFolders.size === 0 ? ' saved locally' : ''}
          </p>
        </div>
      </div>

      {/* Filters */}
      <div className="flex flex-wrap items-center gap-2 md:gap-3 mb-4 md:mb-6">
        {/* User Filter Popover */}
        <div className="relative" ref={filterRef}>
          <button
            onClick={() => { setUserFilterOpen((v) => !v); setUserSearch('') }}
            className={`flex items-center gap-2 px-3 py-2 text-sm rounded-lg border transition-colors ${
              checkedFolders.size > 0
                ? 'border-[#0095f6] bg-[#0095f6]/10 text-[#0095f6]'
                : 'border-[#333] bg-[#161616] text-gray-400 hover:text-white'
            }`}
          >
            <UsersFilterIcon className="w-4 h-4" />
            Users
            {checkedFolders.size > 0 && (
              <span className="bg-[#0095f6] text-white text-xs rounded-full w-5 h-5 flex items-center justify-center font-medium">
                {checkedFolders.size}
              </span>
            )}
          </button>

          {userFilterOpen && (
            <div className="absolute top-full left-0 mt-2 w-64 bg-[#1a1a1a] border border-[#333] rounded-lg shadow-xl z-50 overflow-hidden">
              {/* Search */}
              <div className="p-2 border-b border-[#333]">
                <input
                  type="text"
                  value={userSearch}
                  onChange={(e) => setUserSearch(e.target.value)}
                  placeholder="Search users..."
                  autoFocus
                  className="w-full px-3 py-1.5 bg-[#111] border border-[#333] rounded-md text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#0095f6]"
                />
              </div>

              {/* List */}
              <div className="max-h-72 overflow-y-auto">
                {folders
                  .filter((f) => f.name.toLowerCase().includes(userSearch.toLowerCase()))
                  .map((f) => (
                    <button
                      key={f.name}
                      onClick={() => togglePill(f.name)}
                      className="w-full flex items-center gap-3 px-3 py-2 hover:bg-[#252525] transition-colors text-left"
                    >
                      <div className={`w-4 h-4 rounded border flex-shrink-0 flex items-center justify-center ${
                        checkedFolders.has(f.name)
                          ? 'bg-[#0095f6] border-[#0095f6]'
                          : 'border-[#555]'
                      }`}>
                        {checkedFolders.has(f.name) && (
                          <svg className="w-3 h-3 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={3}>
                            <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
                          </svg>
                        )}
                      </div>
                      <span className="text-sm text-gray-300 truncate flex-1">{f.name}</span>
                      <span className="text-xs text-gray-600 flex-shrink-0">{f.total}</span>
                    </button>
                  ))}
              </div>

              {/* Footer */}
              {checkedFolders.size > 0 && (
                <div className="p-2 border-t border-[#333]">
                  <button
                    onClick={() => { clearFilters(); setUserFilterOpen(false) }}
                    className="w-full py-1.5 text-xs text-gray-400 hover:text-white transition-colors"
                  >
                    Clear all
                  </button>
                </div>
              )}
            </div>
          )}
        </div>

        {/* Selected user tags */}
        {checkedFolders.size > 0 && checkedFolders.size <= 5 && (
          Array.from(checkedFolders).map((name) => (
            <span
              key={name}
              className="flex items-center gap-1.5 px-2.5 py-1.5 text-xs bg-[#0095f6]/10 text-[#0095f6] rounded-lg border border-[#0095f6]/30"
            >
              {name}
              <button
                onClick={() => togglePill(name)}
                className="hover:text-white transition-colors"
              >
                <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={3}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
                </svg>
              </button>
            </span>
          ))
        )}

        {/* Type Filter */}
        <div className="flex rounded-lg overflow-hidden border border-[#333]">
          {TYPE_OPTIONS.map((opt) => (
            <button
              key={opt.value}
              onClick={() => setTypeFilter(opt.value)}
              className={`px-3 py-2 text-sm transition-colors ${
                typeFilter === opt.value
                  ? 'bg-[#0095f6] text-white'
                  : 'bg-[#161616] text-gray-400 hover:text-white'
              }`}
            >
              {opt.label}
            </button>
          ))}
        </div>

        {/* Sort Dropdown */}
        <SortDropdown value={sortOption} onChange={setSortOption} />

        {/* Reshuffle Button */}
        {sortOption === 'shuffle' && (
          <button
            onClick={handleReshuffle}
            className="flex items-center gap-2 px-3 py-2 text-sm rounded-lg border border-[#333] bg-[#161616] text-gray-400 hover:text-white transition-colors"
          >
            <RefreshIcon className="w-4 h-4" />
            Reshuffle
          </button>
        )}

        {/* Filters Toggle */}
        <button
          onClick={() => setFiltersExpanded((v) => !v)}
          className={`relative flex items-center gap-2 px-3 py-2 text-sm rounded-lg border transition-colors ${
            filtersExpanded || hasAdvancedFilters
              ? 'border-[#0095f6] bg-[#0095f6]/10 text-[#0095f6]'
              : 'border-[#333] bg-[#161616] text-gray-400 hover:text-white'
          }`}
        >
          <FilterIcon className="w-4 h-4" />
          Filters
          {hasAdvancedFilters && (
            <span className="w-2 h-2 rounded-full bg-[#0095f6] absolute -top-0.5 -right-0.5" />
          )}
        </button>

        {/* Slideshow Button */}
        <button
          onClick={() => setSlideshow(true)}
          className="flex items-center gap-2 px-3 py-2 text-sm rounded-lg border border-[#333] bg-[#161616] text-gray-400 hover:text-white transition-colors"
        >
          <SlideshowIcon className="w-4 h-4" />
          Slideshow
        </button>

        {/* Grid Wall Button */}
        <div className="relative" ref={gridPickerRef}>
          <button
            onClick={() => setGridPickerOpen(v => !v)}
            className="flex items-center gap-2 px-3 py-2 text-sm rounded-lg border border-[#333] bg-[#161616] text-gray-400 hover:text-white transition-colors"
          >
            <GridWallIcon className="w-4 h-4" />
            Grid Wall
          </button>
          {gridPickerOpen && (
            <GridWallPicker
              onSelect={(layout) => { setGridWallLayout(layout); setGridPickerOpen(false) }}
              onClose={() => setGridPickerOpen(false)}
            />
          )}
        </div>
      </div>

      {/* Advanced Filters Panel */}
      {filtersExpanded && (
        <div className="flex flex-wrap items-end gap-3 mb-4 p-3 bg-[#161616] border border-[#222] rounded-lg">
          <div>
            <label className="block text-xs text-gray-500 mb-1">From</label>
            <input
              type="date"
              value={dateFrom}
              onChange={(e) => setDateFrom(e.target.value)}
              className="px-2.5 py-1.5 text-sm rounded-md border border-[#333] bg-[#111] text-gray-300 focus:outline-none focus:border-[#0095f6]"
            />
          </div>
          <div>
            <label className="block text-xs text-gray-500 mb-1">To</label>
            <input
              type="date"
              value={dateTo}
              onChange={(e) => setDateTo(e.target.value)}
              className="px-2.5 py-1.5 text-sm rounded-md border border-[#333] bg-[#111] text-gray-300 focus:outline-none focus:border-[#0095f6]"
            />
          </div>
          <div className="flex-1 min-w-[150px]">
            <label className="block text-xs text-gray-500 mb-1">Search</label>
            <input
              type="text"
              value={searchText}
              onChange={(e) => setSearchText(e.target.value)}
              placeholder="Filename or folder..."
              className="w-full px-2.5 py-1.5 text-sm rounded-md border border-[#333] bg-[#111] text-gray-300 placeholder-gray-600 focus:outline-none focus:border-[#0095f6]"
            />
          </div>
          {hasAdvancedFilters && (
            <button
              onClick={clearAdvancedFilters}
              className="px-3 py-1.5 text-xs text-gray-400 hover:text-white border border-[#333] rounded-md transition-colors"
            >
              Clear
            </button>
          )}
        </div>
      )}

      {loading ? (
        <Spinner />
      ) : error ? (
        <div className="text-center py-12">
          <p className="text-red-400 mb-4">{error}</p>
        </div>
      ) : files.length === 0 ? (
        <div className="text-center py-16 bg-[#161616] border border-[#222] rounded-lg">
          <GalleryIcon className="w-12 h-12 text-gray-600 mx-auto mb-3" />
          <p className="text-gray-500 text-sm">No media files found</p>
          <p className="text-gray-600 text-xs mt-1">
            Download media from the Users or Search page
          </p>
        </div>
      ) : (
        <>
          <div className="grid grid-cols-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-1 md:gap-2">
            {files.map((file, i) => (
              <div
                key={`${file.folder}-${file.filename}-${i}`}
                className="relative group bg-[#161616] rounded-lg overflow-hidden cursor-pointer aspect-square"
                onClick={() => setLightboxIndex(i)}
              >
                <VideoPreviewThumbnail file={file}>
                  <GalleryThumbnail file={file} />
                </VideoPreviewThumbnail>

                {/* Date badge */}
                {file.postedAt && (
                  <div className="absolute top-2 left-2">
                    <span className="bg-black/50 text-white/80 text-[10px] px-1.5 py-0.5 rounded">
                      {formatShortDate(file.postedAt)}
                    </span>
                  </div>
                )}

                {/* Delete button */}
                <button
                  onClick={(e) => {
                    e.stopPropagation()
                    deleteMediaFile(file.folder, file.filename).then((res) => {
                      if (!res.error) setFiles((prev) => prev.filter((_, idx) => idx !== i))
                    })
                  }}
                  className="absolute top-2 right-2 p-1.5 bg-black/60 hover:bg-red-500/80 rounded-full text-white/70 hover:text-white opacity-0 group-hover:opacity-100 transition-all z-10"
                  title="Delete"
                >
                  <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                    <path strokeLinecap="round" strokeLinejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
                  </svg>
                </button>

                {/* Overlay */}
                <div className="absolute inset-0 bg-black/0 group-hover:bg-black/40 transition-colors flex items-end pointer-events-none">
                  <div className="w-full p-2 opacity-0 group-hover:opacity-100 transition-opacity">
                    <p className="text-xs text-white truncate">@{file.folder}</p>
                  </div>
                </div>

                {/* Video badge */}
                {file.type === 'video' && (
                  <div className="absolute bottom-2 right-2 pointer-events-none">
                    <svg className="w-5 h-5 text-white drop-shadow-lg" fill="currentColor" viewBox="0 0 24 24">
                      <path d="M8 5v14l11-7z" />
                    </svg>
                  </div>
                )}
              </div>
            ))}
          </div>

          <div className="mt-6">
            <LoadMoreButton
              onClick={() => loadFiles(false)}
              loading={loadingMore}
              hasMore={hasMore}
            />
          </div>
        </>
      )}

      {/* Lightbox */}
      {lightboxIndex !== null && files[lightboxIndex] && (
        <Lightbox
          files={files}
          index={lightboxIndex}
          setIndex={setLightboxIndex}
          hlsEnabled={hlsEnabled}
          onClose={() => setLightboxIndex(null)}
          hasMore={hasMore}
          onLoadMore={() => loadFiles(false)}
          onDelete={async (i) => {
            const f = files[i]
            const res = await deleteMediaFile(f.folder, f.filename)
            if (!res.error) {
              const newFiles = files.filter((_, idx) => idx !== i)
              setFiles(newFiles)
              if (newFiles.length === 0) {
                setLightboxIndex(null)
              } else if (i >= newFiles.length) {
                setLightboxIndex(newFiles.length - 1)
              }
            }
          }}
        />
      )}

      {/* Slideshow */}
      {slideshow && (
        <Slideshow
          filterParams={getFilterParams()}
          typeFilter={typeFilter}
          sortOption={sortOption}
          hlsEnabled={hlsEnabled}
          onClose={() => setSlideshow(false)}
        />
      )}

      {/* Grid Wall */}
      {gridWallLayout && (
        <GridWall
          layout={gridWallLayout}
          fetchItems={fetchGridItems}
          hlsEnabled={hlsEnabled}
          onClose={() => setGridWallLayout(null)}
        />
      )}
    </div>
  )
}

function Lightbox({ files, index, setIndex, hlsEnabled, onClose, onDelete, hasMore, onLoadMore }) {
  const file = files[index]
  const hasPrev = index > 0
  const hasNext = index < files.length - 1 || hasMore
  const loadingMoreRef = useRef(false)

  // Auto-load more files when navigating near the end
  useEffect(() => {
    if (hasMore && index >= files.length - 5 && !loadingMoreRef.current) {
      loadingMoreRef.current = true
      onLoadMore()
      setTimeout(() => { loadingMoreRef.current = false }, 1000)
    }
  }, [index, files.length, hasMore, onLoadMore])

  useEffect(() => {
    const handleKey = (e) => {
      if (e.key === 'Escape') onClose()
      if (e.key === 'ArrowRight' && hasNext) setIndex(index + 1)
      if (e.key === 'ArrowLeft' && hasPrev) setIndex(index - 1)
    }
    window.addEventListener('keydown', handleKey)
    return () => window.removeEventListener('keydown', handleKey)
  }, [onClose, index, hasPrev, hasNext, setIndex])

  return (
    <div
      className="fixed inset-0 z-[100] bg-black/90 flex items-center justify-center"
      onClick={onClose}
    >
      <div className="absolute top-4 right-4 flex items-center gap-3 z-10">
        <a
          href={file.url}
          target="_blank"
          rel="noopener noreferrer"
          onClick={(e) => e.stopPropagation()}
          className="p-2 bg-white/10 hover:bg-white/20 rounded-full text-white transition-colors"
          title="Open in new window"
        >
          <svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" />
          </svg>
        </a>
        <button
          onClick={(e) => { e.stopPropagation(); onDelete(index) }}
          className="p-2 bg-white/10 hover:bg-red-500/70 rounded-full text-white transition-colors"
          title="Delete"
        >
          <svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
          </svg>
        </button>
        <button
          onClick={onClose}
          className="p-2 bg-white/10 hover:bg-white/20 rounded-full text-white transition-colors"
        >
          <svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
          </svg>
        </button>
      </div>

      {/* Prev arrow */}
      {hasPrev && (
        <button
          onClick={(e) => { e.stopPropagation(); setIndex(index - 1) }}
          className="absolute left-3 top-1/2 -translate-y-1/2 p-2 bg-white/10 hover:bg-white/20 rounded-full text-white transition-colors z-10"
        >
          <svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
          </svg>
        </button>
      )}

      {/* Next arrow */}
      {hasNext && (
        <button
          onClick={(e) => { e.stopPropagation(); setIndex(index + 1) }}
          className="absolute right-3 top-1/2 -translate-y-1/2 p-2 bg-white/10 hover:bg-white/20 rounded-full text-white transition-colors z-10"
        >
          <svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
          </svg>
        </button>
      )}

      <div className="max-w-[90vw] max-h-[90vh]" onClick={(e) => e.stopPropagation()}>
        {file.type === 'video' ? (
          <HlsVideo
            key={index}
            hlsSrc={hlsEnabled ? `/api/hls/${encodeURIComponent(file.folder)}/${encodeURIComponent(file.filename)}/master.m3u8` : null}
            src={file.url}
            controls
            autoPlay
            className="max-w-full max-h-[90vh] rounded-lg"
          />
        ) : (
          <a href={file.url} target="_blank" rel="noopener noreferrer" className="cursor-pointer">
            <img
              src={file.url}
              alt=""
              className="max-w-full max-h-[90vh] rounded-lg object-contain"
            />
          </a>
        )}
        <p className="text-center text-sm text-gray-400 mt-3">
          @{file.folder} &middot; {index + 1} / {files.length}
        </p>
      </div>
    </div>
  )
}

function Slideshow({ filterParams, typeFilter, hlsEnabled, onClose }) {
  const [items, setItems] = useState([])
  const [index, setIndex] = useState(0)
  const [paused, setPaused] = useState(false)
  const [fadeKey, setFadeKey] = useState(0)
  const videoRef = useRef(null)
  const timerRef = useRef(null)

  const current = items[index] || null
  const isVideo = current?.type === 'video'

  // Load ALL matching files shuffled
  const loadBatch = useCallback(async () => {
    const params = {
      ...filterParams,
      sort: 'shuffle',
      limit: 100000,
    }
    if (typeFilter === 'image') params.type = 'image'
    else if (typeFilter === 'video') params.type = 'video'
    // 'all' — no type filter

    const data = await getGalleryFiles(params)
    if (!data.error && data.files.length > 0) {
      setItems(data.files)
      setIndex(0)
      setFadeKey((k) => k + 1)
    }
  }, [filterParams, typeFilter])

  useEffect(() => { loadBatch() }, [])

  // Advance to next item (or reload batch if at end)
  const advance = useCallback(() => {
    setIndex((prev) => {
      const next = prev + 1
      if (next >= items.length) {
        loadBatch()
        return prev
      }
      setFadeKey((k) => k + 1)
      return next
    })
  }, [items.length, loadBatch])

  // For images (and images in 'all' mode): auto-advance after 5s
  useEffect(() => {
    if (items.length === 0 || paused) return
    if (isVideo) return // videos advance on ended event
    timerRef.current = setTimeout(advance, 5000)
    return () => clearTimeout(timerRef.current)
  }, [index, items.length, paused, isVideo, advance])

  // When a video ends, advance
  const handleVideoEnded = useCallback(() => {
    if (!paused) advance()
  }, [paused, advance])

  // Keyboard controls
  useEffect(() => {
    const handleKey = (e) => {
      if (e.key === 'Escape') onClose()
      if (e.key === ' ') {
        e.preventDefault()
        setPaused((p) => {
          const next = !p
          // If unpausing a video, resume playback
          if (!next && videoRef.current && videoRef.current.paused) {
            videoRef.current.play()
          } else if (next && videoRef.current && !videoRef.current.paused) {
            videoRef.current.pause()
          }
          return next
        })
      }
      if (e.key === 'ArrowRight' && items.length > 0) {
        clearTimeout(timerRef.current)
        advance()
      }
      if (e.key === 'ArrowLeft' && items.length > 0) {
        setIndex((prev) => {
          const next = Math.max(prev - 1, 0)
          setFadeKey((k) => k + 1)
          return next
        })
      }
    }
    window.addEventListener('keydown', handleKey)
    return () => window.removeEventListener('keydown', handleKey)
  }, [onClose, items, advance])

  return (
    <div className="fixed inset-0 z-[100] bg-black flex items-center justify-center">
      <div className="absolute top-4 right-4 flex items-center gap-3 z-10">
        {current && (
          <a
            href={current.url}
            target="_blank"
            rel="noopener noreferrer"
            className="p-2 bg-white/10 hover:bg-white/20 rounded-full text-white transition-colors"
            title="Open in new window"
          >
            <svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
              <path strokeLinecap="round" strokeLinejoin="round" d="M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" />
            </svg>
          </a>
        )}
        <button
          onClick={onClose}
          className="p-2 bg-white/10 hover:bg-white/20 rounded-full text-white transition-colors"
        >
          <svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
          </svg>
        </button>
      </div>

      {paused && (
        <div className="absolute top-4 left-4 text-white/50 text-sm z-10">
          Paused
        </div>
      )}

      {current ? (
        isVideo ? (
          <HlsVideo
            key={fadeKey}
            ref={videoRef}
            hlsSrc={hlsEnabled ? `/api/hls/${encodeURIComponent(current.folder)}/${encodeURIComponent(current.filename)}/master.m3u8` : null}
            src={current.url}
            controls
            autoPlay
            onEnded={handleVideoEnded}
            className="max-w-full max-h-full object-contain animate-fadeIn"
          />
        ) : (
          <img
            key={fadeKey}
            src={current.url}
            alt=""
            className="max-w-full max-h-full object-contain animate-fadeIn"
          />
        )
      ) : (
        <Spinner />
      )}

      {current && (
        <div className="absolute bottom-4 left-0 right-0 text-center text-white/40 text-sm">
          @{current.folder} &middot; {index + 1} / {items.length}
          {isVideo && ' (video)'}
        </div>
      )}
    </div>
  )
}

function GridWallIcon({ className }) {
  return (
    <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z" />
    </svg>
  )
}

function SlideshowIcon({ className }) {
  return (
    <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z" />
    </svg>
  )
}

function ShuffleIcon({ className }) {
  return (
    <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M7.5 21L3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5" />
    </svg>
  )
}

function RefreshIcon({ className }) {
  return (
    <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182" />
    </svg>
  )
}

function UsersFilterIcon({ className }) {
  return (
    <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" />
    </svg>
  )
}

function FilterIcon({ className }) {
  return (
    <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M10.5 6h9.75M10.5 6a1.5 1.5 0 11-3 0m3 0a1.5 1.5 0 10-3 0M3.75 6H7.5m3 12h9.75m-9.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-3.75 0H7.5m9-6h3.75m-3.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-9.75 0h9.75" />
    </svg>
  )
}

function GalleryIcon({ className }) {
  return (
    <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909M18 3.75H6A2.25 2.25 0 003.75 6v12A2.25 2.25 0 006 20.25h12A2.25 2.25 0 0020.25 18V6A2.25 2.25 0 0018 3.75z" />
    </svg>
  )
}
