import { useMemo, useState } from 'react'
import { useParams } from 'react-router-dom'
import {
  useItemDetails,
  useLibraryByTmdbId,
  useRefreshItem,
  useSampleEpisode,
  useBulkToggleFavorite,
} from '../hooks/use-jellyfin'
import { useTmdbMovie, useTmdbTvShow, useTmdbCollection } from '../hooks/use-tmdb'
import {
  useCinemeta,
  useFanartMovie,
  useFanartTv,
  useTvmazeByImdbId,
  useWikiResolve,
  useWikiSection,
  useWikidataAwards,
  useWikidataLocations,
  useRottenTomatoes,
} from '../hooks/use-external'
import { pickBestFanartImage } from '../api/fanart'
import DetailHero from '../components/detail/DetailHero'
import DetailStickyBar from '../components/detail/DetailStickyBar'
import type { SectionTab } from '../components/detail/DetailSectionTabs'
import DetailSkeleton from '../components/detail/DetailSkeleton'
import DetailMainSections from '../components/detail/DetailMainSections'
import { usePastSentinel } from '../hooks/use-past-sentinel'
import { parseTmdbRouteId } from '../lib/tmdb-mapping'
import TmdbDetailPage from './TmdbDetailPage'
import { getBestImage, getImageUrl, getStoredServerUrl } from '../api/jellyfin'
import PlaylistView from '../components/detail/PlaylistView'
import FolderView from '../components/detail/FolderView'
import { formatRuntime, regionForUser } from '../lib/format'
import { usePreferencesStore } from '../stores/preferences-store'

export default function DetailPage() {
  const { id } = useParams<{ id: string }>()
  // Synthetic TMDB ids from discovery rows route to a dedicated TMDB-only
  // page so items not in the library get a proper detail view + Request CTA.
  const tmdbRoute = parseTmdbRouteId(id)
  if (tmdbRoute) return <TmdbDetailPage tmdbId={tmdbRoute.tmdbId} kind={tmdbRoute.kind} />
  return <LibraryDetailPage id={id} />
}

