'use client'

import { useState, useEffect, useRef, useMemo, useCallback, Fragment } from 'react'
import { Search } from 'lucide-react'
import { useCommandPalette } from './command-palette-context'
import { useCommandPaletteSearch } from './useCommandPaletteSearch'
import { CommandGroup } from './CommandGroup'
import { CommandResultItem } from './CommandResultItem'
import type { CommandItem } from './useCommandPaletteSearch'

export interface SearchResult {
  id: string
  type: string
  name: string
  detail: string
  path: string
}

export interface QuickAction {
  id: string
  icon: React.ElementType
  name: string
  shortcut?: string
  action: () => void
}

export interface NavigationItem {
  id: string
  icon: React.ElementType
  name: string
  path: string
}

export interface CommandPaletteProps {
  searchFn?: (query: string) => Promise<SearchResult[]>
  quickActions?: QuickAction[]
  navigationItems?: NavigationItem[]
  recentItems?: SearchResult[]
  typeIcons?: Record<string, React.ElementType>
  typeColors?: Record<string, string>
  placeholder?: string
  onNavigate: (path: string) => void
}

/**
 * Convert the heterogeneous props into a unified CommandItem[] for the hook.
 * Async search results are injected separately since they arrive after debounce.
 */
function buildCommands(
  results: SearchResult[],
  quickActions: QuickAction[],
  navigationItems: NavigationItem[],
  recentItems: SearchResult[],
  hasQuery: boolean,
  typeIcons: Record<string, React.ElementType>,
  typeColors: Record<string, string>,
): CommandItem[] {
  const commands: CommandItem[] = []

  // Search results (only when query is active - injected externally)
  for (const r of results) {
    commands.push({
      id: r.id,
      icon: typeIcons[r.type],
      label: r.name,
      detail: r.detail,
      group: '__results__',
      onSelect: r.path,
      colorClass: typeColors[r.type] || 'bg-gray-100 text-gray-600',
    })
  }

  // Quick actions (always shown)
  for (const a of quickActions) {
    commands.push({
      id: a.id,
      icon: a.icon,
      label: a.name,
      shortcut: a.shortcut,
      group: 'Quick Actions',
      onSelect: () => a.action(),
      colorClass: 'bg-gray-100 text-gray-600',
    })
  }

  // Recent items (only when no query)
  if (!hasQuery) {
    for (const r of recentItems.slice(0, 5)) {
      commands.push({
        id: r.id,
        icon: typeIcons[r.type],
        label: r.name,
        detail: r.detail,
        group: 'Recent',
        onSelect: r.path,
        colorClass: 'bg-gray-100 text-gray-600',
      })
    }
  }

  // Navigation items (only included when query is active - filtered by hook)
  if (hasQuery) {
    for (const n of navigationItems) {
      commands.push({
        id: n.id,
        icon: n.icon,
        label: n.name,
        group: 'Go to',
        onSelect: n.path,
        colorClass: 'bg-gray-100 text-gray-600',
      })
    }
  }

  return commands
}

