import { useEffect, useState } from 'react' import { useQuery } from '@tanstack/react-query' import { getMovieFull, getTvShowFull } from '../api/tmdb' import type { BaseItemDto } from '../api/types' import { getTmdbId } from '../lib/item-types' /** * Returns the YouTube key of the first official Trailer/Teaser for the * given item, lazy-fetched only after the user has hovered the card for * `delayMs`. Avoids slamming TMDB when users sweep the cursor across a * grid. * * The fetch is gated by an `armed` boolean toggled by the consumer * (PosterCard's hover effect) so we don't dispatch network requests for * every card on the screen, only the ones the user lingers on. */ export function useHoverTrailer( item: BaseItemDto | null | undefined, hovered: boolean, enabled: boolean, delayMs = 700, ): { videoKey: string | null; ready: boolean } { const [armed, setArmed] = useState(false) // Arm only after the user has stayed on the card for delayMs. useEffect(() => { if (!hovered || !enabled) { setArmed(false) return } const id = setTimeout(() => setArmed(true), delayMs) return () => clearTimeout(id) }, [hovered, enabled, delayMs]) const tmdbId = getTmdbId(item) const numericId = tmdbId ? Number(tmdbId) : null const isTv = item?.Type === 'Series' const movieQ = useQuery({ queryKey: ['tmdb', 'movie-full', numericId], queryFn: () => (numericId ? getMovieFull(numericId) : null), enabled: !!numericId && !isTv && armed, staleTime: 24 * 60 * 60 * 1000, }) const tvQ = useQuery({ queryKey: ['tmdb', 'tv-full', numericId], queryFn: () => (numericId ? getTvShowFull(numericId) : null), enabled: !!numericId && isTv && armed, staleTime: 24 * 60 * 60 * 1000, }) const videos = (isTv ? tvQ.data?.videos?.results : movieQ.data?.videos?.results) || [] // Prefer official trailers, then teasers; restricted to YouTube since // we render via the YT iframe player. const pickPriority = (t: string) => (t === 'Trailer' ? 0 : t === 'Teaser' ? 1 : 2) const trailer = [...videos] .filter(v => v.site === 'YouTube' && v.key) .sort((a, b) => { if (a.official !== b.official) return a.official ? -1 : 1 return pickPriority(a.type) - pickPriority(b.type) })[0] return { videoKey: trailer?.key || null, ready: armed && (movieQ.isFetched || tvQ.isFetched), } }