import { useMemo, useState, useEffect, useCallback } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { useNavigate } from 'react-router-dom'
import { Shuffle, RotateCw, ArrowRight, Star, X } from '../../lib/icons'
import { useTmdbDiscoverMovies, useTmdbDiscoverTv } from '../../hooks/use-tmdb'
import { useLibraryByTmdbId } from '../../hooks/use-jellyfin'
import { usePreferencesStore } from '../../stores/preferences-store'
import { DISCOVER_MOODS } from '../../lib/discover-moods'
import { filterToMissing } from '../../pages/discover/helpers'
import type { TmdbDiscoverItem } from '../../api/tmdb'

const TMDB_IMG = 'https://image.tmdb.org/t/p'

interface Props {
  kind: 'movie' | 'tv'
  /** Optional mood id - when set, the roulette picks from that mood's pool. */
  moodId?: string | null
}

/**
 * "Pick for me" roulette. Pulls a pool of titles matching the current
 * Discover context (mood when active, otherwise top-rated by popularity),
 * filters out items the user already owns, and surfaces a single random
 * pick in a centered modal. Cheap dopamine hit + cure for choice paralysis.
 */
export default function Roulette({ kind, moodId }: Props) {
  const [open, setOpen] = useState(false)

  return (
    <>
      <button
        onClick={() => setOpen(true)}
        title="Pick something for me"
        aria-label="Pick something for me"
        className="inline-flex items-center gap-2 h-10 pl-3.5 pr-4 rounded-full bg-cool/15 hover:bg-cool/22 text-cool border border-cool/30 hover:border-cool/45 text-[12.5px] font-semibold tracking-tight transition-all duration-200 hover:scale-[1.03] active:scale-[0.97] focus-ring"
      >
        <Shuffle size={14} stroke={2.25} />
        Pick for me
      </button>

      <AnimatePresence>
        {open && (
          <RouletteModal kind={kind} moodId={moodId} onClose={() => setOpen(false)} />
        )}
      </AnimatePresence>
    </>
  )
}

