import { useCallback, useEffect, useRef } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { X } from 'lucide-react'
import { usePhotoStore } from '../../store/photoStore'
import { usePhotosQuery } from '../../hooks/usePhotosQuery'
import type { Photo } from '../../types/photo'
import { PreviewImage } from './PreviewImage'
import { PreviewFilmstrip } from './PreviewFilmstrip'
import { getPreviewImageSrc, isVideo } from './previewSrc'

export function PreviewView() {
  const activePhotoId = usePhotoStore((s) => s.activePhotoId)
  const setActivePhoto = usePhotoStore((s) => s.setActivePhoto)
  const closePreview = usePhotoStore((s) => s.closePreview)

  const containerRef = useRef<HTMLDivElement>(null)
  const previouslyFocusedRef = useRef<HTMLElement | null>(null)

  // Same hook Timeline uses, so we share one cache entry rather than looking
  // it up by key (which broke when the key gained the filter params).
  const { data: photos = [] } = usePhotosQuery()

  const currentIndex = activePhotoId
    ? photos.findIndex((p) => p.id === activePhotoId)
    : 0
  const safeIndex = currentIndex < 0 ? 0 : currentIndex
  const currentPhoto: Photo | undefined = photos[safeIndex]

  const goPrev = useCallback(() => {
    if (photos.length === 0) return
    const next = Math.max(0, safeIndex - 1)
    setActivePhoto(photos[next].id)
  }, [photos, safeIndex, setActivePhoto])

  const goNext = useCallback(() => {
    if (photos.length === 0) return
    const next = Math.min(photos.length - 1, safeIndex + 1)
    setActivePhoto(photos[next].id)
  }, [photos, safeIndex, setActivePhoto])

  // Preview-scoped hotkeys: only mounted while PreviewView is rendered.
  useHotkeys('escape', closePreview, { preventDefault: true })
  useHotkeys('left', goPrev, { preventDefault: true }, [goPrev])
  useHotkeys('right', goNext, { preventDefault: true }, [goNext])

  // Preload the immediate neighbors so arrow nav feels instant. Skip videos
  // (browsers can't preload them via Image()) and skip when at the edges.
  useEffect(() => {
    const neighbors: Photo[] = []
    if (safeIndex > 0) neighbors.push(photos[safeIndex - 1])
    if (safeIndex < photos.length - 1) neighbors.push(photos[safeIndex + 1])
    for (const p of neighbors) {
      if (isVideo(p)) continue
      const img = new Image()
      img.src = getPreviewImageSrc(p)
    }
  }, [safeIndex, photos])

  // Focus trap: focus the preview container on mount, restore focus on
  // unmount. The container is keyboard-focusable (tabIndex=-1) so screen
  // readers and tab navigation stay scoped here.
  useEffect(() => {
    previouslyFocusedRef.current = document.activeElement as HTMLElement | null
    containerRef.current?.focus()
    return () => {
      previouslyFocusedRef.current?.focus?.()
    }
  }, [])

  // Trap Tab inside the dialog so users can't accidentally tab into the
  // hidden grid behind. Simple cycle implementation.
  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key !== 'Tab') return
    const root = containerRef.current
    if (!root) return
    const focusable = root.querySelectorAll<HTMLElement>(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    )
    if (focusable.length === 0) {
      e.preventDefault()
      root.focus()
      return
    }
    const first = focusable[0]
    const last = focusable[focusable.length - 1]
    const active = document.activeElement as HTMLElement | null
    if (e.shiftKey && active === first) {
      e.preventDefault()
      last.focus()
    } else if (!e.shiftKey && active === last) {
      e.preventDefault()
      first.focus()
    }
  }

  if (!currentPhoto) {
    return (
      <div
        ref={containerRef}
        role="dialog"
        aria-modal="true"
        aria-label="Photo preview"
        tabIndex={-1}
        className="fixed inset-0 z-40 flex flex-col items-center justify-center bg-black text-text-muted outline-none"
      >
        <div>No photo to display</div>
        <button
          onClick={closePreview}
          className="mt-4 rounded border border-border px-3 py-1 text-sm hover:bg-surface"
        >
          Close
        </button>
      </div>
    )
  }

  return (
    <div
      ref={containerRef}
      role="dialog"
      aria-modal="true"
      aria-label={`Photo preview: ${currentPhoto.filename}`}
      tabIndex={-1}
      onKeyDown={handleKeyDown}
      className="fixed inset-0 z-40 flex flex-col bg-black outline-none"
    >
      {/* Close button */}
      <button
        onClick={closePreview}
        className="absolute right-3 top-3 z-10 flex h-9 w-9 items-center justify-center rounded-full bg-black/60 text-white transition hover:bg-black/80"
        title="Close (Esc)"
        aria-label="Close preview"
      >
        <X className="h-5 w-5" />
      </button>

      {/* Filename + counter */}
      <div className="absolute left-3 top-3 z-10 rounded bg-black/60 px-3 py-1.5 text-xs text-white">
        <div className="font-mono">{currentPhoto.filename}</div>
        <div className="text-text-muted">
          {safeIndex + 1} / {photos.length}
        </div>
      </div>

      <PreviewImage photo={currentPhoto} />

      <PreviewFilmstrip
        photos={photos}
        currentIndex={safeIndex}
        onSelect={setActivePhoto}
      />
    </div>
  )
}