export function CommandPalette({
  searchFn,
  quickActions = [],
  navigationItems = [],
  recentItems = [],
  typeIcons = {},
  typeColors = {},
  placeholder = 'Search or type a command...',
  onNavigate,
}: CommandPaletteProps) {
  const { isOpen, close } = useCommandPalette()
  const inputRef = useRef<HTMLInputElement>(null)
  const [asyncResults, setAsyncResults] = useState<SearchResult[]>([])
  const [isLoading, setIsLoading] = useState(false)
  // Track query locally so we can build commands with the right hasQuery flag
  const [localQuery, setLocalQuery] = useState('')

  const commands = useMemo(
    () =>
      buildCommands(
        asyncResults,
        quickActions,
        navigationItems,
        recentItems,
        !!localQuery,
        typeIcons,
        typeColors,
      ),
    [asyncResults, quickActions, navigationItems, recentItems, localQuery, typeIcons, typeColors]
  )

  const handleExecute = useCallback(
    (command: CommandItem) => {
      if (typeof command.onSelect === 'string') {
        onNavigate(command.onSelect)
      } else {
        command.onSelect()
      }
      close()
    },
    [onNavigate, close]
  )

  const {
    query,
    setQuery,
    filteredGroups,
    selectedIndex,
    onKeyDown,
  } = useCommandPaletteSearch({
    commands,
    onExecute: handleExecute,
    isOpen,
  })

  // Sync local query with hook query
  useEffect(() => {
    setLocalQuery(query)
  }, [query])

  // Focus input when opened
  useEffect(() => {
    if (isOpen) {
      setAsyncResults([])
      setLocalQuery('')
      setTimeout(() => inputRef.current?.focus(), 0)
    }
  }, [isOpen])

  // Search debounce for async results
  useEffect(() => {
    if (!query.trim() || !searchFn) {
      setAsyncResults([])
      return
    }

    const timer = setTimeout(async () => {
      setIsLoading(true)
      try {
        const data = await searchFn(query)
        setAsyncResults(data)
      } catch (error) {
        console.error('Search error:', error)
        setAsyncResults([])
      } finally {
        setIsLoading(false)
      }
    }, 200)

    return () => clearTimeout(timer)
  }, [query, searchFn])

  if (!isOpen) return null

  // Compute flat index offset for each group to match selectedIndex
  let flatIndex = 0

  return (
    <div
      className="fixed inset-0 z-50 flex items-start justify-center pt-20"
      onClick={close}
    >
      {/* Backdrop */}
      <div className="absolute inset-0 bg-black/50 backdrop-blur-sm pointer-events-none" />

      {/* Palette */}
      <div
        role="dialog"
        aria-modal="true"
        aria-label="Command palette"
        className="relative w-full max-w-xl bg-white rounded-xl shadow-2xl border border-gray-200 overflow-hidden"
        onClick={(e) => e.stopPropagation()}
      >
        {/* Search input */}
        <div className="flex items-center gap-3 px-4 py-3 border-b border-gray-200">
          <Search className="w-5 h-5 text-gray-400" />
          <input
            ref={inputRef}
            type="text"
            value={query}
            onChange={(e) => {
              setQuery(e.target.value)
              setLocalQuery(e.target.value)
            }}
            onKeyDown={onKeyDown}
            placeholder={placeholder}
            className="flex-1 outline-none text-lg bg-transparent"
          />
          <kbd className="px-2 py-1 bg-gray-100 text-gray-500 text-xs rounded">ESC</kbd>
        </div>

        {/* Results */}
        <div role="listbox" aria-label="Search results" className="max-h-96 overflow-y-auto">
          {/* Search results group header with query text */}
          {query && asyncResults.length > 0 && (
            <div className="px-3 py-2">
              <p className="text-xs font-medium text-gray-500 uppercase tracking-wider">
                Results for &quot;{query}&quot;
              </p>
            </div>
          )}

          {/* Loading state */}
          {isLoading && (
            <div className="px-4 py-3 text-gray-500 text-sm">
              Searching...
            </div>
          )}

          {/* No results */}
          {query && !isLoading && asyncResults.length === 0 && (
            <div className="px-4 py-3 text-gray-500 text-sm">
              No results found for &quot;{query}&quot;
            </div>
          )}

          {filteredGroups.map((group, gi) => {
            // Skip the __results__ group label -- we render a custom header above
            const isResultsGroup = group.label === '__results__'
            const showBorder = !isResultsGroup && gi > 0

            const groupStartIndex = flatIndex

            const renderedItems = group.items.map((item, i) => {
              const itemIndex = groupStartIndex + i
              const showArrow = typeof item.onSelect === 'string'

              return (
                <CommandResultItem
                  key={item.id}
                  icon={item.icon}
                  label={item.label}
                  detail={item.detail}
                  shortcut={item.shortcut}
                  selected={selectedIndex === itemIndex}
                  colorClass={item.colorClass}
                  showArrow={showArrow}
                  onClick={() => handleExecute(item)}
                />
              )
            })

            flatIndex += group.items.length

            if (isResultsGroup) {
              // Results rendered with custom header above
              return <Fragment key={group.label}>{renderedItems}</Fragment>
            }

            return (
              <CommandGroup key={group.label} label={group.label} showBorder={showBorder}>
                {renderedItems}
              </CommandGroup>
            )
          })}
        </div>

        {/* Footer */}
        <div className="flex items-center justify-between px-4 py-2 bg-gray-50 border-t border-gray-200 text-xs text-gray-500">
          <div className="flex items-center gap-4">
            <span><kbd className="px-1.5 py-0.5 bg-white border rounded">&uarr;&darr;</kbd> Navigate</span>
            <span><kbd className="px-1.5 py-0.5 bg-white border rounded">&crarr;</kbd> Select</span>
            <span><kbd className="px-1.5 py-0.5 bg-white border rounded">ESC</kbd> Close</span>
          </div>
          <span>Press <kbd className="px-1.5 py-0.5 bg-white border rounded">&#8984;K</kbd> anywhere</span>
        </div>
      </div>
    </div>
  )
}
