import * as React from "react"
import { SearchIcon, XIcon } from "lucide-react"
import { cn } from "../core/cn"

interface CommandItem {
  value: string
  label: string
  description?: string
  icon?: React.ReactNode
  disabled?: boolean
  group?: string
}

interface CommandProps {
  items: CommandItem[]
  value?: string
  onValueChange?: (value: string) => void
  placeholder?: string
  emptyMessage?: string
  className?: string
  inputClassName?: string
  listClassName?: string
}

function Command({ className, ...props }: React.ComponentPropsWithoutRef<"div">) {
  return (
    <div
      data-slot="command"
      className={cn("flex h-full w-full flex-col overflow-hidden rounded-xl bg-popover text-popover-foreground", className)}
      {...props}
    />
  )
}

function CommandInput({ className, ...props }: React.ComponentPropsWithoutRef<"input">) {
  return (
    <div data-slot="command-input-wrapper" className="flex items-center border-b px-3">
      <SearchIcon className="mr-2 size-4 shrink-0 text-muted-foreground" />
      <input
        data-slot="command-input"
        className={cn(
          "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none",
          "placeholder:text-muted-foreground",
          "disabled:cursor-not-allowed disabled:opacity-50",
          className
        )}
        {...props}
      />
    </div>
  )
}

function CommandList({ className, ...props }: React.ComponentPropsWithoutRef<"div">) {
  return (
    <div
      data-slot="command-list"
      className={cn("max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto", className)}
      {...props}
    />
  )
}

function CommandEmpty({ className, ...props }: React.ComponentPropsWithoutRef<"div">) {
  return (
    <div
      data-slot="command-empty"
      className={cn("py-6 text-center text-sm text-muted-foreground", className)}
      {...props}
    />
  )
}

function CommandGroup({ className, heading, ...props }: React.ComponentPropsWithoutRef<"div"> & { heading?: string }) {
  return (
    <div data-slot="command-group" className={cn("overflow-hidden p-1 text-foreground", className)}>
      {heading && (
        <div className="px-2 py-1.5 text-xs font-medium text-muted-foreground">{heading}</div>
      )}
      <div {...props} />
    </div>
  )
}

function CommandSeparator({ className, ...props }: React.ComponentPropsWithoutRef<"div">) {
  return (
    <div
      data-slot="command-separator"
      className={cn("-mx-1 h-px bg-border", className)}
      {...props}
    />
  )
}

interface CommandItemProps extends React.ComponentPropsWithoutRef<"div"> {
  selected?: boolean
  disabled?: boolean
  onSelect?: () => void
}

function CommandItem({ className, selected, disabled, onSelect, ...props }: CommandItemProps) {
  return (
    <div
      data-slot="command-item"
      data-selected={selected}
      aria-disabled={disabled}
      role="option"
      aria-selected={selected}
      onClick={!disabled ? onSelect : undefined}
      className={cn(
        "relative flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none",
        "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground",
        "hover:bg-accent hover:text-accent-foreground",
        disabled && "pointer-events-none opacity-50",
        className
      )}
      {...props}
    />
  )
}

function CommandShortcut({ className, ...props }: React.ComponentPropsWithoutRef<"span">) {
  return (
    <span
      data-slot="command-shortcut"
      className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)}
      {...props}
    />
  )
}

function CommandSearch({
  items,
  value,
  onValueChange,
  placeholder = "Search...",
  emptyMessage = "No results found.",
  className,
}: CommandProps) {
  const [query, setQuery] = React.useState("")
  const [selectedValue, setSelectedValue] = React.useState(value ?? "")

  const filtered = React.useMemo(() => {
    if (!query) return items
    const q = query.toLowerCase()
    return items.filter(
      (item) =>
        item.label.toLowerCase().includes(q) ||
        item.description?.toLowerCase().includes(q) ||
        item.value.toLowerCase().includes(q)
    )
  }, [items, query])

  const groups = React.useMemo(() => {
    const map = new Map<string, CommandItem[]>()
    for (const item of filtered) {
      const key = item.group ?? ""
      if (!map.has(key)) map.set(key, [])
      map.get(key)!.push(item)
    }
    return map
  }, [filtered])

  const handleSelect = (val: string) => {
    setSelectedValue(val)
    onValueChange?.(val)
  }

  return (
    <Command className={className}>
      <CommandInput
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder={placeholder}
      />
      <CommandList>
        {filtered.length === 0 ? (
          <CommandEmpty>{emptyMessage}</CommandEmpty>
        ) : (
          Array.from(groups.entries()).map(([group, groupItems]) => (
            <CommandGroup key={group} heading={group || undefined}>
              {groupItems.map((item) => (
                <CommandItem
                  key={item.value}
                  selected={selectedValue === item.value}
                  disabled={item.disabled}
                  onSelect={() => handleSelect(item.value)}
                >
                  {item.icon && <span className="shrink-0">{item.icon}</span>}
                  <span>{item.label}</span>
                  {item.description && (
                    <span className="ml-auto text-xs text-muted-foreground">{item.description}</span>
                  )}
                </CommandItem>
              ))}
            </CommandGroup>
          ))
        )}
      </CommandList>
    </Command>
  )
}

export { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSearch, CommandSeparator, CommandShortcut }
export type { CommandItem, CommandProps }
