"use client"

import { useEffect, useMemo, useState, useId, type ReactNode } from "react"
import { ChevronsUpDown, Check, X } from "lucide-react"
import { Input } from "@/components/ui/input"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { ScrollArea } from "@/components/ui/scroll-area"
import { Separator } from "@/components/ui/separator"
import { cn } from "@/lib/utils"

export type SearchableComboboxOption = {
  value: string
  label: string
  description?: string
  keywords?: string[]
  disabled?: boolean
}

type SearchableComboboxProps = {
  value: string | null
  onValueChange: (value: string | null) => void
  options: SearchableComboboxOption[]
  placeholder?: string
  searchPlaceholder?: string
  emptyText?: string
  className?: string
  triggerClassName?: string
  disabled?: boolean
  allowClear?: boolean
  clearLabel?: string
  renderValue?: (option: SearchableComboboxOption | null) => React.ReactNode
  renderOption?: (option: SearchableComboboxOption, active: boolean) => React.ReactNode
  contentClassName?: string
  scrollClassName?: string
  scrollProps?: React.HTMLAttributes<HTMLDivElement>
  prefix?: ReactNode
  align?: "left" | "center"
}

export function SearchableCombobox({
  value,
  onValueChange,
  options,
  placeholder = "Selecionar...",
  searchPlaceholder = "Buscar...",
  emptyText = "Nenhuma opção encontrada.",
  className,
  triggerClassName,
  disabled,
  allowClear = false,
  clearLabel = "Limpar seleção",
  renderValue,
  renderOption,
  contentClassName,
  scrollClassName,
  scrollProps,
  prefix,
  align = "left",
}: SearchableComboboxProps) {
  const [open, setOpen] = useState(false)
  const [search, setSearch] = useState("")
  const listId = useId()

  const selected = useMemo(() => {
    if (value === null) return null
    return options.find((option) => option.value === value) ?? null
  }, [options, value])

  const filtered = useMemo(() => {
    const term = search.trim().toLowerCase()
    if (!term) {
      return options
    }
    return options.filter((option) => {
      const labelMatch = option.label.toLowerCase().includes(term)
      const descriptionMatch = option.description?.toLowerCase().includes(term) ?? false
      const keywordMatch = option.keywords?.some((keyword) => keyword.toLowerCase().includes(term)) ?? false
      return labelMatch || descriptionMatch || keywordMatch
    })
  }, [options, search])

  useEffect(() => {
    if (!open) {
      setSearch("")
    }
  }, [open])

  const handleSelect = (nextValue: string) => {
    if (nextValue === value) {
      setOpen(false)
      return
    }
    onValueChange(nextValue)
    setOpen(false)
  }

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <button
          type="button"
          role="combobox"
          aria-expanded={open}
          aria-controls={listId}
          disabled={disabled}
          className={cn(
            "flex h-11 w-full items-center justify-between gap-2 rounded-full border border-input bg-background px-3 text-sm font-semibold text-foreground shadow-sm transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-60",
            className,
            triggerClassName,
          )}
        >
          <span className="flex flex-1 items-center gap-2">
            {prefix ? <span className="inline-flex items-center text-neutral-400">{prefix}</span> : null}
            <span className={cn("flex-1 truncate", align === "center" ? "text-center" : "text-left")}>
              {renderValue ? (
                renderValue(selected)
              ) : selected?.label ? (
                selected.label
              ) : (
                <span className="text-muted-foreground">{placeholder}</span>
              )}
            </span>
          </span>
          <ChevronsUpDown className="ml-2 size-4 shrink-0 text-neutral-500 opacity-70" />
        </button>
      </PopoverTrigger>
      <PopoverContent
        id={listId}
        className={cn("z-50 w-[var(--radix-popover-trigger-width)] max-w-[480px] p-0", contentClassName)}
        collisionPadding={16}
      >
        <div className="border-b border-border/80 p-2">
          <Input
            autoFocus
            value={search}
            onChange={(event) => setSearch(event.target.value)}
            placeholder={searchPlaceholder}
            className="h-9"
          />
        </div>
        {allowClear ? (
          <>
            <button
              type="button"
              onClick={() => {
                onValueChange(null)
                setOpen(false)
              }}
              className={cn(
                "flex w-full items-center justify-between gap-2 px-3 py-2 text-sm font-medium text-muted-foreground transition hover:bg-muted",
                selected === null ? "text-foreground" : "",
              )}
            >
              <span>{clearLabel}</span>
              <X className="size-4 opacity-60" />
            </button>
            <Separator />
          </>
        ) : null}
        <ScrollArea
          className={cn("max-h-60 overflow-y-auto", scrollClassName)}
          {...scrollProps}
        >
          {filtered.length === 0 ? (
            <div className="px-3 py-4 text-sm text-muted-foreground">{emptyText}</div>
          ) : (
            <div className="py-1">
              {filtered.map((option) => {
                const isActive = option.value === value
                const content = renderOption ? (
                  renderOption(option, isActive)
                ) : (
                  <div className="flex flex-col">
                    <span className="font-medium text-foreground">{option.label}</span>
                    {option.description ? <span className="text-xs text-muted-foreground">{option.description}</span> : null}
                  </div>
                )
                return (
                  <button
                    type="button"
                    key={option.value}
                    disabled={option.disabled}
                    onClick={() => handleSelect(option.value)}
                    className={cn(
                      "flex w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm transition",
                      option.disabled ? "cursor-not-allowed opacity-50" : "hover:bg-muted",
                      isActive ? "bg-muted" : "",
                    )}
                  >
                    {content}
                    <Check className={cn("size-4 shrink-0 text-primary", isActive ? "opacity-100" : "opacity-0")} />
                  </button>
                )
              })}
            </div>
          )}
        </ScrollArea>
      </PopoverContent>
    </Popover>
  )
}
