"use client"

import * as React from "react"
import Link from "next/link"
import { useRouter } from "next/navigation"
import { Search, FileText, BookOpen, FileQuestion, Megaphone, Loader2 } from "lucide-react"

import { Input } from "@/shared/components/ui/input"
import { useDebounce } from "@/shared/hooks/use-debounce"
import { cn } from "@/shared/lib/utils"

type ResultType = "question" | "textbook" | "exam" | "announcement"

interface SearchResultItem {
  id: string
  title: string
  snippet: string
  type: ResultType
  href: string
  createdAt: string
}

interface SearchResponse {
  success: boolean
  results: SearchResultItem[]
  total: number
  query: string
}

const TYPE_ICON: Record<ResultType, React.ComponentType<{ className?: string }>> = {
  question: FileQuestion,
  textbook: BookOpen,
  exam: FileText,
  announcement: Megaphone,
}

const TYPE_LABEL: Record<ResultType, string> = {
  question: "Question",
  textbook: "Textbook",
  exam: "Exam",
  announcement: "Announcement",
}

interface GlobalSearchProps {
  className?: string
  placeholder?: string
}

export function GlobalSearch({
  className,
  placeholder = "Search... (Cmd+K)",
}: GlobalSearchProps) {
  const router = useRouter()
  const [query, setQuery] = React.useState("")
  const [open, setOpen] = React.useState(false)
  const [loading, setLoading] = React.useState(false)
  const [results, setResults] = React.useState<SearchResultItem[]>([])
  const [error, setError] = React.useState<string | null>(null)
  const [activeIndex, setActiveIndex] = React.useState(0)

  const debouncedQuery = useDebounce(query, 300)
  const containerRef = React.useRef<HTMLDivElement>(null)
  const inputRef = React.useRef<HTMLInputElement>(null)

  // Cmd/Ctrl + K 快捷键聚焦
  React.useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault()
        inputRef.current?.focus()
        setOpen(true)
      }
      if (e.key === "Escape") {
        setOpen(false)
        inputRef.current?.blur()
      }
    }
    window.addEventListener("keydown", handler)
    return () => window.removeEventListener("keydown", handler)
  }, [])

  // 点击外部关闭
  React.useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
        setOpen(false)
      }
    }
    document.addEventListener("mousedown", handler)
    return () => document.removeEventListener("mousedown", handler)
  }, [])

  // 防抖后发起搜索
  React.useEffect(() => {
    const q = debouncedQuery.trim()
    if (!q) {
      setResults([])
      setError(null)
      setLoading(false)
      return
    }
    let cancelled = false
    setLoading(true)
    setError(null)
    fetch(`/api/search?q=${encodeURIComponent(q)}&type=all&pageSize=20`)
      .then((r) => r.json())
      .then((data: SearchResponse) => {
        if (cancelled) return
        if (!data.success) {
          setError("Search failed")
          setResults([])
        } else {
          setResults(data.results)
          setActiveIndex(0)
        }
      })
      .catch(() => {
        if (cancelled) return
        setError("Network error")
        setResults([])
      })
      .finally(() => {
        if (!cancelled) setLoading(false)
      })
    return () => {
      cancelled = true
    }
  }, [debouncedQuery])

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "ArrowDown") {
      e.preventDefault()
      setActiveIndex((i) => Math.min(i + 1, results.length - 1))
    } else if (e.key === "ArrowUp") {
      e.preventDefault()
      setActiveIndex((i) => Math.max(i - 1, 0))
    } else if (e.key === "Enter") {
      e.preventDefault()
      const item = results[activeIndex]
      if (item) {
        setOpen(false)
        router.push(item.href)
      }
    }
  }

  const showDropdown = open && query.trim().length > 0

  return (
    <div ref={containerRef} className={cn("relative", className)}>
      <Search className="text-muted-foreground absolute top-2.5 left-2.5 size-4" />
      <Input
        ref={inputRef}
        type="search"
        placeholder={placeholder}
        className="w-[200px] pl-9 lg:w-[300px]"
        value={query}
        onChange={(e) => {
          setQuery(e.target.value)
          setOpen(true)
        }}
        onFocus={() => setOpen(true)}
        onKeyDown={handleKeyDown}
        aria-label="Global search"
      />
      {showDropdown ? (
        <div className="absolute top-full right-0 z-50 mt-1 w-[min(480px,calc(100vw-2rem))] rounded-md border bg-popover p-0 shadow-md">
          {loading ? (
            <div className="flex items-center justify-center gap-2 px-4 py-8 text-sm text-muted-foreground">
              <Loader2 className="h-4 w-4 animate-spin" />
              Searching...
            </div>
          ) : error ? (
            <div className="px-4 py-8 text-center text-sm text-destructive">{error}</div>
          ) : results.length === 0 ? (
            <div className="px-4 py-8 text-center text-sm text-muted-foreground">
              No results found for &ldquo;{query}&rdquo;
            </div>
          ) : (
            <ul className="max-h-[60vh] overflow-auto py-1" role="listbox">
              {results.map((item, idx) => {
                const Icon = TYPE_ICON[item.type]
                return (
                  <li key={`${item.type}-${item.id}`} role="option" aria-selected={idx === activeIndex}>
                    <Link
                      href={item.href}
                      onClick={() => {
                        setOpen(false)
                        setQuery("")
                      }}
                      className={cn(
                        "flex items-start gap-3 px-3 py-2 text-sm transition-colors hover:bg-accent",
                        idx === activeIndex && "bg-accent"
                      )}
                      onMouseEnter={() => setActiveIndex(idx)}
                    >
                      <Icon className="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" />
                      <div className="min-w-0 flex-1">
                        <div className="flex items-center justify-between gap-2">
                          <p className="truncate font-medium">{item.title}</p>
                          <span className="shrink-0 text-xs text-muted-foreground">
                            {TYPE_LABEL[item.type]}
                          </span>
                        </div>
                        {item.snippet ? (
                          <p className="mt-0.5 line-clamp-1 text-xs text-muted-foreground">
                            {item.snippet}
                          </p>
                        ) : null}
                      </div>
                    </Link>
                  </li>
                )
              })}
            </ul>
          )}
        </div>
      ) : null}
    </div>
  )
}
