import { useMemo, useState } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import { Cake, MapPin, Skull, ExternalLink, ChevronDown } from '../lib/icons'
import { useTmdbPerson } from '../hooks/use-tmdb'
import { useWikiResolve } from '../hooks/use-external'
import { getTmdbImageUrl } from '../api/tmdb'
import type { TmdbCombinedCreditCast, TmdbCombinedCreditCrew } from '../api/tmdb'
import { formatDate } from '../lib/format'
import { usePosterGridClasses } from '../lib/density'

const DEPT_FILTERS = ['All', 'Acting', 'Directing', 'Writing', 'Production', 'Camera', 'Editing', 'Sound']

export default function PersonPage() {
  const { id } = useParams<{ id: string }>()
  const navigate = useNavigate()
  const { data: person, isLoading } = useTmdbPerson(id)
  const gridCls = usePosterGridClasses()

  // Wikipedia bio fallback - only fetched when TMDB has no biography of
  // its own. The query is the person's name; first matching article wins.
  const wikiEnabled = !!person && (!person.biography || person.biography.length < 60)
  const { data: wiki } = useWikiResolve(person?.name, wikiEnabled)

  const [bioExpanded, setBioExpanded] = useState(false)
  const [filter, setFilter] = useState<string>('All')

  const filmography = useMemo(() => {
    const cast = (person?.combined_credits?.cast || []).map(c => ({ ...c, _kind: 'cast' as const }))
    const crew = (person?.combined_credits?.crew || []).map(c => ({ ...c, _kind: 'crew' as const }))
    type MergedCredit =
      | (TmdbCombinedCreditCast & { _kind: 'cast' })
      | (TmdbCombinedCreditCrew & { _kind: 'crew' })
    let merged: MergedCredit[] = [
      ...cast,
      ...crew,
    ]

    if (filter !== 'All') {
      if (filter === 'Acting') {
        merged = merged.filter(c => c._kind === 'cast')
      } else {
        merged = merged.filter((c): c is MergedCredit & { _kind: 'crew' } => c._kind === 'crew' && c.department === filter)
      }
    }

    // De-duplicate by media id (a person may appear in cast + crew)
    const seen = new Set<string>()
    const unique: typeof merged = []
    for (const c of merged) {
      const key = `${c.media_type}-${c.id}`
      if (seen.has(key)) continue
      seen.add(key)
      unique.push(c)
    }

    // Sort by popularity, then date
    return unique.sort((a, b) => {
      const pa = a.popularity ?? 0
      const pb = b.popularity ?? 0
      if (pb !== pa) return pb - pa
      const da = (a.release_date || a.first_air_date || '0').slice(0, 4)
      const db = (b.release_date || b.first_air_date || '0').slice(0, 4)
      return db.localeCompare(da)
    })
  }, [person, filter])

  if (isLoading) return <PersonSkeleton />
  if (!person) {
    return (
      <div className="flex flex-col items-center justify-center h-[60vh] text-center px-6">
        <p className="text-text-2 text-[15px] mb-1">Person not found</p>
        <p className="text-text-4 text-[12px]">No TMDB key configured, or this person isn't in TMDB.</p>
      </div>
    )
  }

  const profile = person.profile_path ? getTmdbImageUrl(person.profile_path, 'w500') : ''
  const department = person.known_for_department || 'Acting'

  return (
    <div className="px-7 pt-6 pb-12">
      {/* Top row */}
      <div className="grid md:grid-cols-[180px_1fr] gap-7 mb-9">
        <motion.div
          initial={{ opacity: 0, scale: 0.96 }}
          animate={{ opacity: 1, scale: 1 }}
          transition={{ duration: 0.5, ease: [0.16, 1, 0.3, 1] }}
          className="relative w-full max-w-[180px] aspect-[2/3] rounded-xl overflow-hidden ring-1 ring-border bg-elevated mx-auto md:mx-0"
        >
          {profile ? (
            <img src={profile} alt={person.name} className="w-full h-full object-cover" />
          ) : (
            <div className="w-full h-full grid place-items-center text-text-3 text-3xl font-display">
              {person.name[0]}
            </div>
          )}
        </motion.div>

        <motion.div
          initial={{ opacity: 0, y: 10 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.5, delay: 0.1, ease: [0.16, 1, 0.3, 1] }}
        >
          <p className="text-[10px] uppercase tracking-[0.14em] text-accent font-semibold mb-1">
            {department}
          </p>
          <h1 className="font-display text-3xl md:text-4xl font-bold text-text-1 tracking-tight mb-3">
            {person.name}
          </h1>

          <div className="flex items-center gap-4 flex-wrap text-[12.5px] text-text-3 mb-5">
            {person.birthday && (
              <span className="inline-flex items-center gap-1.5">
                <Cake size={12} />
                {formatDate(person.birthday)}
                {!person.deathday && (
                  <span className="text-text-4">({yearsSince(person.birthday)})</span>
                )}
              </span>
            )}
            {person.deathday && (
              <span className="inline-flex items-center gap-1.5">
                <Skull size={12} />
                {formatDate(person.deathday)}
              </span>
            )}
            {person.place_of_birth && (
              <span className="inline-flex items-center gap-1.5">
                <MapPin size={12} />
                {person.place_of_birth}
              </span>
            )}
          </div>

          {(person.biography || wiki?.extract) && (
            <div>
              <p
                className={`text-[13px] text-text-2 leading-relaxed max-w-[72ch] whitespace-pre-line ${
                  !bioExpanded ? 'line-clamp-6' : ''
                }`}
              >
                {person.biography || wiki?.extract}
              </p>
              {(person.biography || wiki?.extract || '').length > 600 && (
                <button
                  onClick={() => setBioExpanded(b => !b)}
                  className="text-[12px] text-accent hover:text-accent-hover transition-colors font-medium mt-1.5 inline-flex items-center gap-1 focus-ring rounded"
                >
                  {bioExpanded ? 'Show less' : 'Read more'}
                  <ChevronDown
                    size={12}
                    className={`transition-transform duration-200 ${bioExpanded ? 'rotate-180' : ''}`}
                  />
                </button>
              )}
              {!person.biography && wiki && (
                <p className="text-[10.5px] text-text-4 mt-1.5">Source: Wikipedia</p>
              )}
            </div>
          )}

          {/* External links */}
          <div className="flex items-center gap-1.5 mt-5 flex-wrap">
            {person.imdb_id && (
              <ExternalLinkChip href={`https://www.imdb.com/name/${person.imdb_id}/`} label="IMDb" />
            )}
            <ExternalLinkChip
              href={`https://www.themoviedb.org/person/${person.id}`}
              label="TMDB"
            />
            {person.external_ids?.instagram_id && (
              <ExternalLinkChip
                href={`https://instagram.com/${person.external_ids.instagram_id}`}
                label="Instagram"
              />
            )}
            {person.external_ids?.twitter_id && (
              <ExternalLinkChip
                href={`https://twitter.com/${person.external_ids.twitter_id}`}
                label="Twitter"
              />
            )}
            {person.homepage && <ExternalLinkChip href={person.homepage} label="Website" />}
          </div>
        </motion.div>
      </div>

      {/* Filmography */}
      <div className="mb-3 flex items-center justify-between gap-4 flex-wrap">
        <div className="flex items-center gap-2">
          <span className="w-1 h-3.5 rounded-full bg-accent" />
          <h3 className="text-[11px] font-semibold text-text-2 uppercase tracking-[0.14em]">
            Filmography
          </h3>
          <span className="text-[11px] text-text-4 tabular-nums">
            ({filmography.length})
          </span>
        </div>
        <div className="flex items-center gap-1 p-0.5 bg-elevated/60 border border-border rounded-md overflow-x-auto hide-scrollbar">
          {DEPT_FILTERS.map(d => {
            const isActive = filter === d
            return (
              <button
                key={d}
                onClick={() => setFilter(d)}
                className={`relative h-7 px-2.5 rounded text-[11.5px] font-medium tracking-tight whitespace-nowrap transition-colors duration-150 focus-ring ${
                  isActive ? 'text-void' : 'text-text-3 hover:text-text-1'
                }`}
              >
                {isActive && (
                  <motion.span
                    layoutId="filmo-active"
                    className="absolute inset-0 bg-accent rounded"
                    transition={{ type: 'spring', stiffness: 380, damping: 30 }}
                  />
                )}
                <span className="relative">{d}</span>
              </button>
            )
          })}
        </div>
      </div>

      {filmography.length === 0 ? (
        <p className="text-[13px] text-text-4 mt-4">No credits in this category.</p>
      ) : (
        <div className={gridCls}>
          {filmography.map((c, i) => {
            const title = c.title || c.name || 'Untitled'
            const year = (c.release_date || c.first_air_date || '').slice(0, 4)
            return (
              <motion.button
                key={`${c.media_type}-${c.id}-${c.credit_id}`}
                onClick={() => navigate(`/item/tmdb-${c.id}`)}
                initial={{ opacity: 0, y: 8 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ duration: 0.3, delay: Math.min(i * 0.012, 0.4) }}
                whileHover={{ y: -3 }}
                className="group text-left focus-ring rounded-lg"
              >
                <div className="relative aspect-[2/3] rounded-lg overflow-hidden bg-elevated ring-1 ring-border group-hover:ring-accent/30 transition-all duration-200">
                  {c.poster_path ? (
                    <img
                      src={getTmdbImageUrl(c.poster_path, 'w300')}
                      alt={title}
                      loading="lazy"
                      className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
                    />
                  ) : (
                    <div className="w-full h-full grid place-items-center text-text-3 text-2xl font-display">
                      {title[0]}
                    </div>
                  )}
                  <div className="absolute top-1.5 left-1.5">
                    <span className="inline-flex items-center h-[18px] px-1.5 rounded text-[9px] font-bold tracking-[0.04em] uppercase bg-black/55 backdrop-blur text-white border border-white/10">
                      {c.media_type === 'tv' ? 'TV' : 'Film'}
                    </span>
                  </div>
                </div>
                <div className="mt-2 px-px">
                  <p className="text-[12.5px] font-medium text-text-1 truncate leading-tight tracking-tight">
                    {title}
                  </p>
                  <p className="text-[11px] text-text-3 truncate leading-tight mt-0.5">
                    {c.character ? c.character : (c as TmdbCombinedCreditCrew).job}
                    {year && (
                      <>
                        <span className="text-text-5 mx-1">·</span>
                        <span className="tabular-nums">{year}</span>
                      </>
                    )}
                  </p>
                </div>
              </motion.button>
            )
          })}
        </div>
      )}
    </div>
  )
}

