// components/searchable-multi-select.tsx
import { useState, useEffect, useRef, useCallback } from 'react'
import { Check, ChevronsUpDown, Loader2, X } from 'lucide-react'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/command'
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from '@/components/ui/popover'
import { Badge } from '@/components/ui/badge'
import { ScrollArea } from '@/components/ui/scroll-area'

export interface FieldMapping {
  value: string  // The field name for the value (e.g., 'id', 'user_id')
  label: string  // The field name for the label (e.g., 'name', 'username', 'full_name')
}

export interface SearchableMultiSelectProps {
  value: string[]
  onChange: (value: string[]) => void
  fetchData: (search: string, page: number) => Promise<{
    data: any[]
    hasMore: boolean
  }>
  fieldMapping: FieldMapping
  placeholder?: string
  disabled?: boolean
  className?: string
  emptyText?: string
}

export function SearchableMultiSelect({
  value = [],
  onChange,
  fetchData,
  fieldMapping,
  placeholder = 'Select items...',
  disabled = false,
  className,
  emptyText = 'No items found.',
}: SearchableMultiSelectProps) {
  const [open, setOpen] = useState(false)
  const [search, setSearch] = useState('')
  const [options, setOptions] = useState<any[]>([])
  const [selectedItems, setSelectedItems] = useState<any[]>([])
  const [loading, setLoading] = useState(false)
  const [page, setPage] = useState(1)
  const [hasMore, setHasMore] = useState(true)
  const observerTarget = useRef<HTMLDivElement>(null)

  // Fetch data
  const loadData = useCallback(
    async (searchTerm: string, pageNum: number, reset: boolean = false) => {
      setLoading(true)
      try {
        const result = await fetchData(searchTerm, pageNum)
        setOptions((prev) => (reset ? result.data : [...prev, ...result.data]))
        setHasMore(result.hasMore)
      } catch (error) {
        console.error('Error fetching data:', error)
      } finally {
        setLoading(false)
      }
    },
    [fetchData]
  )

  // Initial load and search
  useEffect(() => {
    const timeoutId = setTimeout(() => {
      setPage(1)
      loadData(search, 1, true)
    }, 300)
    return () => clearTimeout(timeoutId)
  }, [search, loadData])

  // Intersection observer for pagination
  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting && hasMore && !loading) {
          const nextPage = page + 1
          setPage(nextPage)
          loadData(search, nextPage, false)
        }
      },
      { threshold: 1.0 }
    )

    const currentTarget = observerTarget.current
    if (currentTarget) {
      observer.observe(currentTarget)
    }

    return () => {
      if (currentTarget) {
        observer.unobserve(currentTarget)
      }
    }
  }, [hasMore, loading, page, search, loadData])

  // Load selected items details
  useEffect(() => {
    const loadSelectedDetails = async () => {
      if (value.length > 0 && options.length > 0) {
        const selected = options.filter((opt) =>
          value.includes(opt[fieldMapping.value])
        )
        setSelectedItems(selected)
      } else if (value.length === 0) {
        setSelectedItems([])
      }
    }
    loadSelectedDetails()
  }, [value, options, fieldMapping.value])

  const handleSelect = (item: any) => {
    const itemValue = item[fieldMapping.value]
    const newValue = value.includes(itemValue)
      ? value.filter((v) => v !== itemValue)
      : [...value, itemValue]
    
    onChange(newValue)
  }

  const handleRemove = (itemValue: string, e?: React.MouseEvent) => {
    e?.stopPropagation()
    onChange(value.filter((v) => v !== itemValue))
  }

  const getInitials = (name: string) => {
    if (!name) return 'U'
    return name
      .split(' ')
      .map((n) => n[0])
      .join('')
      .toUpperCase()
      .slice(0, 2)
  }

  const getSelectedItem = (itemValue: string) => {
    return selectedItems.find((item) => item[fieldMapping.value] === itemValue)
  }

  const handleClearSearch = () => {
    setSearch('')
  }

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button
          variant="outline"
          role="combobox"
          aria-expanded={open}
          disabled={disabled}
          className={cn(
            'w-full justify-between h-auto min-h-10 px-3 py-2',
            className
          )}
        >
          <div className="flex flex-wrap gap-1.5 flex-1 max-h-32 overflow-y-auto py-1 scrollbar-hide">
            {value.length === 0 ? (
              <span className="text-muted-foreground">{placeholder}</span>
            ) : (
              value.map((itemValue) => {
                const item = getSelectedItem(itemValue)
                const displayName = item
                  ? item[fieldMapping.label]
                  : itemValue
                return (
                  <Badge
                    key={itemValue}
                    variant="secondary"
                    className="pl-2 pr-1 py-1 gap-1.5 rounded-full hover:bg-secondary/80 border-primary/10"
                  >
                    <div className="flex items-center gap-1.5">
                      <div className="h-5 w-5 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-[10px] font-bold">
                        {getInitials(displayName)}
                      </div>
                      <span className="text-xs max-w-[120px] truncate font-medium">
                        {displayName}
                      </span>
                      <button
                        type="button"
                        onClick={(e) => handleRemove(itemValue, e)}
                        className="ml-0.5 rounded-full hover:bg-destructive/10 hover:text-destructive p-0.5 transition-colors"
                      >
                        <X className="h-3 w-3" />
                      </button>
                    </div>
                  </Badge>
                )
              })
            )}
          </div>
          <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-full p-0" align="start">
        <Command shouldFilter={false}>
          <div className="relative">
            <CommandInput
              placeholder="Search..."
              value={search}
              onValueChange={setSearch}
              className="pr-8"
            />
            {search && (
              <Button
                type="button"
                variant="ghost"
                size="sm"
                className="absolute right-1 top-1/2 transform -translate-y-1/2 h-6 w-6 p-0 hover:bg-muted"
                onClick={handleClearSearch}
              >
                <X className="h-3 w-3" />
              </Button>
            )}
          </div>
          <CommandList>
            <CommandEmpty>{emptyText}</CommandEmpty>
            <CommandGroup>
              <ScrollArea className="h-72">
                {Array.isArray(options)
                  ? options.map((item) => {
                      const itemValue = item[fieldMapping.value]
                      const itemLabel = item[fieldMapping.label]
                      const isSelected = value.includes(itemValue)
                      
                      return (
                        <CommandItem
                          key={itemValue}
                          onSelect={() => handleSelect(item)}
                          className="cursor-pointer"
                        >
                          <div className="flex items-center gap-2 flex-1">
                            <div className="h-7 w-7 rounded-full bg-muted flex items-center justify-center text-xs font-medium">
                              {getInitials(itemLabel)}
                            </div>
                            <span className="flex-1">{itemLabel}</span>
                            <Check
                              className={cn(
                                'h-4 w-4',
                                isSelected ? 'opacity-100' : 'opacity-0'
                              )}
                            />
                          </div>
                        </CommandItem>
                      )
                    })
                  : null}
                {loading && (
                  <div className="flex items-center justify-center py-4">
                    <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
                  </div>
                )}
                <div ref={observerTarget} className="h-2" />
              </ScrollArea>
            </CommandGroup>
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
  )
}
