﻿import { useEffect, useMemo, useRef, useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { useNavigate } from 'react-router-dom'
import { X, Check, Play } from '../../lib/icons'
import { useEpisodes, useItemDetails, useSeasons } from '../../hooks/use-jellyfin'
import { useCinemeta } from '../../hooks/use-external'
import { getBestImage } from '../../api/jellyfin'
import { formatRuntime } from '../../lib/format'
import { buildCinemetaEpisodeMap } from '../../api/cinemeta'
import { useAnimeFiller, classifyEpisode } from '../../lib/anime-filler'
import { EpisodeMetaProvider } from '../../lib/episode-meta-context'
import EpisodeRatingChip from '../detail/EpisodeRatingChip'
import FillerChip from '../detail/FillerChip'
import { usePreferencesStore } from '../../stores/preferences-store'
import Select, { type SelectOption } from '../ui/Select'

/**
 * Netflix-style in-player episode browser. Slides in from the right when the
 * user clicks the episodes button in the player chrome. Shows the current
 * season's episodes with thumbnails, runtimes, watch progress, and a season
 * dropdown at the top. Clicking an episode navigates the player to that
 * episode's id.
 *
 * Mounted at the player's root level so it can sit above the click-capture
 * layer and the controls bars without fighting their pointer events.
 */
interface Props {
  open: boolean
  onClose: () => void
  seriesId: string
  currentItemId: string
  /** Falls back to the season currently in the URL if the current item lives elsewhere. */
  initialSeasonId?: string
  serverUrl: string
}

export default function EpisodesPanel({
  open,
  onClose,
  seriesId,
  currentItemId,
  initialSeasonId,
  serverUrl,
}: Props) {
  const navigate = useNavigate()
  const panelRef = useRef<HTMLElement>(null)
  const { data: seasons = [] } = useSeasons(seriesId)
  const [seasonId, setSeasonId] = useState<string | undefined>(initialSeasonId)

  // Pick a sensible default season the first time data lands.
  useEffect(() => {
    if (seasonId) return
    if (initialSeasonId) {
      setSeasonId(initialSeasonId)
      return
    }
    if (seasons.length > 0) setSeasonId(seasons[0].Id || undefined)
  }, [seasons, initialSeasonId, seasonId])

  const { data: episodes = [] } = useEpisodes(seriesId, seasonId)
  // Pull series IMDB / TMDB ids so we can attach rating + filler chips to
  // the episode rows the same way the detail page does.
  const { data: seriesItem } = useItemDetails(seriesId)
  const seriesImdbId = seriesItem?.ProviderIds?.Imdb || null
  const seriesTmdbId = seriesItem?.ProviderIds?.Tmdb ? Number(seriesItem.ProviderIds.Tmdb) : null
  const { data: cinemetaSeriesData } = useCinemeta(seriesImdbId, 'series')
  const cinemetaMap = useMemo(
    () => buildCinemetaEpisodeMap(cinemetaSeriesData),
    [cinemetaSeriesData],
  )
  const fillerData = useAnimeFiller(seriesTmdbId)
  const seasonStarts = useMemo(() => {
    const m = new Map<number, number>()
    if (!seasons) return m
    let running = 0
    const ordered = [...seasons]
      .filter(s => (s.IndexNumber ?? 0) > 0)
      .sort((a, b) => (a.IndexNumber ?? 0) - (b.IndexNumber ?? 0))
    for (const s of ordered) {
      const idx = s.IndexNumber ?? 0
      m.set(idx, running)
      running += s.ChildCount ?? 0
    }
    return m
  }, [seasons])
  const fillerOf = useMemo(() => {
    return (season: number | null | undefined, episode: number | null | undefined) => {
      if (!fillerData || season == null || episode == null) return null
      const start = seasonStarts.get(season)
      if (start == null) return null
      return classifyEpisode(start + episode, fillerData)
    }
  }, [fillerData, seasonStarts])
  const spoilerBlur = usePreferencesStore(s => s.episode.show.spoilerBlur)

  // Specials always last to match the rest of the app.
  const orderedEpisodes = useMemo(() => {
    return [...episodes].sort((a: any, b: any) => {
      const aSpecial = a.ParentIndexNumber === 0
      const bSpecial = b.ParentIndexNumber === 0
      if (aSpecial && !bSpecial) return 1
      if (!aSpecial && bSpecial) return -1
      return (a.IndexNumber ?? 0) - (b.IndexNumber ?? 0)
    })
  }, [episodes])

  // Close on Escape so the user can dismiss without reaching for the mouse.
  useEffect(() => {
    if (!open) return
    function onKey(e: KeyboardEvent) {
      if (e.key === 'Escape') {
        e.stopPropagation()
        onClose()
      }
    }
    window.addEventListener('keydown', onKey, true)
    return () => window.removeEventListener('keydown', onKey, true)
  }, [open, onClose])

  const seasonOptions: SelectOption<string>[] = seasons
    .filter(s => !!s.Id)
    .map(s => ({
      value: s.Id as string,
      label: s.IndexNumber === 0 ? 'Specials' : s.Name || `Season ${s.IndexNumber ?? '?'}`,
    }))

  return (
    <EpisodeMetaProvider cinemetaMap={cinemetaMap} fillerOf={fillerOf}>
    <AnimatePresence>
      {open && (
        <>
          {/* Backdrop - dims the player area, dismisses on click */}
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.18 }}
            onClick={onClose}
            className="absolute inset-0 z-30 bg-black/55 backdrop-blur-[2px]"
          />

          {/* Panel */}
          <motion.aside
            ref={panelRef as any}
            initial={{ x: '100%' }}
            animate={{ x: 0 }}
            exit={{ x: '100%' }}
            transition={{ duration: 0.32, ease: [0.16, 1, 0.3, 1] }}
            className="absolute right-0 top-0 bottom-0 z-40 w-[380px] max-w-[85vw] bg-[#0c0a08]/96 backdrop-blur-xl border-l border-white/10 flex flex-col shadow-[0_0_60px_rgba(0,0,0,0.6)]"
            data-episodes-panel
            role="dialog"
            aria-label="Episodes"
          >
            {/* Header */}
            <header className="shrink-0 px-5 pt-5 pb-3 border-b border-white/8">
              <div className="flex items-center justify-between mb-3">
                <h2 className="text-[13px] font-semibold uppercase tracking-[0.14em] text-white/85">
                  Episodes
                </h2>
                <button
                  onClick={onClose}
                  className="w-8 h-8 grid place-items-center rounded-full text-white/70 hover:text-white hover:bg-white/10 transition-colors focus-ring"
                  aria-label="Close"
                >
                  <X size={16} />
                </button>
              </div>
              {seasonOptions.length > 0 && (
                <Select
                  value={seasonId || ''}
                  onChange={v => setSeasonId(v)}
                  options={seasonOptions}
                  width="w-full"
                  ariaLabel="Season"
                  portalContainer={panelRef.current}
                />
              )}
            </header>

            {/* Episode list */}
            <div className="flex-1 overflow-y-auto content-scroll px-3 py-3 space-y-2">
              {orderedEpisodes.length === 0 && (
                <p className="text-[12.5px] text-white/55 px-2 py-6 text-center">
                  No episodes found in this season.
                </p>
              )}
              {orderedEpisodes.map(ep => {
                const epId = ep.Id || ''
                const isCurrent = epId === currentItemId
                const watched = ep.UserData?.Played === true
                const progressTicks = Number(ep.UserData?.PlaybackPositionTicks ?? 0)
                const runtimeTicks = Number(ep.RunTimeTicks ?? 0)
                const progressPct =
                  progressTicks > 0 && runtimeTicks > 0
                    ? Math.min(100, (progressTicks / runtimeTicks) * 100)
                    : 0
                const epNum = ep.IndexNumber
                const seasonNum = ep.ParentIndexNumber
                const thumb = getBestImage(serverUrl, ep, 'thumb', 360)
                return (
                  <button
                    key={epId}
                    onClick={() => {
                      if (epId && !isCurrent) {
                        onClose()
                        navigate(`/play/${epId}`)
                      }
                    }}
                    disabled={isCurrent}
                    className={`w-full text-left rounded-lg overflow-hidden border transition-colors duration-150 group ${
                      isCurrent
                        ? 'border-accent/70 bg-accent/8 cursor-default'
                        : 'border-white/10 hover:border-white/25 hover:bg-white/5 focus-ring'
                    }`}
                  >
                    <div className="flex gap-3 p-2">
                      <div className="relative shrink-0 w-[120px] aspect-video rounded-md overflow-hidden bg-black">
                        {thumb ? (
                          <img
                            src={thumb}
                            alt=""
                            className={`w-full h-full object-cover transition-[filter,transform] duration-300 ${
                              isCurrent ? '' : 'group-hover:scale-[1.04]'
                            } ${
                              spoilerBlur && !watched && !isCurrent
                                ? 'blur-[10px] saturate-[0.6] group-hover:blur-0 group-hover:saturate-100'
                                : ''
                            }`}
                          />
                        ) : (
                          <div className="w-full h-full bg-elevated" />
                        )}
                        {/* Play overlay on hover (skipped for current episode) */}
                        {!isCurrent && (
                          <div className="absolute inset-0 grid place-items-center bg-black/45 opacity-0 group-hover:opacity-100 transition-opacity">
                            <span className="w-9 h-9 rounded-full bg-white/95 grid place-items-center text-void">
                              <Play size={14} fill="currentColor" className="translate-x-px" />
                            </span>
                          </div>
                        )}
                        {watched && !isCurrent && (
                          <span className="absolute top-1 right-1 w-5 h-5 rounded-full bg-accent text-void grid place-items-center">
                            <Check size={11} strokeWidth={3} />
                          </span>
                        )}
                        <span className="absolute top-1 left-1 flex gap-1">
                          <FillerChip season={seasonNum} episode={epNum} />
                        </span>
                        {progressPct > 0 && progressPct < 95 && !watched && (
                          <div className="absolute left-0 right-0 bottom-0 h-1 bg-black/45">
                            <div
                              className="h-full bg-accent"
                              style={{ width: `${progressPct}%` }}
                            />
                          </div>
                        )}
                        {isCurrent && (
                          <div className="absolute inset-0 grid place-items-center bg-black/45">
                            <span className="text-[10px] uppercase tracking-[0.16em] font-semibold text-accent">
                              Now playing
                            </span>
                          </div>
                        )}
                      </div>
                      <div className="min-w-0 flex-1 py-0.5">
                        <p
                          className={`text-[10.5px] uppercase tracking-[0.14em] font-semibold mb-0.5 ${
                            isCurrent ? 'text-accent' : 'text-white/55'
                          }`}
                        >
                          {seasonNum != null && epNum != null
                            ? `S${seasonNum} Â· E${epNum}`
                            : `Episode ${epNum ?? '?'}`}
                          {runtimeTicks > 0 && (
                            <span className="text-white/40 normal-case tracking-normal font-normal ml-1.5">
                              Â· {formatRuntime(runtimeTicks)}
                            </span>
                          )}
                          <span className="ml-1.5 inline-flex">
                            <EpisodeRatingChip season={seasonNum} episode={epNum} />
                          </span>
                        </p>
                        <p
                          className={`text-[13px] font-medium leading-tight tracking-tight line-clamp-2 ${
                            isCurrent ? 'text-white' : 'text-white/90'
                          }`}
                        >
                          {ep.Name || `Episode ${epNum ?? ''}`}
                        </p>
                        {ep.Overview && (
                          <p
                            className={`text-[11.5px] text-white/55 leading-snug mt-1 line-clamp-2 transition-[filter,color] duration-200 ${
                              spoilerBlur && !watched && !isCurrent
                                ? 'blur-[5px] text-white/35 hover:blur-0 hover:text-white/55'
                                : ''
                            }`}
                          >
                            {ep.Overview}
                          </p>
                        )}
                      </div>
                    </div>
                  </button>
                )
              })}
            </div>
          </motion.aside>
        </>
      )}
    </AnimatePresence>
    </EpisodeMetaProvider>
  )
}
