"use client"

import { useEffect, useId, useRef, useState, type ComponentType } from "react"
import { Building2, Check, ChevronDown, type LucideProps } from "lucide-react"
import dynamicIconImports from "lucide-react/dynamicIconImports"
import { Input } from "@/components/ui/input"
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { useLucideIconNames } from "@/hooks/use-lucide-icon-names"
import { cn } from "@/lib/utils"

interface LucideIconSelectProps {
  value: string
  onValueChange: (value: string) => void
  placeholder?: string
  disabled?: boolean
  className?: string
}

const PRELOAD_BATCH_SIZE = 28
const preloadedIconNames = new Set<string>()
const resolvedIconComponentsByName = new Map<string, ComponentType<LucideProps>>()
const loadingIconPromisesByName = new Map<string, Promise<void>>()

function isLucideIconName(iconName: string) {
  return iconName in dynamicIconImports
}

async function ensureIconComponent(iconName: string) {
  if (!iconName || !isLucideIconName(iconName)) return null
  const existingComponent = resolvedIconComponentsByName.get(iconName)
  if (existingComponent) return existingComponent

  let loadingPromise = loadingIconPromisesByName.get(iconName)
  if (!loadingPromise) {
    const loader = dynamicIconImports[iconName as keyof typeof dynamicIconImports]
    loadingPromise = loader()
      .then((module) => {
        resolvedIconComponentsByName.set(iconName, module.default)
      })
      .finally(() => {
        loadingIconPromisesByName.delete(iconName)
      })
    loadingIconPromisesByName.set(iconName, loadingPromise)
  }
  await loadingPromise
  return resolvedIconComponentsByName.get(iconName) ?? null
}

function preloadIconByName(iconName: string) {
  if (!iconName || preloadedIconNames.has(iconName) || !isLucideIconName(iconName)) return
  preloadedIconNames.add(iconName)
  void ensureIconComponent(iconName).catch(() => {
    preloadedIconNames.delete(iconName)
  })
}

