import { useMemo, useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { useNavigate } from 'react-router-dom'
import { RotateCw, ListDetails, ArrowLeft, Star, Book, ChevronRight } from '../../lib/icons'
import { useTmdbMovie, useTmdbTvShow, useTmdbDiscoverMovies } from '../../hooks/use-tmdb'
import { useLibraryByTmdbId } from '../../hooks/use-jellyfin'
import { mapTmdbToJf } from '../../lib/tmdb-mapping'
import { tmdbMovieGenreId } from '../../lib/tmdb-genres'
import { usePreferencesStore } from '../../stores/preferences-store'
import { usePersonalData } from '../../stores/personal-data-store'
import { useDiary } from '../../stores/diary-store'
import type { BaseItemDto } from '../../api/types'

interface Props {
  open: boolean
  hasEpisodes: boolean
  /** The just-finished item, used to source same-mood recommendations. */
  item?: BaseItemDto | null
  /** Next item in queue / series, if any. */
  nextItem?: BaseItemDto | null
  onReplay: () => void
  onEpisodes: () => void
  onBack: () => void
  onPlayNext?: () => void
}

/**
 * Card shown when a video ends and there's no auto-advance target.
 * Three direct actions (Replay / Episodes / Back) plus two scrollable
 * recommendation rows: "More like this" sourced from TMDB
 * recommendations, and "Different vibe" pulling top-rated picks from
 * a deliberately opposite genre.
 */
export default function EndOfVideoCard({
  open,
  hasEpisodes,
  item,
  nextItem,
  onReplay,
  onEpisodes,
  onBack,
  onPlayNext,
}: Props) {
  return (
    <AnimatePresence>
      {open && (
        <motion.div
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          transition={{ duration: 0.22 }}
          className="absolute inset-0 z-30 grid place-items-center bg-black/65 backdrop-blur-sm overflow-y-auto"
        >
          <motion.div
            initial={{ y: 20, scale: 0.96 }}
            animate={{ y: 0, scale: 1 }}
            exit={{ y: 20, scale: 0.96 }}
            transition={{ duration: 0.32, ease: [0.16, 1, 0.3, 1] }}
            className="bg-glass-strong backdrop-blur-2xl border border-white/14 rounded-2xl p-7 text-center shadow-[0_30px_80px_-20px_rgba(0,0,0,0.85)] w-[min(960px,92vw)] my-8"
          >
            <p className="text-[11px] uppercase tracking-[0.18em] font-semibold text-white/60 mb-2">
              Finished
            </p>
            <h2 className="font-display text-2xl font-bold text-white mb-4 tracking-tight">
              {item?.Name || "What's next?"}
            </h2>

            {item && <RateAndLogRow itemId={item.Id} itemName={item.Name || ''} />}

            {nextItem && onPlayNext && (
              <motion.button
                initial={{ opacity: 0, y: 8 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.15 }}
                onClick={onPlayNext}
                className="mb-5 w-full max-w-md mx-auto flex items-center gap-3 p-3 rounded-xl bg-white/8 hover:bg-white/14 border border-white/14 hover:border-white/25 transition text-left focus-ring"
              >
                <div className="w-10 h-10 rounded-lg bg-elevated grid place-items-center shrink-0">
                  <ChevronRight size={16} className="text-accent" />
                </div>
                <div className="min-w-0 flex-1">
                  <p className="text-[10px] uppercase tracking-[0.14em] font-semibold text-white/55">
                    Up next
                  </p>
                  <p className="text-[13px] text-white font-medium truncate tracking-tight">
                    {nextItem.Name}
                  </p>
                </div>
              </motion.button>
            )}

            <div className="flex items-center gap-2.5 justify-center flex-wrap mb-2">
              <button
                onClick={onReplay}
                autoFocus
                className="inline-flex items-center gap-2 h-11 px-5 rounded-full bg-accent hover:bg-accent-hover text-void text-[13px] font-semibold tracking-tight transition-[transform,background] duration-200 ease-out hover:scale-[1.03] active:scale-[0.97] focus-ring shadow-[0_8px_24px_-8px_rgba(245,182,66,0.5)]"
              >
                <RotateCw size={14} stroke={2.25} />
                Replay
              </button>
              {hasEpisodes && (
                <button
                  onClick={onEpisodes}
                  className="inline-flex items-center gap-2 h-11 px-5 rounded-full bg-white/8 hover:bg-white/14 backdrop-blur text-white text-[13px] font-medium tracking-tight border border-white/14 hover:border-white/25 transition-all duration-200 ease-out active:scale-[0.97] focus-ring"
                >
                  <ListDetails size={14} />
                  Episodes
                </button>
              )}
              <button
                onClick={onBack}
                className="inline-flex items-center gap-2 h-11 px-5 rounded-full bg-white/8 hover:bg-white/14 backdrop-blur text-white text-[13px] font-medium tracking-tight border border-white/14 hover:border-white/25 transition-all duration-200 ease-out active:scale-[0.97] focus-ring"
              >
                <ArrowLeft size={14} stroke={2} />
                Back
              </button>
            </div>
            {item && <EndOfVideoExtras item={item} />}
          </motion.div>
        </motion.div>
      )}
    </AnimatePresence>
  )
}

function RateAndLogRow({ itemId, itemName }: { itemId?: string; itemName: string }) {
  const [hoverRating, setHoverRating] = useState(0)
  const personal = usePersonalData(s => itemId ? s.entries[itemId] : undefined)
  const setRating = usePersonalData(s => s.setRating)
  const addDiary = useDiary(s => s.add)
  const current = personal?.rating || 0
  const [logged, setLogged] = useState(false)

  if (!itemId || String(itemId).startsWith('tmdb-')) return null

  return (
    <div className="flex items-center justify-center gap-3 mb-5">
      <div className="flex items-center gap-1">
        {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(star => (
          <button
            key={star}
            type="button"
            onMouseEnter={() => setHoverRating(star)}
            onMouseLeave={() => setHoverRating(0)}
            onClick={() => setRating(itemId, star)}
            className="w-6 h-6 grid place-items-center focus-ring rounded"
            aria-label={`Rate ${star} out of 10`}
          >
            <Star
              size={14}
              className={
                (hoverRating ? star <= hoverRating : star <= current)
                  ? 'text-accent'
                  : 'text-white/25'
              }
              fill={(hoverRating ? star <= hoverRating : star <= current) ? 'currentColor' : 'none'}
              stroke={2}
            />
          </button>
        ))}
      </div>
      <span className="text-[11px] text-white/40 tabular-nums w-6 text-left">
        {hoverRating || current || '-'}
      </span>
      <button
        onClick={() => {
          if (logged) return
          addDiary({ itemId, itemName, watchedAt: new Date().toISOString() })
          setLogged(true)
        }}
        disabled={logged}
        className="inline-flex items-center gap-1.5 h-8 px-3 rounded-full bg-white/8 hover:bg-white/14 border border-white/14 text-[11.5px] text-white/80 hover:text-white transition disabled:opacity-40 disabled:cursor-default focus-ring"
      >
        <Book size={12} />
        {logged ? 'Logged' : 'Add to diary'}
      </button>
    </div>
  )
}

function EndOfVideoExtras({ item }: { item: BaseItemDto }) {
  const showMoreLikeThis = usePreferencesStore(s => s.endVideo.show.moreLikeThis)
  const showAntiRec = usePreferencesStore(s => s.endVideo.show.antiRec)
  if (!showMoreLikeThis && !showAntiRec) return null
  return (
    <div className="mt-6 text-left">
      {showMoreLikeThis && <MoreLikeThis item={item} />}
      {showAntiRec && <DifferentVibe item={item} />}
    </div>
  )
}

/* ────────────────────────────────────────────────────────────── */
/*  Recommendation rows                                            */
/* ────────────────────────────────────────────────────────────── */

/**
 * "More like this" - pulls TMDB recommendations on the just-watched
 * item. For episodes, sources from the parent series since per-episode
 * recommendations don't exist.
 */
function MoreLikeThis({ item }: { item: BaseItemDto }) {
  // Episodes: fall back to series TMDB id when present (passed via item.SeriesId
  // would require an extra fetch; the player already has it in the parent's
  // ProviderIds when we navigate from a series detail page, but for safety
  // we use the item's own ProviderIds or null).
  const tmdbId = item.ProviderIds?.Tmdb ? Number(item.ProviderIds.Tmdb) : null
  const isSeries = item.Type === 'Series' || item.Type === 'Episode'
  const movieFull = useTmdbMovie(!isSeries ? tmdbId : null)
  const tvFull = useTmdbTvShow(isSeries ? tmdbId : null)
  const libraryByTmdbId = useLibraryByTmdbId()

  const items = useMemo(() => {
    const recs = isSeries ? tvFull.data?.recommendations?.results : movieFull.data?.recommendations?.results
    if (!recs) return []
    return mapTmdbToJf(recs.slice(0, 12), libraryByTmdbId.data)
  }, [movieFull.data, tvFull.data, isSeries, libraryByTmdbId.data])

  if (!tmdbId || items.length === 0) return null
  return <RowStrip title="More like this" items={items} />
}

const VIBE_FLIP: Record<string, number> = {
  Horror: 35, // → Comedy
  Thriller: 35,
  Crime: 35,
  Drama: 12, // → Adventure
  Documentary: 28, // → Action
  Action: 18, // → Drama
  Adventure: 18,
  Comedy: 27, // → Horror
  Family: 53, // → Thriller
  Animation: 80, // → Crime
  Romance: 878, // → Sci-Fi
  'Science Fiction': 10749, // → Romance
}

/**
 * "Different vibe" - top-rated picks from the genre roughly opposite
 * the just-watched item. Useful when the user wants a palate cleanser
 * after a heavy watch.
 */
function DifferentVibe({ item }: { item: BaseItemDto }) {
  const oppositeGenreId = useMemo(() => {
    const genres = item.Genres || []
    for (const g of genres) {
      if (VIBE_FLIP[g] != null) return VIBE_FLIP[g]
    }
    // Fall back: if the source genre is in our movie-genre map, swap to
    // the most distant entry (Documentary) so we always emit something.
    return tmdbMovieGenreId('Documentary')
  }, [item.Genres])

  const discover = useTmdbDiscoverMovies(
    oppositeGenreId
      ? {
          with_genres: String(oppositeGenreId),
          'vote_count.gte': '500',
          sort_by: 'vote_average.desc',
        }
      : ({} as Record<string, string>),
  )
  const libraryByTmdbId = useLibraryByTmdbId()

  const items = useMemo(() => {
    const raw = (discover.data?.results || []).slice(0, 10).map(m => ({ ...m, media_type: 'movie' }))
    return mapTmdbToJf(raw, libraryByTmdbId.data)
  }, [discover.data, libraryByTmdbId.data])

  if (items.length === 0) return null
  return <RowStrip title="Want a different vibe?" items={items} />
}

function RowStrip({ title, items }: { title: string; items: BaseItemDto[] }) {
  const navigate = useNavigate()
  return (
    <section className="mb-5 last:mb-0">
      <p className="text-[10.5px] uppercase tracking-[0.16em] font-semibold text-white/55 mb-2.5 px-1">
        {title}
      </p>
      <div className="flex gap-2 overflow-x-auto hide-scrollbar -mx-1 px-1 pb-1.5">
        {items.map(it => {
          const tmdbPoster = it._tmdbPoster
          const inLibrary = it._inLibrary === true
          const poster =
            tmdbPoster ||
            (it.ImageTags?.Primary && it.Id
              ? null // Local items go through real Jellyfin URL on click; we skip the thumb here
              : null)
          return (
            <button
              key={it.Id}
              onClick={() => it.Id && navigate(`/item/${it.Id}`)}
              className="shrink-0 w-[112px] text-left focus-ring rounded-md group"
            >
              <div className={`relative aspect-[2/3] rounded-md overflow-hidden bg-elevated/60 ring-1 transition ${
                inLibrary ? 'ring-accent/60' : 'ring-white/10 group-hover:ring-white/30'
              }`}>
                {poster && (
                  <img src={poster} alt="" loading="lazy" className="w-full h-full object-cover group-hover:scale-[1.04] transition-transform duration-300" />
                )}
                {!poster && (
                  <div className="absolute inset-0 grid place-items-center text-white/45 text-2xl font-display font-semibold">
                    {it.Name?.[0]?.toUpperCase() || '?'}
                  </div>
                )}
              </div>
              <p className="text-[11.5px] text-white/85 font-medium truncate mt-1.5 leading-tight">
                {it.Name}
              </p>
              {it.ProductionYear && (
                <p className="text-[10px] text-white/45 tabular-nums">
                  {it.ProductionYear}
                </p>
              )}
            </button>
          )
        })}
      </div>
    </section>
  )
}