function RouletteModal({
  kind,
  moodId,
  onClose,
}: {
  kind: 'movie' | 'tv'
  moodId?: string | null
  onClose: () => void
}) {
  const navigate = useNavigate()
  const hideAdult = usePreferencesStore(s => s.hideAdult)
  const lib = useLibraryByTmdbId()

  // Resolve the source query based on context. Mood wins when present;
  // otherwise fall back to popularity-sorted, well-voted picks.
  const mood = moodId ? DISCOVER_MOODS.find(m => m.id === moodId) : null
  const params =
    mood && (kind === 'movie' ? mood.movieParams : mood.tvParams)
    || {
      sort_by: 'popularity.desc',
      'vote_count.gte': '1000',
      'vote_average.gte': '6.5',
    }

  const movies = useTmdbDiscoverMovies(kind === 'movie' ? params : {})
  const tv = useTmdbDiscoverTv(kind === 'tv' ? params : {})
  const data = kind === 'movie' ? movies.data : tv.data
  const isLoading = kind === 'movie' ? movies.isLoading : tv.isLoading

  const pool = useMemo(() => {
    const raw = (data?.results || []).map(m => ({ ...m, media_type: kind })) as TmdbDiscoverItem[]
    let filtered = filterToMissing(raw, lib.data, hideAdult, m => !!m.adult)
    if (mood?.extra) filtered = filtered.filter(mood.extra as (m: TmdbDiscoverItem) => boolean)
    return filtered.filter(m => m.poster_path && m.overview)
  }, [data, lib.data, hideAdult, kind, mood])

  const [pickIndex, setPickIndex] = useState(() => Math.floor(Math.random() * 20))
  const [spinNonce, setSpinNonce] = useState(0)

  // Whenever the pool changes (mood swap / data loads), reseed the pick.
  useEffect(() => {
    if (pool.length > 0) {
      setPickIndex(Math.floor(Math.random() * pool.length))
    }
  }, [pool.length, moodId, kind])

  const pick = pool[pickIndex % Math.max(1, pool.length)] || null

  const spin = useCallback(() => {
    if (pool.length < 2) return
    let next = pickIndex
    // Avoid landing on the same pick consecutively.
    while (next === pickIndex) next = Math.floor(Math.random() * pool.length)
    setPickIndex(next)
    setSpinNonce(n => n + 1)
  }, [pool.length, pickIndex])

  const open = useCallback(() => {
    if (!pick) return
    const mediaType = pick.media_type === 'tv' || pick.first_air_date ? 'tv' : 'movie'
    navigate(`/item/tmdb-${mediaType}-${pick.id}`)
    onClose()
  }, [pick, navigate, onClose])

  useEffect(() => {
    function onKey(e: KeyboardEvent) {
      if (e.key === 'Escape') onClose()
      if (e.key === ' ') {
        e.preventDefault()
        spin()
      }
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [pickIndex, pool.length, onClose, spin])

  const title = pick?.title || pick?.name || ''
  const year = (pick?.release_date || pick?.first_air_date || '').slice(0, 4)
  const rating = typeof pick?.vote_average === 'number' ? pick.vote_average.toFixed(1) : null
  const overview: string = pick?.overview || ''
  const backdrop = pick?.backdrop_path ? `${TMDB_IMG}/w1280${pick.backdrop_path}` : null
  const poster = pick?.poster_path ? `${TMDB_IMG}/w500${pick.poster_path}` : null

  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      transition={{ duration: 0.18 }}
      className="fixed inset-0 z-toast grid place-items-center bg-black/70 backdrop-blur-sm"
      onClick={onClose}
    >
      <motion.div
        initial={{ opacity: 0, scale: 0.92, y: 16 }}
        animate={{ opacity: 1, scale: 1, y: 0 }}
        exit={{ opacity: 0, scale: 0.95, y: 8 }}
        transition={{ duration: 0.32, ease: [0.16, 1, 0.3, 1] }}
        onClick={e => e.stopPropagation()}
        className="relative w-[760px] max-w-[92vw] rounded-2xl overflow-hidden bg-[#0c0a08]/97 ring-1 ring-white/14 shadow-[0_40px_100px_-20px_rgba(0,0,0,0.85)]"
      >
        <button
          onClick={onClose}
          aria-label="Close"
          className="absolute top-3 right-3 z-20 w-9 h-9 grid place-items-center rounded-full text-white/75 hover:text-white hover:bg-white/10 transition-colors focus-ring"
        >
          <X size={16} />
        </button>

        {/* Backdrop band */}
        <div className="relative h-[260px] overflow-hidden">
          <AnimatePresence mode="wait">
            <motion.div
              key={`bg-${spinNonce}`}
              initial={{ opacity: 0, scale: 1.08 }}
              animate={{ opacity: 1, scale: 1 }}
              exit={{ opacity: 0 }}
              transition={{ duration: 0.5, ease: [0.16, 1, 0.3, 1] }}
              className="absolute inset-0"
            >
              {backdrop && (
                <img src={backdrop} alt="" className="w-full h-full object-cover" />
              )}
              <div className="absolute inset-0 bg-gradient-to-t from-[#0c0a08] via-[#0c0a08]/55 to-[#0c0a08]/20" />
            </motion.div>
          </AnimatePresence>
          <div className="absolute top-5 left-5 flex items-center gap-2 z-10">
            <span className="w-1 h-3 rounded-full bg-cool" />
            <span className="text-[10.5px] uppercase tracking-[0.2em] font-semibold text-cool">
              Pick for you
            </span>
            {mood && (
              <span className="text-[10.5px] text-white/55 tracking-tight">
                - {mood.label}
              </span>
            )}
          </div>
        </div>

        {/* Body */}
        <div className="-mt-24 relative px-7 pb-7 flex gap-5">
          <AnimatePresence mode="wait">
            <motion.div
              key={`poster-${spinNonce}`}
              initial={{ opacity: 0, y: 16, rotateY: 28 }}
              animate={{ opacity: 1, y: 0, rotateY: 0 }}
              exit={{ opacity: 0, y: -8, rotateY: -16 }}
              transition={{ duration: 0.45, ease: [0.16, 1, 0.3, 1] }}
              className="shrink-0 w-[140px] aspect-[2/3] rounded-xl overflow-hidden ring-1 ring-white/12 shadow-[0_18px_36px_-12px_rgba(0,0,0,0.8)] bg-elevated"
            >
              {poster ? (
                <img src={poster} alt={title} className="w-full h-full object-cover" />
              ) : (
                <div className="w-full h-full grid place-items-center text-white/40 text-3xl font-display">
                  ?
                </div>
              )}
            </motion.div>
          </AnimatePresence>

          <div className="flex-1 min-w-0 pt-24">
            <AnimatePresence mode="wait">
              <motion.div
                key={`info-${spinNonce}`}
                initial={{ opacity: 0, y: 8 }}
                animate={{ opacity: 1, y: 0 }}
                exit={{ opacity: 0, y: -4 }}
                transition={{ duration: 0.32, ease: [0.16, 1, 0.3, 1] }}
              >
                <h2 className="font-display text-[22px] md:text-[26px] font-bold text-white tracking-tight leading-[1.1] mb-1.5">
                  {title || (isLoading ? 'Spinning...' : 'No matches')}
                </h2>
                <div className="flex items-center gap-2 text-[11.5px] text-white/65 mb-3 tabular-nums">
                  {year && <span>{year}</span>}
                  {year && rating && <span className="text-white/30">·</span>}
                  {rating && (
                    <span className="inline-flex items-center gap-1 text-accent">
                      <Star size={11} fill="currentColor" stroke={0} />
                      {rating}
                    </span>
                  )}
                  <span className="text-white/30">·</span>
                  <span className="uppercase tracking-[0.14em] text-[10px] font-semibold text-white/55">
                    {kind === 'tv' ? 'Series' : 'Movie'}
                  </span>
                </div>
                <p className="text-[12.5px] text-white/80 leading-relaxed line-clamp-4">
                  {overview || (isLoading ? 'Pulling a pick...' : 'Try a different mood - this pool came back empty.')}
                </p>
              </motion.div>
            </AnimatePresence>
          </div>
        </div>

        {/* Actions */}
        <div className="px-7 pb-6 flex items-center gap-2.5">
          <button
            onClick={open}
            disabled={!pick}
            className="inline-flex items-center gap-2 h-10 px-5 rounded-full bg-accent hover:bg-accent-hover text-void text-[13px] font-semibold tracking-tight disabled:opacity-40 disabled:cursor-not-allowed transition-transform duration-200 hover:scale-[1.03] active:scale-[0.97] focus-ring shadow-[0_8px_24px_-8px_rgba(245,182,66,0.5)]"
          >
            View details
            <ArrowRight size={13} stroke={2.25} />
          </button>
          <button
            onClick={spin}
            disabled={pool.length < 2}
            className="inline-flex items-center gap-2 h-10 px-4 rounded-full bg-white/8 hover:bg-white/14 text-white/90 border border-white/15 hover:border-white/25 text-[12.5px] font-medium tracking-tight disabled:opacity-40 disabled:cursor-not-allowed transition-colors focus-ring"
            title="Spin again (Space)"
          >
            <RotateCw size={13} stroke={2.25} />
            Spin again
          </button>
          <span className="ml-auto text-[10.5px] text-white/40 tabular-nums">
            {pool.length > 0 ? `${pool.length} in pool` : ''}
          </span>
        </div>
      </motion.div>
    </motion.div>
  )
}