export function LucideIconSelect({
  value,
  onValueChange,
  placeholder,
  disabled,
  className,
}: LucideIconSelectProps) {
  const [open, setOpen] = useState(false)
  const [activeIndex, setActiveIndex] = useState(-1)
  const listboxId = useId()
  const optionRefs = useRef<Array<HTMLButtonElement | null>>([])
  const previewRequestRef = useRef(0)
  const [PreviewIcon, setPreviewIcon] = useState<ComponentType<LucideProps> | null>(null)
  const iconNames = useLucideIconNames()
  const trimmedValue = value.trim()
  const normalizedQuery = trimmedValue.toLowerCase()

  const filteredIconNames = (() => {
    if (!normalizedQuery) return iconNames
    return iconNames.filter((iconName) => iconName.includes(normalizedQuery))
  })()

  const hasExactMatch = iconNames.includes(trimmedValue)
  const selectedIndex = filteredIconNames.indexOf(trimmedValue)
  const activePreviewName =
    open && activeIndex >= 0 ? filteredIconNames[activeIndex] ?? trimmedValue : trimmedValue

  useEffect(() => {
    if (!activePreviewName || !isLucideIconName(activePreviewName)) {
      setPreviewIcon(null)
      return
    }

    const cachedComponent = resolvedIconComponentsByName.get(activePreviewName)
    if (cachedComponent) {
      setPreviewIcon(() => cachedComponent)
      return
    }

    const requestId = previewRequestRef.current + 1
    previewRequestRef.current = requestId
    void ensureIconComponent(activePreviewName).then((component) => {
      if (!component) return
      if (previewRequestRef.current !== requestId) return
      setPreviewIcon(() => component)
    })
  }, [activePreviewName])

  const openWithInitialIndex = (fallbackDirection: "first" | "last" = "first") => {
    setOpen(true)
    if (filteredIconNames.length === 0) {
      setActiveIndex(-1)
      return
    }
    if (selectedIndex >= 0) {
      setActiveIndex(selectedIndex)
      return
    }
    setActiveIndex(fallbackDirection === "last" ? filteredIconNames.length - 1 : 0)
  }

  const selectByIndex = (index: number) => {
    const iconName = filteredIconNames[index]
    if (!iconName) return
    onValueChange(iconName)
    setOpen(false)
    setActiveIndex(-1)
  }

  const moveActiveIndex = (direction: "next" | "prev") => {
    if (filteredIconNames.length === 0) return
    if (!open) {
      openWithInitialIndex(direction === "next" ? "first" : "last")
      return
    }
    const lastIndex = filteredIconNames.length - 1
    let nextIndex = activeIndex
    if (nextIndex < 0) nextIndex = selectedIndex >= 0 ? selectedIndex : 0
    nextIndex = direction === "next" ? nextIndex + 1 : nextIndex - 1
    if (nextIndex > lastIndex) nextIndex = 0
    if (nextIndex < 0) nextIndex = lastIndex
    preloadIconByName(filteredIconNames[nextIndex])
    preloadIconByName(filteredIconNames[nextIndex + 1] ?? "")
    preloadIconByName(filteredIconNames[nextIndex - 1] ?? "")
    setActiveIndex(nextIndex)
    optionRefs.current[nextIndex]?.scrollIntoView({ block: "nearest" })
  }

  useEffect(() => {
    if (trimmedValue.length === 0) return
    for (let index = 0; index < Math.min(filteredIconNames.length, PRELOAD_BATCH_SIZE); index += 1) {
      preloadIconByName(filteredIconNames[index])
    }
  }, [trimmedValue, filteredIconNames])

  useEffect(() => {
    if (!open) return
    for (let index = 0; index < Math.min(filteredIconNames.length, PRELOAD_BATCH_SIZE); index += 1) {
      preloadIconByName(filteredIconNames[index])
    }
    if (activeIndex >= 0) preloadIconByName(filteredIconNames[activeIndex] ?? "")
    if (selectedIndex >= 0) preloadIconByName(filteredIconNames[selectedIndex] ?? "")
  }, [open, filteredIconNames, activeIndex, selectedIndex])

  return (
    <div className={cn("space-y-[var(--ds-space-1x)]", className)}>
      <Popover open={open} onOpenChange={setOpen}>
        <PopoverAnchor asChild>
          <div className="flex items-center gap-[var(--ds-space-2x)]">
            <Input
              value={value}
              onChange={(event) => {
                const nextValue = event.target.value
                const nextTrimmedValue = nextValue.trim().toLowerCase()
                const nextFilteredIconNames = nextTrimmedValue
                  ? iconNames.filter((iconName) => iconName.includes(nextTrimmedValue))
                  : iconNames

                onValueChange(nextValue)

                // Close current menu state first, then reopen only if there are matches.
                setOpen(false)
                if (nextValue.trim().length > 0 && nextFilteredIconNames.length > 0) {
                  setOpen(true)
                  setActiveIndex(0)
                } else {
                  setActiveIndex(-1)
                }
              }}
              onKeyDown={(event) => {
                if (event.key === "ArrowDown") {
                  event.preventDefault()
                  moveActiveIndex("next")
                } else if (event.key === "ArrowUp") {
                  event.preventDefault()
                  moveActiveIndex("prev")
                } else if (event.key === "Enter") {
                  if (open && activeIndex >= 0) {
                    event.preventDefault()
                    selectByIndex(activeIndex)
                  }
                } else if (event.key === "Escape") {
                  setOpen(false)
                  setActiveIndex(-1)
                } else if (event.key === "Backspace" || event.key === "Delete") {
                  setOpen(false)
                  setActiveIndex(-1)
                }
              }}
              role="combobox"
              aria-expanded={open}
              aria-controls={listboxId}
              aria-activedescendant={open && activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined}
              placeholder={placeholder}
              disabled={disabled}
              className="h-10 flex-1 rounded-[var(--ds-radius-m)] border-[var(--ds-neutral-300)] bg-white px-[var(--ds-space-2x)] ds-type-global-s text-[var(--ds-text-neutral-default)] placeholder:text-[var(--ds-text-neutral-lighter)]"
            />
            <PopoverTrigger asChild>
              <button
                type="button"
                onClick={() => {
                  if (!open) {
                    if (filteredIconNames.length === 0) {
                      setActiveIndex(-1)
                    } else if (selectedIndex >= 0) {
                      setActiveIndex(selectedIndex)
                    } else {
                      setActiveIndex(0)
                    }
                  } else {
                    setActiveIndex(-1)
                  }
                }}
                disabled={disabled}
                aria-label="Abrir lista de iconos"
                className="flex h-10 w-10 shrink-0 items-center justify-center rounded-[var(--ds-radius-m)] border border-[var(--ds-neutral-300)] bg-white text-[var(--ds-text-neutral-lighter)] transition-colors hover:bg-[var(--ds-neutral-100)] hover:text-[var(--ds-text-neutral-default)] disabled:cursor-not-allowed disabled:opacity-50"
              >
                <ChevronDown
                  className={cn("h-4 w-4 transition-transform", open && "rotate-180")}
                />
              </button>
            </PopoverTrigger>
            <div
              className="flex h-10 w-10 shrink-0 items-center justify-center rounded-[var(--ds-radius-m)] bg-[var(--ds-blueprimary-100)] text-[var(--ds-brand-400)]"
              title="Vista previa del ícono"
            >
              {PreviewIcon ? <PreviewIcon className="h-5 w-5" /> : <Building2 className="h-5 w-5" />}
            </div>
          </div>
        </PopoverAnchor>
        <PopoverContent
          align="start"
          sideOffset={6}
          onOpenAutoFocus={(event) => event.preventDefault()}
          onCloseAutoFocus={(event) => event.preventDefault()}
          className="w-[36rem] max-w-[calc(100vw-2rem)] p-[var(--ds-space-1x)]"
        >
          <div
            id={listboxId}
            role="listbox"
            className="max-h-[18rem] overflow-y-auto rounded-[var(--ds-radius-s)]"
          >
            {filteredIconNames.length > 0 ? (
              filteredIconNames.map((iconName, index) => {
                const isSelected = trimmedValue === iconName
                const isActive = index === activeIndex
                return (
                  <button
                    key={iconName}
                    id={`${listboxId}-option-${index}`}
                    type="button"
                    role="option"
                    aria-selected={isSelected}
                    ref={(element) => {
                      optionRefs.current[index] = element
                    }}
                    onMouseEnter={() => setActiveIndex(index)}
                    onClick={() => selectByIndex(index)}
                    onKeyDown={(event) => {
                      if (event.key === "ArrowDown") {
                        event.preventDefault()
                        moveActiveIndex("next")
                      } else if (event.key === "ArrowUp") {
                        event.preventDefault()
                        moveActiveIndex("prev")
                      } else if (event.key === "Escape") {
                        setOpen(false)
                        setActiveIndex(-1)
                      }
                    }}
                    className={cn(
                      "flex w-full items-center justify-between gap-[var(--ds-space-2x)] rounded-[var(--ds-radius-s)] px-[var(--ds-space-2x)] py-[var(--ds-space-15x)] text-left ds-type-global-xs text-[var(--ds-text-neutral-default)] transition-colors hover:bg-[var(--ds-neutral-100)]",
                      (isSelected || isActive) &&
                        "bg-[var(--ds-blueprimary-100)] text-[var(--ds-blueprimary-800)]",
                    )}
                  >
                    <span>{iconName}</span>
                    {isSelected && <Check className="h-4 w-4" />}
                  </button>
                )
              })
            ) : (
              <div className="px-[var(--ds-space-2x)] py-[var(--ds-space-3x)] ds-type-global-xs text-[var(--ds-text-neutral-lighter)]">
                {iconNames.length === 0
                  ? "No hay iconos disponibles en este momento."
                  : "No hay coincidencias para la búsqueda actual."}
              </div>
            )}
          </div>
        </PopoverContent>
      </Popover>
      <span className="block ds-type-global-xxs text-[var(--ds-text-neutral-lighter)]">
        {iconNames.length > 0
          ? `Hay ${iconNames.length} iconos disponibles. Podés escribir para filtrar o abrir manualmente la lista.`
          : "Escribí para buscar opciones del catálogo de iconos."}
      </span>
      {trimmedValue.length > 0 && iconNames.length > 0 && !hasExactMatch && (
        <span className="block ds-type-global-xxs text-[var(--ds-error-600)]">
          Este nombre no existe en el catálogo local de Lucide.
        </span>
      )}
    </div>
  )
}
