'use client'

import { useState, useEffect, useCallback, useMemo, useRef } from 'react'
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog'
import * as VisuallyHidden from '@radix-ui/react-visually-hidden'
import { MagnifyingGlass, File, Code, ArrowRight, BookOpen, Lightning } from '@phosphor-icons/react'
import { cn } from '@/lib/utils'

interface SearchItem {
  id: string
  title: string
  description?: string
  type: 'endpoint' | 'doc' | 'folder'
  method?: string
  path?: string
  href: string
}

interface SearchDialogProps {
  open: boolean
  onOpenChange: (open: boolean) => void
  items: SearchItem[]
  onSelect: (item: SearchItem) => void
}

const METHOD_COLORS: Record<string, string> = {
  GET: 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400',
  POST: 'bg-blue-500/10 text-blue-600 dark:text-blue-400',
  PUT: 'bg-amber-500/10 text-amber-600 dark:text-amber-400',
  PATCH: 'bg-orange-500/10 text-orange-600 dark:text-orange-400',
  DELETE: 'bg-red-500/10 text-red-600 dark:text-red-400',
}

interface GroupedResults {
  docs: SearchItem[]
  endpoints: SearchItem[]
}

export function SearchDialog({ open, onOpenChange, items, onSelect }: SearchDialogProps) {
  const [query, setQuery] = useState('')
  const [selectedIndex, setSelectedIndex] = useState(0)
  const inputRef = useRef<HTMLInputElement>(null)
  const listRef = useRef<HTMLDivElement>(null)

  // Filter and group items based on query with fuzzy/BM25-like scoring
  const { groupedResults } = useMemo(() => {
    let filtered: SearchItem[]
    
    if (!query.trim()) {
      // Show a mix of docs and endpoints when no query
      const docs = items.filter(i => i.type === 'doc').slice(0, 15)
      const endpoints = items.filter(i => i.type === 'endpoint').slice(0, 15)
      filtered = [...docs, ...endpoints]
    } else {
      // Tokenize query
      const queryTokens = query.toLowerCase().split(/\s+/).filter(t => t.length > 1)
      const queryLower = query.toLowerCase()
      
      // Score each item
      const scored = items.map(item => {
        let score = 0
        const titleLower = item.title.toLowerCase()
        const descLower = (item.description || '').toLowerCase()
        const pathLower = (item.path || '').toLowerCase()
        const hrefLower = item.href.toLowerCase()
        
        // Exact phrase match (highest priority)
        if (titleLower.includes(queryLower)) score += 100
        if (pathLower.includes(queryLower)) score += 80
        if (descLower.includes(queryLower)) score += 60
        if (hrefLower.includes(queryLower)) score += 40
        
        // Token matching
        for (const token of queryTokens) {
          // Title matches
          if (titleLower === token) score += 50
          else if (titleLower.startsWith(token)) score += 30
          else if (titleLower.includes(token)) score += 20
          
          // Path matches (for endpoints and docs)
          if (pathLower.includes(token)) score += 25
          const pathParts = pathLower.split(/[\/\s-]/)
          if (pathParts.some(part => part === token)) score += 35
          if (pathParts.some(part => part.startsWith(token))) score += 20
          
          // Description matches
          if (descLower.includes(token)) score += 15
          
          // Href/slug matches
          const hrefParts = hrefLower.split(/[\/\s-#]/)
          if (hrefParts.some(part => part === token)) score += 30
          if (hrefParts.some(part => part.startsWith(token))) score += 15
          
          // Method matching for endpoints
          if (item.method && item.method.toLowerCase() === token) score += 25
          
          // Fuzzy matching
          const allWords = [titleLower, ...pathParts, ...hrefParts].filter(Boolean)
          for (const word of allWords) {
            if (word.length > 2 && token.length > 2) {
              const minLen = Math.min(word.length, token.length)
              let matches = 0
              for (let i = 0; i < minLen; i++) {
                if (word[i] === token[i]) matches++
              }
              if (matches / minLen > 0.7) score += 5
            }
          }
        }
        
        return { item, score }
      })
      
      // Filter and sort by score
      filtered = scored
        .filter(s => s.score > 0)
        .sort((a, b) => b.score - a.score)
        .slice(0, 30)
        .map(s => s.item)
    }
    
    // Group by type
    const grouped: GroupedResults = {
      docs: filtered.filter(i => i.type === 'doc'),
      endpoints: filtered.filter(i => i.type === 'endpoint'),
    }
    
    return { groupedResults: grouped }
  }, [query, items])

  // Flat list for keyboard navigation
  const flatItems = useMemo(() => {
    return [...groupedResults.docs, ...groupedResults.endpoints]
  }, [groupedResults])

  // Reset selection when results change
  useEffect(() => {
    setSelectedIndex(0)
  }, [flatItems])

  // Reset and focus when dialog opens
  useEffect(() => {
    if (open) {
      setQuery('')
      setSelectedIndex(0)
      setTimeout(() => inputRef.current?.focus(), 50)
    }
  }, [open])

  // Scroll selected item into view
  useEffect(() => {
    if (listRef.current && flatItems.length > 0) {
      const selectedEl = listRef.current.querySelector(`[data-index="${selectedIndex}"]`)
      selectedEl?.scrollIntoView({ block: 'nearest' })
    }
  }, [selectedIndex, flatItems.length])

  // Handle selection
  const handleSelect = useCallback((item: SearchItem) => {
    onSelect(item)
    onOpenChange(false)
  }, [onSelect, onOpenChange])

  // Keyboard navigation
  const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault()
        setSelectedIndex(i => Math.min(i + 1, flatItems.length - 1))
        break
      case 'ArrowUp':
        e.preventDefault()
        setSelectedIndex(i => Math.max(i - 1, 0))
        break
      case 'Enter':
        e.preventDefault()
        if (flatItems[selectedIndex]) {
          handleSelect(flatItems[selectedIndex])
        }
        break
    }
  }, [flatItems, selectedIndex, handleSelect])

  // Get the global index for an item
  const getGlobalIndex = (item: SearchItem) => {
    return flatItems.findIndex(i => i.id === item.id)
  }

  const renderItem = (item: SearchItem) => {
    const index = getGlobalIndex(item)
    return (
      <button
        key={item.id}
        data-index={index}
        onClick={() => handleSelect(item)}
        onMouseEnter={() => setSelectedIndex(index)}
        className={cn(
          'w-full flex items-center gap-3 px-3 py-2 rounded-md text-left transition-colors duration-75',
          index === selectedIndex
            ? 'bg-primary/10 text-foreground'
            : 'hover:bg-muted/50'
        )}
      >
        {/* Icon */}
        <div className="shrink-0">
          {item.type === 'endpoint' ? (
            <Code className="h-4 w-4 text-muted-foreground" weight="bold" />
          ) : (
            <File className="h-4 w-4 text-muted-foreground" weight="bold" />
          )}
        </div>

        {/* Content */}
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2">
            {item.method && (
              <span className={cn(
                'px-1.5 py-0.5 rounded text-[10px] font-bold uppercase shrink-0',
                METHOD_COLORS[item.method] || 'bg-gray-500/10 text-gray-600'
              )}>
                {item.method}
              </span>
            )}
            <span className="font-medium truncate text-sm">{item.title}</span>
          </div>
          {(item.path || item.description) && (
            <p className="text-xs text-muted-foreground truncate mt-0.5">
              {item.type === 'endpoint' ? item.path : item.description || item.path}
            </p>
          )}
        </div>

        {/* Arrow */}
        {index === selectedIndex && (
          <ArrowRight className="h-4 w-4 text-muted-foreground shrink-0" />
        )}
      </button>
    )
  }

  const hasResults = flatItems.length > 0

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent 
        className="max-w-2xl p-0 gap-0 overflow-hidden !duration-150"
        onOpenAutoFocus={(e) => e.preventDefault()}
      >
        <VisuallyHidden.Root>
          <DialogTitle>Search documentation</DialogTitle>
        </VisuallyHidden.Root>
        
        {/* Search input */}
        <div className="flex items-center border-b px-4 gap-3">
          <MagnifyingGlass className="h-5 w-5 text-muted-foreground shrink-0" />
          <input
            ref={inputRef}
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            onKeyDown={handleKeyDown}
            placeholder="Search documentation and endpoints..."
            className="flex-1 h-14 text-base bg-transparent outline-none placeholder:text-muted-foreground"
          />
          <kbd className="hidden sm:inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground">
            ESC
          </kbd>
        </div>

        {/* Results */}
        <div ref={listRef} className="max-h-[400px] overflow-y-auto">
          {!hasResults && query ? (
            <div className="py-12 text-center text-muted-foreground">
              <MagnifyingGlass className="h-10 w-10 mx-auto mb-3 opacity-50" />
              <p className="text-sm">No results found for &quot;{query}&quot;</p>
            </div>
          ) : !hasResults ? (
            <div className="py-12 text-center text-muted-foreground">
              <p className="text-sm">Start typing to search...</p>
            </div>
          ) : (
            <div className="py-2">
              {/* Documentation Section */}
              {groupedResults.docs.length > 0 && (
                <div className="mb-2">
                  <div className="flex items-center gap-2 px-4 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wide">
                    <BookOpen className="h-3.5 w-3.5" weight="bold" />
                    Documentation
                    <span className="text-[10px] font-normal ml-auto">{groupedResults.docs.length}</span>
                  </div>
                  <div className="px-2 space-y-0.5">
                    {groupedResults.docs.map(renderItem)}
                  </div>
                </div>
              )}

              {/* API Endpoints Section */}
              {groupedResults.endpoints.length > 0 && (
                <div>
                  <div className="flex items-center gap-2 px-4 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wide">
                    <Lightning className="h-3.5 w-3.5" weight="bold" />
                    API Endpoints
                    <span className="text-[10px] font-normal ml-auto">{groupedResults.endpoints.length}</span>
                  </div>
                  <div className="px-2 space-y-0.5">
                    {groupedResults.endpoints.map(renderItem)}
                  </div>
                </div>
              )}
            </div>
          )}
        </div>

        {/* Footer */}
        <div className="border-t px-4 py-2 flex items-center gap-4 text-xs text-muted-foreground bg-muted/30">
          <span className="flex items-center gap-1">
            <kbd className="px-1.5 py-0.5 rounded border bg-background text-[10px]">↑↓</kbd>
            navigate
          </span>
          <span className="flex items-center gap-1">
            <kbd className="px-1.5 py-0.5 rounded border bg-background text-[10px]">↵</kbd>
            select
          </span>
          <span className="flex items-center gap-1">
            <kbd className="px-1.5 py-0.5 rounded border bg-background text-[10px]">esc</kbd>
            close
          </span>
        </div>
      </DialogContent>
    </Dialog>
  )
}
