import { useEffect, useMemo, useState } from 'react'
import Fuse from 'fuse.js'
import { useFullLibraryCatalog, useEpisodeAndTrackSearch } from './use-jellyfin'
import type { BaseItemDto } from '../api/types'

/**
 * Real fuzzy search across the user's library. Pre-fetches the full
 * Movies + Series + MusicAlbum + MusicArtist catalog once (cached 12h)
 * and runs Fuse.js client-side so typos, partial words, and out-of-
 * order tokens all resolve. Episodes and tracks fall back to Jellyfin's
 * server-side searchTerm because pre-fetching every episode of every
 * series would be enormous.
 *
 * The Fuse threshold is intentionally generous (0.4) so single-letter
 * typos still surface the right title; we cap at 80 results so the UI
 * stays manageable even for libraries with 5000+ items.
 */
export function useFuzzyLibrarySearch(query: string) {
  const catalog = useFullLibraryCatalog()
  const epAndTrack = useEpisodeAndTrackSearch(query)

  // Local debounce so Fuse doesn't re-run on every keystroke. The
  // catalog is stable so this is the only thing changing the result.
  const [debounced, setDebounced] = useState(query)
  useEffect(() => {
    const t = setTimeout(() => setDebounced(query), 120)
    return () => clearTimeout(t)
  }, [query])

  const fuse = useMemo(() => {
    const items = catalog.data || []
    if (items.length === 0) return null
    return new Fuse(items as BaseItemDto[], {
      keys: [
        { name: 'Name', weight: 0.7 },
        { name: 'OriginalTitle', weight: 0.25 },
        { name: 'Overview', weight: 0.05 },
      ],
      threshold: 0.4,
      ignoreLocation: true,
      shouldSort: true,
      includeScore: true,
      minMatchCharLength: 2,
    })
  }, [catalog.data])

  const results = useMemo<BaseItemDto[]>(() => {
    const trimmed = debounced.trim()
    if (!trimmed || !fuse) return []
    return fuse.search(trimmed, { limit: 80 }).map(r => r.item)
  }, [fuse, debounced])

  return {
    catalogResults: results,
    episodesAndTracks: (epAndTrack.data || []) as BaseItemDto[],
    isLoading: catalog.isLoading || epAndTrack.isLoading,
    isFetching: catalog.isFetching || epAndTrack.isFetching,
    catalogReady: !!fuse,
  }
}
