import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import { Play, Check, ChevronRight, CloudOff } from '../../lib/icons'
import { useBulkMarkPlayed } from '../../hooks/use-jellyfin'
import { usePreferencesStore } from '../../stores/preferences-store'
import { formatRuntime } from '../../lib/format'
import { getBestImage, getStoredServerUrl } from '../../api/jellyfin'
import type { BaseItemDto } from '../../api/types'
import EpisodeRatingChip from './EpisodeRatingChip'
import FillerChip from './FillerChip'
import MetaBadges from '../ui/MetaBadges'
import SwipeReveal from '../ui/SwipeReveal'

interface Props {
  episode: BaseItemDto
  index: number
}

export default function EpisodeRow({ episode, index }: Props) {
  const serverUrl = getStoredServerUrl()
  const navigate = useNavigate()
  const [thumbErrored, setThumbErrored] = useState(false)
  const spoilerBlur = usePreferencesStore(s => s.episode.show.spoilerBlur)
  const showFillerChips = usePreferencesStore(s => s.episode.show.fillerChips)
  const showRatingChips = usePreferencesStore(s => s.episode.show.ratingChips)
  const swipeActionsEnabled = usePreferencesStore(s => s.episode.behavior.swipeActions)
  const markPlayed = useBulkMarkPlayed()

  const thumbUrl = getBestImage(serverUrl, episode, 'thumb', 360)
  const showThumb = thumbUrl && !thumbErrored

  const isWatched = episode.UserData?.Played
  const progress = episode.UserData?.PlayedPercentage
  const runtime = episode.RunTimeTicks ? formatRuntime(episode.RunTimeTicks) : null

  // Missing = file not on disk. Jellyfin's canonical signal is LocationType:
  // "Virtual" means aired but not acquired, "FileSystem" means we have the
  // file. Trusting LocationType matches what Jellyfin's own UI does.
  const isMissing = (episode as { LocationType?: string }).LocationType === 'Virtual'

  function goToDetail() {
    if (!episode.Id) return
    navigate(`/item/${episode.Id}`)
  }
  function goToPlay(e: React.MouseEvent) {
    e.stopPropagation()
    if (isMissing || !episode.Id) return
    navigate(`/play/${episode.Id}`)
  }

  return (
    <SwipeReveal
      enabled={swipeActionsEnabled}
      actions={episode.Id && !isMissing ? [
        {
          label: isWatched ? 'Unwatched' : 'Watched',
          tone: isWatched ? 'neutral' : 'accent',
          onPress: () => {
            if (!episode.Id) return
            markPlayed.mutate({ itemIds: [episode.Id], played: !isWatched })
          },
        },
      ] : []}
    >
    <motion.div
      onClick={goToDetail}
      onKeyDown={e => {
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault()
          goToDetail()
        }
      }}
      role="button"
      tabIndex={0}
      aria-label={`View ${episode.Name || 'episode'} details`}
      initial={{ opacity: 0, y: 6 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.3, delay: Math.min(index * 0.025, 0.3), ease: [0.16, 1, 0.3, 1] }}
      className={`w-full group flex gap-4 p-3 rounded-lg transition-all duration-200 text-left focus-ring cursor-pointer ${
        isMissing ? 'opacity-55' : 'hover:bg-elevated/60'
      }`}
    >
      <button
        type="button"
        onClick={goToPlay}
        disabled={isMissing}
        aria-label={isMissing ? 'Episode missing' : `Play ${episode.Name || 'episode'}`}
        className={`w-[180px] aspect-video rounded-md overflow-hidden bg-elevated shrink-0 relative focus-ring ${
          isMissing ? 'ring-1 ring-error/25 cursor-not-allowed' : 'ring-1 ring-border cursor-pointer'
        }`}
      >
        {showThumb ? (
          <img
            src={thumbUrl}
            alt=""
            onError={() => setThumbErrored(true)}
            className={`w-full h-full object-cover transition-[transform,filter] duration-500 group-hover:scale-105 ${
              spoilerBlur && !isWatched ? 'blur-md saturate-50 group-hover:blur-0 group-hover:saturate-100' : ''
            }`}
            loading="lazy"
          />
        ) : (
          <div className="w-full h-full grid place-items-center bg-gradient-to-br from-elevated to-surface">
            <span className="text-text-4 text-2xl font-display font-semibold opacity-50 select-none">
              {episode.IndexNumber != null ? `E${episode.IndexNumber}` : (episode.Name || '?')[0]?.toUpperCase()}
            </span>
          </div>
        )}
        <div className="absolute inset-0 bg-gradient-to-t from-black/40 to-transparent" />
        {!isMissing && (
          <div className="absolute inset-0 grid place-items-center opacity-0 group-hover:opacity-100 transition-opacity duration-200">
            <div className="w-11 h-11 rounded-full bg-accent grid place-items-center shadow-lg shadow-black/40">
              <Play size={16} className="text-void translate-x-0.5" fill="currentColor" />
            </div>
          </div>
        )}
        {isMissing && (
          <div className="absolute inset-0 grid place-items-center bg-black/40">
            <div className="flex flex-col items-center gap-1 text-error">
              <CloudOff size={20} />
              <span className="text-[9px] font-bold uppercase tracking-[0.12em]">Missing</span>
            </div>
          </div>
        )}
        {progress != null && progress > 0 && (
          <div className="absolute bottom-0 left-0 right-0 h-[2px] bg-black/30">
            <div
              className="h-full bg-accent shadow-[0_0_6px_rgba(245,182,66,0.5)]"
              style={{ width: `${progress}%` }}
            />
          </div>
        )}
        <div className="absolute top-1.5 right-1.5">
          <MetaBadges item={episode} />
        </div>
      </button>

      <div className="flex-1 min-w-0 py-0.5">
        <div className="flex items-baseline gap-2.5 mb-1.5">
          {episode.IndexNumber != null && (
            <span className="text-accent/80 text-[11px] tabular-nums font-mono font-semibold tracking-wider shrink-0">
              {String(episode.IndexNumber).padStart(2, '0')}
            </span>
          )}
          <span className="text-[14.5px] text-text-1 font-semibold tracking-tight leading-tight truncate">
            {episode.Name}
          </span>
          {isWatched && (
            <span className="shrink-0 w-4 h-4 rounded-full bg-accent grid place-items-center self-center">
              <Check size={9} className="text-void" strokeWidth={3} />
            </span>
          )}
          {isMissing && (
            <span className="shrink-0 inline-flex items-center gap-1 h-4 px-1.5 rounded bg-error/15 text-error text-[9px] font-bold uppercase tracking-[0.06em] self-center">
              <CloudOff size={8} />
              Missing
            </span>
          )}
          {showFillerChips && (
            <span className="shrink-0 self-center">
              <FillerChip
                season={episode.ParentIndexNumber ?? null}
                episode={episode.IndexNumber ?? null}
              />
            </span>
          )}
          <span className="ml-auto flex items-center gap-2 shrink-0 text-[11px] text-text-4 tabular-nums">
            {showRatingChips && (
              <EpisodeRatingChip
                season={episode.ParentIndexNumber ?? null}
                episode={episode.IndexNumber ?? null}
              />
            )}
            {episode.PremiereDate && (
              <span>
                {new Date(episode.PremiereDate).toLocaleDateString(undefined, {
                  year: 'numeric',
                  month: 'short',
                  day: 'numeric',
                })}
              </span>
            )}
            {episode.PremiereDate && runtime && <span className="text-text-5">·</span>}
            {runtime && <span>{runtime}</span>}
          </span>
        </div>
        {episode.Overview && (
          <p
            className={`text-[12.5px] text-text-3 leading-[1.65] line-clamp-2 max-w-[78ch] tracking-[-0.005em] [text-wrap:pretty] transition-[filter,color] duration-200 ${
              spoilerBlur && !isWatched
                ? 'blur-[3px] text-text-4 group-hover:blur-0 group-hover:text-text-3'
                : ''
            }`}
          >
            {episode.Overview}
          </p>
        )}
      </div>

      <ChevronRight
        size={18}
        className="text-text-4 self-center opacity-0 group-hover:opacity-100 transition-all duration-200 -translate-x-1 group-hover:translate-x-0"
      />
    </motion.div>
    </SwipeReveal>
  )
}