function ExternalLinkChip({ href, label }: { href: string; label: string }) {
  return (
    <a
      href={href}
      target="_blank"
      rel="noopener noreferrer"
      className="inline-flex items-center gap-1 h-7 px-2.5 bg-elevated/60 hover:bg-elevated border border-border hover:border-border-hover rounded-md text-[11px] text-text-2 hover:text-text-1 transition-colors focus-ring"
    >
      {label}
      <ExternalLink size={10} className="text-text-4" />
    </a>
  )
}

function yearsSince(iso: string): string {
  try {
    const d = new Date(iso)
    const years = (Date.now() - d.getTime()) / (365.25 * 24 * 3600 * 1000)
    return `${Math.floor(years)} yrs`
  } catch {
    return ''
  }
}

function PersonSkeleton() {
  const gridCls = usePosterGridClasses()
  return (
    <div className="px-7 pt-6 pb-12">
      <div className="grid md:grid-cols-[180px_1fr] gap-7 mb-9">
        <div className="aspect-[2/3] skeleton rounded-xl" />
        <div className="space-y-3">
          <div className="skeleton h-3 w-24 rounded" />
          <div className="skeleton h-9 w-2/3 rounded" />
          <div className="skeleton h-3 w-1/2 rounded" />
          <div className="skeleton h-20 w-full rounded mt-3" />
        </div>
      </div>
      <div className={gridCls}>
        {Array.from({ length: 14 }).map((_, i) => (
          <div key={i}>
            <div className="skeleton aspect-[2/3] rounded-lg" />
            <div className="skeleton h-3 w-3/4 mt-2 rounded" />
            <div className="skeleton h-2.5 w-1/2 mt-1 rounded" />
          </div>
        ))}
      </div>
    </div>
  )
}
