import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query'
import { Link } from '@tanstack/react-router'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ChevronLeft, Play, Plus } from 'lucide-react'
import { qk } from '@/shared/api/query-keys'
import { AUDIENCE_UNSET, SHOW_AUDIENCES, type ShowAudience } from '@/shared/api/types'
import { useApiError } from '@/shared/lib/use-api-error'
import { Badge } from '@/shared/ui/badge'
import { Button } from '@/shared/ui/button'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/shared/ui/dialog'
import { HlsVideo } from '@/shared/ui/hls-video'
import { Pager } from '@/shared/ui/pager'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/ui/select'
import { formatSeasonEpisode, parseEpisodeName } from '@/features/admin/media/episode-parse'
import { formatDuration } from '@/features/admin/media/format'
import { mediaPreviewUrl } from '@/features/admin/media/api'
import { AddEpisodesDialog } from './AddEpisodesDialog'
import { ShowGenresField } from './ShowGenresField'
import { ShowMetadataCard } from './ShowMetadataCard'
import { imageUrl } from '@/features/admin/images/api'
import { getShow, getShowUsage, removeEpisode, setShowAudience } from './api'

const PAGE_SIZE = 20

export function ShowDetail({ showId }: Readonly<{ showId: string }>) {
  const { t } = useTranslation()
  const queryClient = useQueryClient()
  const [addOpen, setAddOpen] = useState(false)
  const [epPage, setEpPage] = useState(1)
  /** Серия, которую смотрят: та же нарезка, что уйдёт в эфир. */
  const [preview, setPreview] = useState<{ assetId: string; title: string } | null>(null)

  const { data: show, isLoading } = useQuery({
    queryKey: qk.shows.detail(showId),
    queryFn: () => getShow(showId),
  })
  // Где шоу задействовано — отдельным запросом: он обходит все группы, и держать его в карточке
  // шоу заодно с остальным значило бы платить за него при каждом обновлении состава.
  const { data: usage } = useQuery({
    queryKey: qk.shows.usage(showId),
    queryFn: () => getShowUsage(showId),
  })

  const invalidate = () => queryClient.invalidateQueries({ queryKey: qk.shows.detail(showId) })
  const onError = useApiError()

  const audienceMutation = useMutation({
    mutationFn: (audience: ShowAudience | null) => setShowAudience(showId, audience),
    onSuccess: invalidate,
    onError,
  })

  const removeMutation = useMutation({
    mutationFn: (episodeId: string) => removeEpisode(showId, episodeId),
    onSuccess: invalidate,
    onError,
  })

  // Какие сезоны загружены — по распознанным SxxExx в именах серий (отсортированы по возрастанию).
  const seasons = useMemo(() => {
    if (!show) return [] as number[]
    const set = new Set<number>()
    for (const e of show.episodes) {
      const parsed = parseEpisodeName(e.assetName ?? '')
      if (parsed.episode != null && parsed.season != null) set.add(parsed.season)
    }
    return [...set].sort((a, b) => a - b)
  }, [show])

  if (isLoading || !show) return <p className="text-muted-foreground">{t('common.loading')}</p>

  // Полнометражке добавлять нечего, пока её единственная серия уже на месте.
  const canAdd = show.kind !== 'Single' || show.episodes.length === 0

  // Страницу серий зажимаем в допустимый диапазон — чтобы после удаления не застрять на пустой.
  const epTotalPages = Math.max(1, Math.ceil(show.episodes.length / PAGE_SIZE))
  const epPageSafe = Math.min(epPage, epTotalPages)
  const epOffset = (epPageSafe - 1) * PAGE_SIZE
  const epItems = show.episodes.slice(epOffset, epOffset + PAGE_SIZE)

  return (
    <div className="flex flex-col gap-4">
      <div className="flex items-center gap-2">
        <Button asChild size="sm" variant="ghost">
          <Link to="/admin/shows">
            <ChevronLeft className="h-4 w-4" />
            {t('admin.shows.title')}
          </Link>
        </Button>
      </div>

      <div className="flex flex-col gap-1">
        <div className="flex flex-wrap items-center gap-3">
          <h2 className="crt-glow text-xl font-semibold">{show.name}</h2>
          <Badge variant="muted">{t(`admin.shows.kinds.${show.kind}`)}</Badge>
          <Select
            value={show.audience ?? AUDIENCE_UNSET}
            onValueChange={(v) =>
              audienceMutation.mutate(v === AUDIENCE_UNSET ? null : (v as ShowAudience))
            }
          >
            {/* Ширина под самую длинную расшифровку рейтинга («NC-17 — только взрослым»):
                у́же — и она переносится на вторую строку, ломая высоту строки заголовка. */}
            <SelectTrigger className="h-7 w-64 whitespace-nowrap">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value={AUDIENCE_UNSET}>{t('admin.shows.audienceUnset')}</SelectItem>
              {SHOW_AUDIENCES.map((value) => (
                <SelectItem key={value} value={value}>
                  {t(`admin.shows.audiences.${value}`)}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
          {show.kind === 'Series' && (
            <Badge variant="muted">
              {t('admin.shows.seasons')}: {seasons.length}
            </Badge>
          )}
          <Badge variant="muted">
            {t('admin.shows.episodes')}: {show.episodes.length}
          </Badge>
        </div>
        {show.kind === 'Series' && seasons.length > 0 && (
          <p className="text-sm text-muted-foreground">
            {t('admin.shows.loadedSeasons')}: {seasons.join(', ')}
          </p>
        )}
        <div className="mt-2">
          <ShowGenresField show={show} onChanged={invalidate} />
        </div>
        {show.collections.length > 0 && (
          <p className="mt-1 flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
            {t('admin.shows.inCollections')}:
            {show.collections.map((collection) => (
              <Link
                key={collection.id}
                to="/admin/collections/$collectionId"
                params={{ collectionId: collection.id }}
                className="text-primary hover:underline"
              >
                {collection.name}
              </Link>
            ))}
          </p>
        )}
        {/* Где шоу задействовано: без этого «используется» при удалении не объясняет, кем. */}
        {usage && usage.groups.length > 0 && (
          <p className="mt-1 flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
            {t('admin.shows.inGroups')}:
            {usage.groups.map((group) => (
              <Link
                key={group.id}
                to="/admin/groups/$groupId"
                params={{ groupId: group.id }}
                className="text-primary hover:underline"
              >
                {group.name}
                {group.viaRule && (
                  <span className="text-muted-foreground"> ({t('admin.groups.byRule')})</span>
                )}
              </Link>
            ))}
          </p>
        )}
        {usage && usage.channels.length > 0 && (
          <p className="mt-1 text-sm text-muted-foreground">
            {t('admin.shows.inChannels')}: {usage.channels.map((c) => c.name).join(', ')}
          </p>
        )}
      </div>

      <ShowMetadataCard show={show} onChanged={invalidate} />

      <div className="flex flex-wrap items-center gap-2">
        <h3 className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">
          {t('admin.shows.episodes')}
        </h3>
        {/* Полнометражке серию добавляют только пока её нет — вторая ей не положена. */}
        {canAdd && (
          <Button size="sm" onClick={() => setAddOpen(true)}>
            <Plus className="h-4 w-4" />
            {t('admin.shows.addMedia')}
          </Button>
        )}
      </div>

      <div className="crt-panel overflow-x-auto rounded-md">
        <table className="w-full text-sm">
          <thead className="border-b border-border text-left text-muted-foreground">
            <tr>
              <th className="px-4 py-2 font-medium">#</th>
              <th className="px-4 py-2 font-medium">{t('admin.shows.episode')}</th>
              <th className="px-4 py-2 font-medium">{t('admin.media.duration')}</th>
              <th className="px-4 py-2 font-medium">{t('admin.media.status')}</th>
              <th className="px-4 py-2 font-medium">{t('common.actions')}</th>
            </tr>
          </thead>
          <tbody>
            {epItems.map((episode, index) => {
              const parsed =
                episode.season != null && episode.episode != null
                  ? { season: episode.season, episode: episode.episode }
                  : parseEpisodeName(episode.assetName ?? '')
              const label = formatSeasonEpisode(parsed)
              return (
                <tr key={episode.id} className="border-b border-border last:border-0">
                  <td className="px-4 py-2 text-muted-foreground">{epOffset + index + 1}</td>
                  <td className="px-4 py-2">
                    <div className="flex items-center gap-2">
                      {episode.stillImageId && (
                        <img
                          src={imageUrl(episode.stillImageId)}
                          alt=""
                          className="h-9 w-16 shrink-0 rounded object-cover"
                        />
                      )}
                      {label && <Badge>{label}</Badge>}
                      <div className="min-w-0">
                        <div className="truncate">{episode.title ?? episode.assetName ?? '—'}</div>
                        {episode.title && (
                          <div className="truncate text-xs text-muted-foreground">
                            {episode.assetName}
                          </div>
                        )}
                      </div>
                    </div>
                  </td>
                  <td className="px-4 py-2 text-muted-foreground">
                    {formatDuration(episode.durationSeconds)}
                  </td>
                  <td className="px-4 py-2">
                    {episode.assetStatus && (
                      <Badge variant={episode.assetStatus === 'Ready' ? 'default' : 'muted'}>
                        {t(`admin.media.statuses.${episode.assetStatus}`)}
                      </Badge>
                    )}
                  </td>
                  <td className="px-4 py-2">
                    <div className="flex items-center gap-2">
                      {/* Смотреть можно только нарезанное: у необработанного ассета плейлиста нет. */}
                      {episode.assetStatus === 'Ready' && (
                        <Button
                          size="sm"
                          variant="outline"
                          title={t('admin.media.preview')}
                          onClick={() =>
                            setPreview({
                              assetId: episode.mediaAssetId,
                              title: episode.title ?? episode.assetName ?? t('admin.shows.episode'),
                            })
                          }
                        >
                          <Play className="h-4 w-4" />
                        </Button>
                      )}
                      <Button
                        size="sm"
                        variant="destructive"
                        onClick={() => removeMutation.mutate(episode.id)}
                      >
                        {t('common.delete')}
                      </Button>
                    </div>
                  </td>
                </tr>
              )
            })}
            {show.episodes.length === 0 && (
              <tr>
                <td className="px-4 py-3 text-muted-foreground" colSpan={5}>
                  {t('admin.shows.noEpisodes')}
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>
      <Pager page={epPageSafe} totalPages={epTotalPages} onChange={setEpPage} />

      <Dialog open={preview !== null} onOpenChange={(open) => !open && setPreview(null)}>
        <DialogContent className="max-w-3xl">
          <DialogHeader>
            <DialogTitle className="truncate">{preview?.title}</DialogTitle>
          </DialogHeader>
          {preview && <HlsVideo src={mediaPreviewUrl(preview.assetId)} autoPlay />}
        </DialogContent>
      </Dialog>

      {addOpen && (
        <AddEpisodesDialog
          show={show}
          onClose={() => setAddOpen(false)}
          onAdded={() => void invalidate()}
        />
      )}
    </div>
  )
}
