import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { Trash2, Upload } from 'lucide-react'
import { useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { qk } from '@/shared/api/query-keys'
import type { ImageCategory } from '@/shared/api/types'
import { useApiError } from '@/shared/lib/use-api-error'
import { Button } from '@/shared/ui/button'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/shared/ui/dialog'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/ui/select'
import { cn } from '@/shared/lib/cn'
import { deleteImage, imageUrl, listImages, uploadImage } from './api'

const CATEGORIES: ImageCategory[] = ['Library', 'ShowPoster', 'EpisodeStill', 'BumperBackground']

type ImageOrder = 'new' | 'old' | 'az' | 'za'

type ImagePick = { id: string; url: string }

/**
 * Внутренность галереи: вкладки по категориям, загрузка и удаление. Если передан <c>onSelect</c> —
 * работает как пикер (клик по картинке или загрузка новой возвращает её и закрывает через onClose).
 * Новые загрузки идут в активную вкладку (по умолчанию — категорию вызова).
 */
export function GalleryBrowser({
  category = 'Library',
  onSelect,
  onClose,
  fill = false,
}: Readonly<{
  category?: ImageCategory
  onSelect?: (image: ImagePick) => void
  onClose?: () => void
  /** Занять экран целиком: на отдельной странице прокрутка должна быть одна — внутри сетки. */
  fill?: boolean
}>) {
  const { t } = useTranslation()
  const queryClient = useQueryClient()
  const [active, setActive] = useState<ImageCategory>(category)
  const fileInput = useRef<HTMLInputElement>(null)

  const onError = useApiError()

  const [order, setOrder] = useState<ImageOrder>('new')

  const { data: images, isLoading } = useQuery({
    queryKey: qk.images.byCategory(active),
    queryFn: () => listImages(active),
  })

  const sorted = useMemo(() => {
    const arr = [...(images ?? [])]
    arr.sort((a, b) => {
      switch (order) {
        case 'old':
          return a.createdAt.localeCompare(b.createdAt)
        case 'az':
          return (a.originalFileName ?? '').localeCompare(b.originalFileName ?? '')
        case 'za':
          return (b.originalFileName ?? '').localeCompare(a.originalFileName ?? '')
        default:
          return b.createdAt.localeCompare(a.createdAt)
      }
    })
    return arr
  }, [images, order])

  const invalidate = () => queryClient.invalidateQueries({ queryKey: qk.images.byCategory(active) })

  const pick = (id: string) => {
    if (!onSelect) return
    onSelect({ id, url: imageUrl(id) })
    onClose?.()
  }

  const upload = useMutation({
    mutationFn: (file: File) => uploadImage(active, file),
    onSuccess: (created) => {
      invalidate()
      // В режиме пикера загрузка = «загрузить и выбрать»: возвращаем новую картинку и закрываем.
      if (onSelect) pick(created.id)
    },
    onError,
  })

  const remove = useMutation({
    mutationFn: (id: string) => deleteImage(id),
    onSuccess: invalidate,
    onError,
  })

  return (
    <div className={cn('flex flex-col', fill && 'min-h-0 flex-1')}>
      <div className="flex flex-wrap gap-1.5">
        {CATEGORIES.map((c) => (
          <button
            key={c}
            type="button"
            onClick={() => setActive(c)}
            className={`rounded-md px-3 py-1.5 text-sm ${
              active === c
                ? 'bg-primary text-primary-foreground'
                : 'text-muted-foreground hover:bg-muted'
            }`}
          >
            {t(`admin.gallery.categories.${c}`)}
          </button>
        ))}
      </div>

      <div className="mt-3 flex items-center justify-between gap-2">
        <span className="text-xs text-muted-foreground">
          {onSelect ? t('admin.gallery.pickHint') : t('admin.gallery.browseHint')}
        </span>
        <Select value={order} onValueChange={(v) => setOrder(v as ImageOrder)}>
          <SelectTrigger className="ml-auto h-8 w-48">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="new">{t('admin.gallery.sort.newest')}</SelectItem>
            <SelectItem value="old">{t('admin.gallery.sort.oldest')}</SelectItem>
            <SelectItem value="az">{t('admin.gallery.sort.nameAsc')}</SelectItem>
            <SelectItem value="za">{t('admin.gallery.sort.nameDesc')}</SelectItem>
          </SelectContent>
        </Select>
        <input
          ref={fileInput}
          type="file"
          accept="image/*"
          className="hidden"
          onChange={(e) => {
            const file = e.target.files?.[0]
            if (file) upload.mutate(file)
            e.target.value = ''
          }}
        />
        <Button
          size="sm"
          variant="outline"
          disabled={upload.isPending}
          onClick={() => fileInput.current?.click()}
        >
          <Upload className="h-4 w-4" />
          {t('admin.gallery.upload')}
        </Button>
      </div>

      <div
        className={cn(
          'mt-3 overflow-y-auto',
          // В диалоге высота ограничена долей экрана, на своей странице — остатком до низа окна:
          // иначе страница прокручивается вместе с сеткой и полос становится две.
          fill ? 'min-h-0 flex-1' : 'max-h-[55vh]',
        )}
      >
        {isLoading && (
          <p className="py-6 text-center text-sm text-muted-foreground">{t('common.loading')}</p>
        )}
        {!isLoading && sorted.length === 0 && (
          <p className="py-6 text-center text-sm text-muted-foreground">
            {t('admin.gallery.empty')}
          </p>
        )}
        {!isLoading && sorted.length > 0 && (
          // Плитки фиксированного размера, а не N колонок на всю ширину: на широком экране пять
          // колонок растягивали постеры на треть экрана каждый.
          <div className="grid grid-cols-[repeat(auto-fill,minmax(7.5rem,1fr))] gap-2">
            {sorted.map((img) => (
              <div key={img.id} className="group relative">
                <button
                  type="button"
                  onClick={() => pick(img.id)}
                  className={`block aspect-square w-full overflow-hidden rounded-md border border-border bg-muted/30 ${
                    onSelect ? 'cursor-pointer hover:border-primary' : 'cursor-default'
                  }`}
                  title={img.originalFileName ?? ''}
                >
                  <img
                    src={imageUrl(img.id)}
                    alt={img.originalFileName ?? ''}
                    loading="lazy"
                    className="h-full w-full object-cover"
                  />
                </button>
                <button
                  type="button"
                  disabled={remove.isPending}
                  onClick={() => remove.mutate(img.id)}
                  aria-label={t('common.delete')}
                  className="absolute right-1 top-1 rounded bg-black/60 p-1 text-white opacity-0 transition-opacity hover:bg-red-600 group-hover:opacity-100"
                >
                  <Trash2 className="h-3.5 w-3.5" />
                </button>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  )
}

/** Общая галерея изображений в модальном окне (используется как пикер в местах выбора картинки). */
export function ImageGallery({
  open,
  onOpenChange,
  category,
  onSelect,
}: Readonly<{
  open: boolean
  onOpenChange: (open: boolean) => void
  category?: ImageCategory
  onSelect?: (image: ImagePick) => void
}>) {
  const { t } = useTranslation()
  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-3xl">
        <DialogHeader>
          <DialogTitle>{t('admin.gallery.title')}</DialogTitle>
        </DialogHeader>
        {open && (
          <GalleryBrowser
            category={category}
            onSelect={onSelect}
            onClose={() => onOpenChange(false)}
          />
        )}
      </DialogContent>
    </Dialog>
  )
}
