"use client"

import * as React from "react"
import { Check, ChevronsUpDown, Search, X } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { createPortal } from "react-dom"

interface ComboboxProps {
  value?: string
  onValueChange?: (value: string) => void
  placeholder?: string
  searchPlaceholder?: string
  emptyText?: string
  options: Array<{ value: string; label: string }>
  className?: string
}

export function Combobox({
  value,
  onValueChange,
  placeholder = "Select option...",
  searchPlaceholder = "Search...",
  emptyText = "No option found.",
  options,
  className,
}: ComboboxProps) {
  const [open, setOpen] = React.useState(false)
  const [search, setSearch] = React.useState("")
  const [mounted, setMounted] = React.useState(false)
  const containerRef = React.useRef<HTMLDivElement>(null)
  const triggerRef = React.useRef<HTMLButtonElement>(null)
  const dropdownRef = React.useRef<HTMLDivElement>(null)
  const inputRef = React.useRef<HTMLInputElement>(null)

  // Track if component is mounted for SSR compatibility
  React.useEffect(() => {
    setMounted(true)
    return () => setMounted(false)
  }, [])

  const filteredOptions = options.filter((option) => option.label.toLowerCase().includes(search.toLowerCase()))

  const selectedOption = options.find((option) => option.value === value)

  const resetSearch = () => {
    setSearch("")
    if (inputRef.current) {
      inputRef.current.focus()
    }
  }

  React.useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        containerRef.current &&
        !containerRef.current.contains(event.target as Node) &&
        dropdownRef.current &&
        !dropdownRef.current.contains(event.target as Node)
      ) {
        setOpen(false)
        setSearch("")
      }
    }

    const handleEscape = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setOpen(false)
        setSearch("")
      }
    }

    if (open) {
      document.addEventListener("mousedown", handleClickOutside)
      document.addEventListener("keydown", handleEscape)
    }

    return () => {
      document.removeEventListener("mousedown", handleClickOutside)
      document.removeEventListener("keydown", handleEscape)
    }
  }, [open])

  // Position the dropdown when it opens
  React.useEffect(() => {
    if (open && triggerRef.current && dropdownRef.current && mounted) {
      const updatePosition = () => {
        if (!triggerRef.current || !dropdownRef.current) return

        const triggerRect = triggerRef.current.getBoundingClientRect()
        const dropdownWidth = triggerRect.width

        // Calculate available space
        const viewportHeight = window.innerHeight
        const spaceBelow = viewportHeight - triggerRect.bottom - 10
        const spaceAbove = triggerRect.top - 10

        // Determine if dropdown should appear above or below
        const showAbove = spaceBelow < 200 && spaceAbove > spaceBelow

        // Set dropdown position
        dropdownRef.current.style.position = "fixed"
        dropdownRef.current.style.width = `${dropdownWidth}px`
        dropdownRef.current.style.left = `${triggerRect.left}px`

        if (showAbove) {
          dropdownRef.current.style.bottom = `${viewportHeight - triggerRect.top + 5}px`
          dropdownRef.current.style.top = "auto"
          // Set a fixed height for the dropdown
          dropdownRef.current.style.maxHeight = `${Math.min(spaceAbove, 300)}px`
        } else {
          dropdownRef.current.style.top = `${triggerRect.bottom + 5}px`
          dropdownRef.current.style.bottom = "auto"
          // Set a fixed height for the dropdown
          dropdownRef.current.style.maxHeight = `${Math.min(spaceBelow, 300)}px`
        }
      }

      updatePosition()
      window.addEventListener("resize", updatePosition)
      window.addEventListener("scroll", updatePosition, true)

      return () => {
        window.removeEventListener("resize", updatePosition)
        window.removeEventListener("scroll", updatePosition, true)
      }
    }
  }, [open, mounted])

  // Generate a longer list of options for testing scrolling
  const testOptions = React.useMemo(() => {
    if (options.length < 10) {
      return [
        ...options,
        { value: "angular", label: "Angular" },
        { value: "svelte", label: "Svelte" },
        { value: "vue", label: "Vue" },
        { value: "ember", label: "Ember" },
        { value: "backbone", label: "Backbone" },
        { value: "jquery", label: "jQuery" },
        { value: "polymer", label: "Polymer" },
        { value: "meteor", label: "Meteor" },
        { value: "aurelia", label: "Aurelia" },
        { value: "mithril", label: "Mithril" },
        { value: "preact", label: "Preact" },
        { value: "alpine", label: "Alpine.js" },
        { value: "lit", label: "Lit" },
        { value: "solid", label: "Solid" },
        { value: "qwik", label: "Qwik" },
        { value: "marko", label: "Marko" },
        { value: "stimulus", label: "Stimulus" },
        { value: "riot", label: "Riot.js" },
        { value: "hyperapp", label: "Hyperapp" },
        { value: "inferno", label: "Inferno" },
      ]
    }
    return options
  }, [options])

  return (
    <div ref={containerRef} className={cn("relative", className)}>
      <Button
        ref={triggerRef}
        variant="outline"
        role="combobox"
        aria-expanded={open}
        className="w-full justify-between"
        onClick={() => setOpen(!open)}
      >
        {selectedOption ? selectedOption.label : placeholder}
        <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
      </Button>

      {mounted &&
        open &&
        createPortal(
          <div
            ref={dropdownRef}
            className="z-[9999] flex flex-col overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95"
          >
            <div className="sticky top-0 z-10 border-b border-border bg-popover">
              <div className="flex items-center px-3 h-10">
                {search ? (
                  <X
                    className="h-4 w-4 shrink-0 text-muted-foreground cursor-pointer"
                    onClick={resetSearch}
                    aria-label="Clear search"
                  />
                ) : (
                  <Search className="h-4 w-4 shrink-0 text-muted-foreground" />
                )}
                <input
                  ref={inputRef}
                  placeholder={searchPlaceholder}
                  value={search}
                  onChange={(e) => setSearch(e.target.value)}
                  className="flex h-full w-full bg-transparent py-2 px-2 text-sm outline-none placeholder:text-muted-foreground"
                  autoFocus
                />
              </div>
            </div>
            <div className="overflow-y-auto overflow-x-hidden p-1" style={{ maxHeight: "250px" }}>
              {filteredOptions.length === 0 ? (
                <div className="py-6 text-center text-sm text-muted-foreground">{emptyText}</div>
              ) : (
                filteredOptions.map((option) => (
                  <div
                    key={option.value}
                    className={cn(
                      "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors",
                      "hover:bg-[var(--background-secondary)] focus:bg-[var(--background-secondary)]",
                    )}
                    onClick={() => {
                      onValueChange?.(option.value)
                      setOpen(false)
                      setSearch("")
                    }}
                  >
                    <Check className={cn("mr-2 h-4 w-4", value === option.value ? "opacity-100" : "opacity-0")} />
                    {option.label}
                  </div>
                ))
              )}
            </div>
          </div>,
          document.body,
        )}
    </div>
  )
}
