import { useMemo, useState, useEffect, useRef } from 'react'
import Fuse from 'fuse.js'
import type { SiteContent } from '../content'

export type SearchResultType = 'episode' | 'question' | 'resource' | 'series'

export interface SearchResult {
  id: string
  type: SearchResultType
  title: string
  subtitle?: string
  description?: string
  href: string
  /** Snippet from script text — only present on script-matched episode results */
  scriptSnippet?: string
}

interface PublicQuestion {
  id: string
  firstName?: string
  question: string
  answer?: string
  topic?: string
}

interface ScriptSearchResult {
  episodeNumber: string
  title: string
  filename: string
  snippet: string
  score: number
}

export function useGlobalSearch(content: SiteContent) {
  const [query, setQuery] = useState('')
  const [questions, setQuestions] = useState<PublicQuestion[]>([])
  const [episodeItems, setEpisodeItems] = useState<SearchResult[]>([])
  const [scriptResults, setScriptResults] = useState<SearchResult[]>([])
  const scriptDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  // Fetch questions once on mount
  useEffect(() => {
    fetch('/api/questions')
      .then(r => r.ok ? r.json() : Promise.reject())
      .then((data: { questions?: PublicQuestion[] }) => {
        setQuestions(Array.isArray(data.questions) ? data.questions : [])
      })
      .catch(() => {})
  }, [])

  // Fetch full episode list once on mount (for title/description matching)
  useEffect(() => {
    fetch('/api/episodes/all')
      .then(r => r.ok ? r.json() : Promise.reject())
      .then((data: { episodes?: Array<{ title: string; link: string; description?: string; episode?: string }> }) => {
        const eps: SearchResult[] = (data.episodes ?? []).map(ep => {
          // Check if there's a matching podcastFeaturedLink highlight page for this episode number
          const highlight = content.podcastFeaturedLinks?.find(
            f => f.episodeNumber && ep.episode && String(f.episodeNumber) === String(ep.episode)
          )
          const hasRichPage = highlight && !!(
            highlight.embedUrl || highlight.showNotes || (highlight.discussionQuestions ?? []).length > 0
          )
          return {
            id: `episode-${ep.episode ?? ep.title}`,
            type: 'episode' as const,
            title: ep.title,
            subtitle: ep.episode ? `Episode ${ep.episode}` : 'Episode',
            description: ep.description,
            href: hasRichPage ? `/episodes/${highlight!.id}` : (ep.link || '/episodes'),
          }
        })
        setEpisodeItems(eps)
      })
      .catch(() => {})
  }, [content.podcastFeaturedLinks])

  // Debounced server-side script search — runs whenever query changes
  useEffect(() => {
    if (scriptDebounceRef.current) clearTimeout(scriptDebounceRef.current)
    if (!query.trim() || query.trim().length < 2) {
      setScriptResults([])
      return
    }
    scriptDebounceRef.current = setTimeout(() => {
      fetch(`/api/episode-scripts/search?q=${encodeURIComponent(query.trim())}`)
        .then(r => r.ok ? r.json() : Promise.reject())
        .then((data: { results?: ScriptSearchResult[] }) => {
          const results = (data.results ?? []).map(r => ({
            id: `script-${r.episodeNumber}`,
            type: 'episode' as const,
            title: r.title,
            subtitle: `Episode ${r.episodeNumber} · Script`,
            description: r.snippet,
            scriptSnippet: r.snippet,
            href: `/episodes`,
          }))
          setScriptResults(results)
        })
        .catch(() => setScriptResults([]))
    }, 200)
  }, [query])

  // Build the Fuse corpus: episodes + resources + series + Q&A
  const staticItems: SearchResult[] = useMemo(() => {
    const results: SearchResult[] = []

    for (const link of content.customLinks ?? []) {
      if (link.placement === 'resources' || link.placement === 'otherSites' || link.placement === 'externalSites') {
        results.push({
          id: `resource-${link.id}`,
          type: 'resource',
          title: link.label,
          subtitle: link.placement === 'resources' ? 'Download' : 'Resource',
          description: link.description,
          href: `/downloads/custom--${link.id}`,
        })
      }
    }

    for (const q of questions) {
      results.push({
        id: `qa-${q.id}`,
        type: 'question',
        title: q.question,
        subtitle: q.topic ?? 'Q&A',
        description: q.answer ? q.answer.slice(0, 120) : undefined,
        href: `/questions`,
      })
    }

    return results
  }, [content, questions])

  const allFuseItems = useMemo(() => [...episodeItems, ...staticItems], [episodeItems, staticItems])

  const fuse = useMemo(() => new Fuse(allFuseItems, {
    keys: [
      { name: 'title', weight: 2 },
      { name: 'subtitle', weight: 0.5 },
      { name: 'description', weight: 1 },
    ],
    threshold: 0.35,
    minMatchCharLength: 2,
    includeScore: true,
  }), [allFuseItems])

  const results = useMemo(() => {
    const q = query.trim()
    if (!q || q.length < 2) return []

    const fuseMatches = fuse.search(q).slice(0, 6).map(r => r.item)

    // Merge script results — deduplicate by episode id (prefer script match if already in fuse)
    const fuseIds = new Set(fuseMatches.map(r => r.id))
    const dedupedScripts = scriptResults.filter(r => !fuseIds.has(r.id))

    // Interleave: fuse results first, then script-only hits, total cap 8
    return [...fuseMatches, ...dedupedScripts].slice(0, 8)
  }, [fuse, query, scriptResults])

  return { query, setQuery, results }
}
