import * as React from 'react'
import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react'

import { cn } from '@/lib/utils'
import { Button } from './button'
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from './command'
import { Popover, PopoverContent, PopoverTrigger } from './popover'

export interface ComboboxOption {
  value: string
  label: string
  disabled?: boolean
  keywords?: string[]
}

export interface ComboboxProps {
  options: ComboboxOption[]
  size?: 'default' | 'compact'
  value?: string
  defaultValue?: string
  onValueChange?: (value: string) => void
  placeholder?: React.ReactNode
  searchPlaceholder?: string
  emptyText?: React.ReactNode
  disabled?: boolean
  className?: string
  contentClassName?: string
  align?: 'start' | 'center' | 'end'
  triggerClassName?: string
  id?: string
  name?: string
  'aria-label'?: string
}

function Combobox({
  options,
  value,
  defaultValue,
  onValueChange,
  placeholder = 'Select an option…',
  searchPlaceholder = 'Search…',
  emptyText = 'No option found.',
  size = 'compact',
  disabled,
  className,
  contentClassName,
  triggerClassName,
  align = 'start',
  id,
  name,
  'aria-label': ariaLabel,
}: ComboboxProps) {
  const isControlled = value !== undefined
  const [internal, setInternal] = React.useState<string | undefined>(defaultValue)
  const [open, setOpen] = React.useState(false)
  const current = isControlled ? value : internal
  const selected = options.find((option) => option.value === current)

  const handleSelect = React.useCallback(
    (next: string) => {
      const resolved = next === current ? '' : next
      if (!isControlled) setInternal(resolved)
      onValueChange?.(resolved)
      setOpen(false)
    },
    [current, isControlled, onValueChange],
  )

  return (
    <div className={cn('w-60', className)}>
      <Popover open={open} onOpenChange={setOpen}>
        <PopoverTrigger asChild>
          <Button
            id={id}
            variant="outline"
            role="combobox"
            aria-expanded={open}
            aria-label={ariaLabel}
            disabled={disabled}
            className={cn(
              'w-full justify-between font-normal',
              !selected && 'text-text-tertiary',
              triggerClassName,
            )}
            suffixIcon={<ChevronsUpDownIcon className="size-4 shrink-0 opacity-60" />}
          >
            <span className="truncate text-left">
              {selected ? selected.label : placeholder}
            </span>
          </Button>
        </PopoverTrigger>
        <PopoverContent
          align={align}
          contentPadding="compact"
          className={cn('w-[var(--radix-popover-trigger-width)] min-w-56', contentClassName)}
        >
          <Command
            className={cn(
              'w-full',
              size === 'compact' &&
                '[&_[data-slot=command-input-wrapper]]:h-8 [&_[data-slot=command-input]]:h-8 [&_[data-slot=command-input-wrapper]]:px-2 [&_[data-slot=command-input]]:py-1.5 [&_[cmdk-group]]:p-0 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-1.5 [&_[data-slot=command-empty]]:py-3'
            )}
          >
            <CommandInput placeholder={searchPlaceholder} />
            <CommandList>
              <CommandEmpty>{emptyText}</CommandEmpty>
              <CommandGroup>
                {options.map((option) => (
                  <CommandItem
                    key={option.value}
                    value={option.value}
                    keywords={[option.label, ...(option.keywords ?? [])]}
                    disabled={option.disabled}
                    onSelect={handleSelect}
                  >
                    <CheckIcon
                      className={cn(
                        'mr-2 size-4',
                        option.value === current ? 'opacity-100' : 'opacity-0',
                      )}
                    />
                    <span className="truncate">{option.label}</span>
                  </CommandItem>
                ))}
              </CommandGroup>
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>
      {name ? <input type="hidden" name={name} value={current ?? ''} /> : null}
    </div>
  )
}

export { Combobox }
