import { useState, useRef, useCallback, useMemo, useEffect } from 'react'
import { Field } from '../../../../types'
import { Check, ChevronsUpDown } from 'lucide-react'
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 { cn } from '@/lib/utils'
import React from 'react'

export type SelectOption = {
  label: string;
  value: string;
};

interface SelectCellProps<T extends string> {
  field: Field<T>
  value: any
  onChange: (value: any) => void
  onStartEdit?: () => void
  onEndEdit?: () => void
  hasErrors?: boolean
  options: readonly any[]
  disabled?: boolean
  className?: string
}

// Lightweight version of the select cell with minimal dependencies
const SelectCell = <T extends string>({
  field,
  value,
  onChange,
  onStartEdit,
  onEndEdit,
  hasErrors,
  options = [],
  disabled = false,
  className = ''
}: SelectCellProps<T>) => {
  // State for the open/closed state of the dropdown
  const [open, setOpen] = useState(false);
  
  // Ref for the command list
  const commandListRef = useRef<HTMLDivElement>(null);
  
  // Controlled state for the internal value - this is key to prevent reopening
  const [internalValue, setInternalValue] = useState(value);
  
  // State to track if the value is being processed/validated
  const [isProcessing, setIsProcessing] = useState(false);
  
  // Add state for hover
  const [isHovered, setIsHovered] = useState(false);
  
  // Helper function to check if a class is present in the className string
  const hasClass = (cls: string): boolean => {
    const classNames = className.split(' ');
    return classNames.includes(cls);
  };
  
  // Update internal value when prop value changes
  useEffect(() => {
    setInternalValue(value);
    // When the value prop changes, it means validation is complete
    setIsProcessing(false);
  }, [value]);
  
  // Memoize options processing to avoid recalculation on every render
  const selectOptions = useMemo(() => {
    // Fast path check - if we have raw options, just use those
    if (options && options.length > 0) {
      // Check if options already have the correct structure to avoid mapping
      if (typeof options[0] === 'object' && 'label' in options[0] && 'value' in options[0]) {
        return options as SelectOption[];
      }
      
      // Optimize mapping to only convert what's needed
      return options.map((option: any) => ({
        label: option.label || String(option.value || option),
        value: String(option.value || option)
      }));
    }
    
    // Fall back to field options if no direct options provided
    const fieldType = field.fieldType;
    if (fieldType && 
        (fieldType.type === 'select' || fieldType.type === 'multi-select') && 
        (fieldType as any).options) {
      const fieldOptions = (fieldType as any).options;
      
      // Check if fieldOptions already have the correct structure
      if (fieldOptions.length > 0 && typeof fieldOptions[0] === 'object' && 
          'label' in fieldOptions[0] && 'value' in fieldOptions[0]) {
        return fieldOptions as SelectOption[];
      }
      
      return fieldOptions.map((option: any) => ({
        label: option.label || String(option.value || option),
        value: String(option.value || option)
      }));
    }
    
    // Return default empty option if no options available
    return [{ label: 'No options available', value: '' }];
  }, [field.fieldType, options]);
  
  // Memoize display value to avoid recalculation on every render
  const displayValue = useMemo(() => {
    if (!internalValue) return 'Select...';
    
    // Fast path: direct lookup by value using find
    const stringValue = String(internalValue);
    const found = selectOptions.find((option: SelectOption) => String(option.value) === stringValue);
    return found ? found.label : stringValue;
  }, [internalValue, selectOptions]);

  // Handle wheel scroll in dropdown - optimized with passive event
  const handleWheel = useCallback((e: React.WheelEvent) => {
    if (commandListRef.current) {
      e.stopPropagation();
      commandListRef.current.scrollTop += e.deltaY;
    }
  }, []);
  
  // Handle selection - UPDATE INTERNAL VALUE FIRST
  const handleSelect = useCallback((selectedValue: string) => {
    // Store the selected value to prevent it being lost in async operations
    const valueToCommit = selectedValue;
    
    // 1. Update internal value immediately to prevent UI flicker
    setInternalValue(valueToCommit);
    
    // 2. Close the dropdown immediately
    setOpen(false);
    
    // 3. Set processing state to show visual indicator
    setIsProcessing(true);
    
    // 4. Only then call the onChange callback
    // This prevents the parent component from re-rendering and causing dropdown to reopen
    if (onEndEdit) onEndEdit();
    
    // 5. Call onChange synchronously to avoid race conditions with other cells
    onChange(valueToCommit);
    
    // 6. Clear processing state after a short delay - reduced for responsiveness
    setTimeout(() => {
      setIsProcessing(false);
    }, 50);
  }, [onChange, onEndEdit]);

  // If disabled, render a static view
  if (disabled && field.key !== 'line' && field.key !== 'subline') {
    const displayText = displayValue;
    
    return (
      <div
        className={cn(
          "w-full px-3 py-2 h-10 rounded-md text-sm flex items-center",
          "border",
          hasErrors ? "border-destructive" : "border-input",
          className
        )}
        style={{
          backgroundColor: hasClass('!bg-blue-100') ? '#dbeafe' : 
                          hasClass('!bg-blue-200') ? '#bfdbfe' : 
                          hasClass('hover:!bg-blue-100') && isHovered ? '#dbeafe' :
                          undefined,
          borderColor: hasClass('!border-blue-500') ? '#3b82f6' : 
                      hasClass('!border-blue-200') ? '#bfdbfe' : 
                      hasClass('!border-blue-200') && isHovered ? '#bfdbfe' :
                      undefined,
          borderRadius: hasClass('!rounded-md') ? '0.375rem' : undefined,
          cursor: hasClass('hover:!bg-blue-100') ? 'pointer' : undefined
        }}
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
      >
        {displayText || ""}
      </div>
    );
  }

  return (
    <Popover 
      open={open} 
      onOpenChange={(isOpen) => {
        // Only open the popover if we're not in copy down mode
        if (!hasClass('!bg-blue-100') && !hasClass('!bg-blue-200') && !hasClass('hover:!bg-blue-100')) {
          setOpen(isOpen);
          if (isOpen && onStartEdit) onStartEdit();
        }
      }}
    >
      <PopoverTrigger asChild>
        <Button
          variant="outline"
          role="combobox"
          aria-expanded={open}
          className={cn(
            "w-full justify-between font-normal",
            "border",
            !internalValue && "text-muted-foreground",
            isProcessing && "text-muted-foreground",
            hasErrors ? "border-destructive" : "",
            className
          )}
          style={{
            backgroundColor: hasClass('!bg-blue-100') ? '#dbeafe' : 
                            hasClass('!bg-blue-200') ? '#bfdbfe' : 
                            hasClass('hover:!bg-blue-100') && isHovered ? '#dbeafe' :
                            undefined,
            borderColor: hasClass('!border-blue-500') ? '#3b82f6' : 
                        hasClass('!border-blue-200') ? '#bfdbfe' : 
                        hasClass('!border-blue-200') && isHovered ? '#bfdbfe' :
                        undefined,
            borderRadius: hasClass('!rounded-md') ? '0.375rem' : undefined,
            borderWidth: hasClass('!border-blue-500') || hasClass('!border-blue-200') ? '0px' : undefined,
            cursor: hasClass('hover:!bg-blue-100') ? 'pointer' : undefined
          }}
          onClick={(e) => {
            // Don't open the dropdown if we're in copy down mode
            if (hasClass('!bg-blue-100') || hasClass('!bg-blue-200') || hasClass('hover:!bg-blue-100')) {
              // Let the parent cell handle the click by NOT preventing default or stopping propagation
              return;
            }
            
            // Only prevent default and stop propagation if not in copy down mode
            e.preventDefault();
            e.stopPropagation();
            setOpen(!open);
            if (!open && onStartEdit) onStartEdit();
          }}
          onMouseEnter={() => setIsHovered(true)}
          onMouseLeave={() => setIsHovered(false)}
        >
          <span className={isProcessing ? "opacity-70" : ""}>
            {displayValue}
          </span>
          <ChevronsUpDown className="mr-1.5 h-4 w-4 shrink-0 opacity-50" />
        </Button>
      </PopoverTrigger>
      <PopoverContent 
        className="p-0 w-[var(--radix-popover-trigger-width)]" 
        align="start"
        sideOffset={4}
      >
        <Command shouldFilter={true}>
          <CommandInput 
            placeholder="Search..."
            className="h-9"
          />
          <CommandList 
            ref={commandListRef} 
            onWheel={handleWheel}
            className="max-h-[200px]"
          >
            <CommandEmpty>No results found.</CommandEmpty>
            <CommandGroup>
              {selectOptions.map((option: SelectOption) => (
                <CommandItem
                  key={option.value}
                  value={option.label}
                  onSelect={() => handleSelect(option.value)}
                  className="cursor-pointer"
                >
                  {option.label}
                  {String(option.value) === String(internalValue) && (
                    <Check className="ml-auto h-4 w-4" />
                  )}
                </CommandItem>
              ))}
            </CommandGroup>
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
  )
}

// Optimize memo comparison to avoid unnecessary re-renders
export default React.memo(SelectCell, (prev, next) => {
  // Only rerender when these critical props change
  if (prev.value !== next.value) return false;
  if (prev.hasErrors !== next.hasErrors) return false;
  if (prev.disabled !== next.disabled) return false;
  if (prev.className !== next.className) return false;
  
  // Only check options array for reference equality - we're handling deep comparison internally
  if (prev.options !== next.options && 
      (prev.options.length !== next.options.length)) {
    return false;
  }
  
  return true;
}); 