import { useQueries, useQuery } from '@tanstack/react-query'
import {
  getMovieFull,
  getTvShowFull,
  getSeasonFull,
  getEpisodeFull,
  getEpisodeGroup,
  getPersonFull,
  getCollection,
  getTrending,
  searchMulti,
  discoverMovies,
  discoverTv,
  getUpcomingMovies,
  getTopRatedMovies,
  getTopRatedTv,
} from '../api/tmdb'

const STALE = 24 * 60 * 60 * 1000

export function useTmdbMovie(tmdbId?: string | number | null) {
  const id = tmdbId ? Number(tmdbId) : undefined
  return useQuery({
    queryKey: ['tmdb', 'movie-full', id],
    queryFn: async () => {
      if (!id) return null
      return getMovieFull(id)
    },
    enabled: !!id,
    staleTime: STALE,
  })
}

export function useTmdbTvShow(tmdbId?: string | number | null) {
  const id = tmdbId ? Number(tmdbId) : undefined
  return useQuery({
    queryKey: ['tmdb', 'tv-full', id],
    queryFn: async () => {
      if (!id) return null
      return getTvShowFull(id)
    },
    enabled: !!id,
    staleTime: STALE,
  })
}

export function useTmdbSeason(tvId?: string | number | null, seasonNum?: number) {
  const id = tvId ? Number(tvId) : undefined
  return useQuery({
    queryKey: ['tmdb', 'season-full', id, seasonNum],
    queryFn: async () => {
      if (!id || seasonNum === undefined) return null
      return getSeasonFull(id, seasonNum)
    },
    enabled: !!id && seasonNum !== undefined,
    staleTime: STALE,
  })
}

export function useTmdbEpisode(
  tvId?: string | number | null,
  seasonNum?: number,
  episodeNum?: number,
) {
  const id = tvId ? Number(tvId) : undefined
  return useQuery({
    queryKey: ['tmdb', 'episode-full', id, seasonNum, episodeNum],
    queryFn: async () => {
      if (!id || seasonNum === undefined || episodeNum === undefined) return null
      return getEpisodeFull(id, seasonNum, episodeNum)
    },
    enabled: !!id && seasonNum !== undefined && episodeNum !== undefined,
    staleTime: STALE,
  })
}

/**
 * Fetch a TMDB episode-group's ordered list. Used by the episode order
 * toggle to reorder the visible episode list to match alternate
 * orderings (production, story, DVD).
 */
export function useTmdbEpisodeGroup(groupId?: string | null) {
  return useQuery({
    queryKey: ['tmdb', 'episode-group', groupId],
    queryFn: async () => {
      if (!groupId) return null
      return getEpisodeGroup(groupId)
    },
    enabled: !!groupId,
    staleTime: STALE,
  })
}

/**
 * Batch-fetch TMDB episode-full data for many episode numbers in a single
 * season. Backed by `useQueries` so React Query handles concurrency,
 * caching, and dedup. Returns a Map keyed by episode number for O(1)
 * lookup at render time.
 */
export function useTmdbEpisodes(
  tvId?: string | number | null,
  seasonNum?: number,
  episodeNumbers: number[] = [],
) {
  const id = tvId ? Number(tvId) : undefined
  const numbers = id != null && seasonNum !== undefined ? episodeNumbers : []
  const queries = useQueries({
    queries: numbers.map(n => ({
      queryKey: ['tmdb', 'episode-full', id, seasonNum, n],
      queryFn: async () => {
        if (!id || seasonNum === undefined) return null
        return getEpisodeFull(id, seasonNum, n)
      },
      enabled: !!id && seasonNum !== undefined,
      staleTime: STALE,
    })),
  })
  const map = new Map<number, NonNullable<Awaited<ReturnType<typeof getEpisodeFull>>>>()
  numbers.forEach((n, i) => {
    const data = queries[i]?.data
    if (data) map.set(n, data)
  })
  return { map, isLoading: queries.some(q => q.isLoading) }
}

export function useTmdbPerson(personId?: string | number | null) {
  const id = personId ? Number(personId) : undefined
  return useQuery({
    queryKey: ['tmdb', 'person-full', id],
    queryFn: async () => {
      if (!id) return null
      return getPersonFull(id)
    },
    enabled: !!id,
    staleTime: STALE,
  })
}

export function useTmdbCollection(collectionId?: string | number | null) {
  const id = collectionId ? Number(collectionId) : undefined
  return useQuery({
    queryKey: ['tmdb', 'collection', id],
    queryFn: async () => {
      if (!id) return null
      return getCollection(id)
    },
    enabled: !!id,
    staleTime: STALE,
  })
}

export function useTmdbTrending(
  mediaType: 'all' | 'movie' | 'tv' | 'person' = 'all',
  window: 'day' | 'week' = 'week',
) {
  return useQuery({
    queryKey: ['tmdb', 'trending', mediaType, window],
    queryFn: () => getTrending(mediaType, window),
    staleTime: 60 * 60 * 1000,
  })
}

export function useTmdbSearch(query: string) {
  return useQuery({
    queryKey: ['tmdb', 'search', query],
    queryFn: () => searchMulti(query),
    enabled: query.length > 2,
    staleTime: 60 * 60 * 1000,
  })
}

export function useTmdbDiscoverMovies(params: Record<string, string>) {
  const key = JSON.stringify(params)
  const hasParams = Object.keys(params).length > 0
  return useQuery({
    queryKey: ['tmdb', 'discover-movie', key],
    queryFn: () => discoverMovies(params),
    enabled: hasParams,
    staleTime: STALE,
  })
}

export function useTmdbDiscoverTv(params: Record<string, string>) {
  const key = JSON.stringify(params)
  const hasParams = Object.keys(params).length > 0
  return useQuery({
    queryKey: ['tmdb', 'discover-tv', key],
    queryFn: () => discoverTv(params),
    enabled: hasParams,
    staleTime: STALE,
  })
}

export function useTmdbUpcoming(region?: string) {
  return useQuery({
    queryKey: ['tmdb', 'upcoming', region],
    queryFn: () => getUpcomingMovies(region),
    staleTime: 12 * 60 * 60 * 1000,
  })
}

export function useTmdbTopRatedMovies() {
  return useQuery({
    queryKey: ['tmdb', 'top-rated', 'movie'],
    queryFn: () => getTopRatedMovies(),
    staleTime: STALE,
  })
}

export function useTmdbTopRatedTv() {
  return useQuery({
    queryKey: ['tmdb', 'top-rated', 'tv'],
    queryFn: () => getTopRatedTv(),
    staleTime: STALE,
  })
}