function LibraryDetailPage({ id }: { id?: string }) {
  const { data: item, isLoading } = useItemDetails(id)
  const { sentinelRef: stickySentinelRef, past: pastHero } = usePastSentinel()
  const toggleFavorite = useBulkToggleFavorite()

  const itemType = item?.Type
  const tmdbId = item?.ProviderIds?.Tmdb
  const imdbId = item?.ProviderIds?.Imdb || null
  const tvdbId = item?.ProviderIds?.Tvdb || null

  const tmdbMovie = useTmdbMovie(itemType === 'Movie' ? tmdbId : null)
  const tmdbTv = useTmdbTvShow(itemType === 'Series' ? tmdbId : null)
  const tmdbData = itemType === 'Movie' ? tmdbMovie.data : tmdbTv.data

  // External enrichment - all keyless except Fanart.tv which silently no-ops
  // when the personal key is empty. Each hook gates on type so we don't fire
  // movie endpoints for shows or vice versa.
  const fanartMovieQuery = useFanartMovie(itemType === 'Movie' ? (tmdbId || imdbId) : null)
  const fanartTvQuery = useFanartTv(itemType === 'Series' ? tvdbId : null)
  const cinemetaQuery = useCinemeta(
    imdbId,
    itemType === 'Movie' ? 'movie' : itemType === 'Series' ? 'series' : undefined,
  )
  const tvmazeQuery = useTvmazeByImdbId(itemType === 'Series' ? imdbId : null)

  // Wikipedia overview fallback - resolved by title+year when neither
  // Jellyfin/TMDB nor Cinemeta produced anything substantial. Hook must run
  // unconditionally so it goes here, above any early returns.
  const baseOverview = item?.Overview || tmdbData?.overview || ''
  const overviewIsThin = baseOverview.trim().length < 60
  const cinemetaDescription = cinemetaQuery.data?.description || ''
  const wikiQuery = useWikiResolve(
    item?.Name && item?.ProductionYear
      ? `${item.Name} ${item.ProductionYear}`
      : item?.Name,
    !!item && overviewIsThin && !cinemetaDescription,
  )

  // Wikipedia "Production" section, resolved unconditionally so the trivia
  // block can render even when the overview is fine. We need a known title
  // first; we always run a quick resolve for that and then ask for the
  // section. Cheap because both queries are cached for a week.
  const wikiTitleQuery = useWikiResolve(
    item?.Name && item?.ProductionYear
      ? `${item.Name} ${item.ProductionYear}`
      : item?.Name,
    !!item,
  )
  const wikiTitle = wikiTitleQuery.data?.title || null
  const wikiProductionQuery = useWikiSection(wikiTitle, 'Production')

  // Wikidata awards via SPARQL P166. Keyed off the TMDB external_ids
  // wikidata_id field which we already pull on movie + tv full responses.
  const wikidataId = tmdbData?.external_ids?.wikidata_id || null
  const awardsQuery = useWikidataAwards(wikidataId)
  const locationsQuery = useWikidataLocations(wikidataId)

  const collectionId = tmdbMovie.data?.belongs_to_collection?.id
  const tmdbCollection = useTmdbCollection(collectionId)

  // Rotten Tomatoes critic + audience scores (Algolia search by title+year,
  // same approach Jellyseerr uses). Series ratings work, episode ratings
  // would be hit-or-miss so we only fire on Movie / Series.
  const rtKind: 'movie' | 'tv' | null =
    itemType === 'Movie' ? 'movie' : itemType === 'Series' ? 'tv' : null
  const rtYear = itemType === 'Movie'
    ? (tmdbMovie.data?.release_date ? Number(tmdbMovie.data.release_date.slice(0, 4)) : item?.ProductionYear) || null
    : itemType === 'Series'
      ? (tmdbTv.data?.first_air_date ? Number(tmdbTv.data.first_air_date.slice(0, 4)) : item?.ProductionYear) || null
      : null
  const rtName =
    itemType === 'Movie'
      ? tmdbMovie.data?.title || item?.Name
      : itemType === 'Series'
        ? tmdbTv.data?.name || item?.Name
        : null
  const rtQuery = useRottenTomatoes(rtName, rtYear, rtKind)

  const prefs = usePreferencesStore()
  const region = prefs.region || regionForUser()
  const showTmdbRatings = prefs.showTmdbRatings

  const libraryMap = useLibraryByTmdbId()
  const refresh = useRefreshItem()
  const sampleEpisode = useSampleEpisode(id, itemType === 'Series')

  // Versions selector state
  const sources = item?.MediaSources || []
  const [selectedSourceId, setSelectedSourceId] = useState<string | null>(null)
  const activeSourceId = selectedSourceId || sources[0]?.Id || null

  // Pick a regional certification when available (must run before early returns)
  const regionalCert = useMemo(() => {
    if (itemType === 'Movie') {
      const dates = (tmdbMovie.data?.release_dates?.results || []).find(r => r.iso_3166_1 === region)
      return dates?.release_dates?.find(d => d.certification)?.certification || null
    }
    if (itemType === 'Series') {
      const r = (tmdbTv.data?.content_ratings?.results || []).find(r => r.iso_3166_1 === region)
      return r?.rating || null
    }
    return null
  }, [itemType, tmdbMovie.data, tmdbTv.data, region])

  if (isLoading) return <DetailSkeleton />

  if (!item) {
    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">Item not found</p>
        <p className="text-text-4 text-[12px]">The item you're looking for may have been removed.</p>
      </div>
    )
  }

  const serverUrl = getStoredServerUrl()

  const jellyfinBackdrop = getBestImage(serverUrl, item, 'backdrop', 1920)
  // Fanart backdrop fallback - useful for older / lesser-known items where
  // the Jellyfin scraper didn't fetch a backdrop. Voted-best English wins.
  const fanartBackdrop = pickBestFanartImage(
    fanartMovieQuery.data?.moviebackground
      || fanartTvQuery.data?.showbackground
      || undefined,
  )
  const backdropUrl = jellyfinBackdrop || fanartBackdrop?.url || null
  const posterUrl = getBestImage(serverUrl, item, 'primary', 400)

  // Logo priority: Jellyfin Logo (locally curated) > Fanart.tv HD logo
  // (cinematic SVG/PNG) > none (falls back to title typography).
  const fanartLogo = pickBestFanartImage(
    fanartMovieQuery.data?.hdmovielogo
      || fanartMovieQuery.data?.movielogo
      || fanartTvQuery.data?.hdtvlogo
      || fanartTvQuery.data?.clearlogo
      || undefined,
  )
  const jellyfinLogo =
    item.Id && item.ImageTags?.Logo
      ? getImageUrl(serverUrl, item.Id, 'Logo', 600, item.ImageTags.Logo)
      : null
  const logoUrl = jellyfinLogo || fanartLogo?.url || null

  const progress = item.UserData?.PlayedPercentage
  const positionTicks = item.UserData?.PlaybackPositionTicks
  const resumeThresholdSec = prefs.resumeThresholdSec
  const watchedSec = positionTicks ? Number(positionTicks) / 10_000_000 : 0
  // Only offer resume when we've watched past the threshold (and we're not effectively done)
  const meetsResumeThreshold = watchedSec >= resumeThresholdSec && (progress ?? 0) < 95
  const resumeTime = positionTicks && meetsResumeThreshold ? formatRuntime(Number(positionTicks)) : null
  const runtime = item.RunTimeTicks ? formatRuntime(item.RunTimeTicks) : null

  const genres = item.Genres || []
  const tmdbCredits = tmdbData?.credits
  const cast = tmdbCredits?.cast?.slice(0, 18) || []
  const crew = tmdbCredits?.crew || []
  const trailer = tmdbData?.videos?.results?.find(
    v => v.site === 'YouTube' && v.type === 'Trailer',
  )
  const hideAdult = prefs.hideAdult
  const adultFilter = <T extends { adult?: boolean }>(arr: T[]) =>
    hideAdult ? arr.filter(x => !x.adult) : arr
  const recommendations = adultFilter((tmdbData?.recommendations?.results || []) as { id: number; adult?: boolean }[])
  // Movie + TV similar arrays don't share an exact element type, so widen
  // to the adultFilter constraint to keep TS happy across the union.
  const similarRaw = itemType === 'Movie'
    ? tmdbMovie.data?.similar?.results || []
    : tmdbTv.data?.similar?.results || []
  const similar = adultFilter(similarRaw as { id: number; adult?: boolean }[])
  const keywords =
    itemType === 'Movie'
      ? tmdbMovie.data?.keywords?.keywords || []
      : tmdbTv.data?.keywords?.results || []
  const reviews = tmdbData?.reviews?.results || []

  const title = item.Name || 'Untitled'
  const year = item.ProductionYear
  // Final overview chain (computed values - the source flags + base/thin
  // were already established up at the top so the hook ordering is stable).
  const overview = baseOverview
    || cinemetaDescription
    || wikiQuery.data?.extract
    || ''
  const overviewSource = baseOverview
    ? null
    : cinemetaDescription
      ? 'IMDB'
      : wikiQuery.data
        ? 'Wikipedia'
        : null
  const taglineText = tmdbData?.tagline

  const rating = regionalCert || item.OfficialRating

  const isFavorite = item.UserData?.IsFavorite

  const isFolder =
    itemType === 'CollectionFolder' ||
    itemType === 'ManualPlaylistsFolder' ||
    itemType === 'PlaylistsFolder'
  if (isFolder) {
    return <FolderView itemId={id!} title={item.Name || 'Library'} collectionType={item.CollectionType} />
  }

  // Playlists get a purpose-built view: hero with Play / Shuffle, item list
  // with thumbs and watched status. No tech specs, no episodes section.
  if (itemType === 'Playlist') {
    return <PlaylistView item={item} serverUrl={serverUrl} />
  }

  const playUrl = `/play/${item.Id}${activeSourceId && sources.length > 1 ? `?source=${activeSourceId}` : ''}`
  const resumeUrl = `/play/${item.Id}?resume=true${activeSourceId && sources.length > 1 ? `&source=${activeSourceId}` : ''}`

  const watchProviders =
    itemType === 'Movie' ? tmdbMovie.data?.['watch/providers'] : tmdbTv.data?.['watch/providers']

  return (
    <div className="pb-16">
      <DetailStickyBar
        visible={pastHero}
        title={title}
        logoUrl={logoUrl}
        posterUrl={posterUrl}
        progress={progress}
        isFavorite={isFavorite}
        playUrl={playUrl}
        resumeUrl={resumeUrl}
        tmdbId={tmdbId}
        imdbId={imdbId}
        itemType={itemType}
        tabs={detailTabsFor(itemType)}
        onFavoriteToggle={
          item.Id
            ? () => toggleFavorite.mutate({ itemIds: [item.Id!], favorite: !isFavorite })
            : undefined
        }
      />
      <DetailHero
        item={item}
        itemType={itemType ?? ""}
        tmdbMovieData={tmdbMovie.data}
        tmdbTvData={tmdbTv.data}
        tmdbId={tmdbId}
        posterUrl={posterUrl}
        logoUrl={logoUrl}
        backdropUrl={backdropUrl}
        title={title}
        year={year}
        rating={rating}
        runtime={runtime}
        taglineText={taglineText}
        genres={genres}
        resumeTime={resumeTime}
        progress={progress}
        isFavorite={isFavorite}
        playUrl={playUrl}
        resumeUrl={resumeUrl}
        trailer={trailer}
        cinemetaData={cinemetaQuery.data}
        showTmdbRatings={showTmdbRatings}
        sampleEpisode={sampleEpisode}
        refresh={refresh}
      />

      <div ref={stickySentinelRef} aria-hidden className="h-px -mt-px" />

      <DetailMainSections
        item={item}
        itemId={id}
        itemType={itemType ?? ""}
        imdbId={imdbId}
        tmdbId={tmdbId}
        tmdbMovieData={tmdbMovie.data}
        tmdbTvData={tmdbTv.data}
        tmdbCollectionData={tmdbCollection.data}
        cinemetaData={cinemetaQuery.data}
        tvmazeData={tvmazeQuery.data}
        wikiProduction={wikiProductionQuery.data}
        awardsData={awardsQuery.data}
        locationsData={locationsQuery.data}
        rtData={rtQuery.data}
        wikiTitle={wikiTitle}
        region={region}
        watchProviders={watchProviders}
        cast={cast}
        crew={crew}
        keywords={keywords}
        reviews={reviews}
        videos={tmdbData?.videos?.results}
        recommendations={recommendations}
        similar={similar}
        libraryMap={libraryMap.data}
        overview={overview}
        overviewSource={overviewSource}
        sources={sources}
        activeSourceId={activeSourceId}
        onSourceChange={setSelectedSourceId}
      />
    </div>
  )
}

function detailTabsFor(itemType: string | undefined): SectionTab[] {
  return [
    { id: 'detail-overview', label: 'Overview' },
    ...(itemType === 'Series' ? [{ id: 'detail-episodes', label: 'Episodes' } as SectionTab] : []),
    { id: 'detail-reception', label: 'Reception' },
    { id: 'detail-cast', label: 'Cast & crew' },
    { id: 'detail-trivia', label: 'Trivia' },
    { id: 'detail-reviews', label: 'Reviews' },
    { id: 'detail-more', label: 'More like this' },
  ]
}

