import React, { forwardRef, useState, useRef, useEffect, useMemo } from 'react';
import { clsx } from 'clsx';

export interface SelectOption {
  value: string | number;
  label: string;
  disabled?: boolean;
  group?: string;
  icon?: React.ReactNode;
  description?: string;
}

export interface SelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'onChange' | 'onSelect'> {
  label?: string;
  error?: string;
  helperText?: string;
  placeholder?: string;
  size?: 'sm' | 'md' | 'lg';
  variant?: 'outline' | 'filled' | 'unstyled';
  options: SelectOption[];
  value?: string | number | Array<string | number>;
  defaultValue?: string | number | Array<string | number>;
  multiple?: boolean;
  searchable?: boolean;
  clearable?: boolean;
  loading?: boolean;
  isRequired?: boolean;
  isInvalid?: boolean;
  maxHeight?: number;
  dropdownPosition?: 'auto' | 'top' | 'bottom';
  createable?: boolean;
  onCreate?: (inputValue: string) => void;
  onSearch?: (inputValue: string) => void;
  onChange?: (value: string | number | Array<string | number>) => void;
  onBlur?: (event: React.FocusEvent<HTMLDivElement>) => void;
  onFocus?: (event: React.FocusEvent<HTMLDivElement>) => void;
  renderOption?: (option: SelectOption, isSelected: boolean) => React.ReactNode;
  renderValue?: (value: string | number | Array<string | number>, options: SelectOption[]) => React.ReactNode;
  noOptionsMessage?: string;
  loadingMessage?: string;
  createLabel?: string;
}

const Select = forwardRef<HTMLDivElement, SelectProps>(({
  label,
  error,
  helperText,
  placeholder = 'Seleccionar...',
  size = 'md',
  variant = 'outline',
  options = [],
  value,
  defaultValue,
  multiple = false,
  searchable = false,
  clearable = false,
  loading = false,
  isRequired = false,
  isInvalid = false,
  maxHeight = 300,
  dropdownPosition = 'auto',
  createable = false,
  onCreate,
  onSearch,
  onChange,
  onBlur,
  onFocus,
  renderOption,
  renderValue,
  noOptionsMessage = 'No hay opciones disponibles',
  loadingMessage = 'Cargando...',
  createLabel = 'Crear',
  className,
  id,
  disabled,
  ...props
}, ref) => {
  const selectId = id || `select-${Math.random().toString(36).substr(2, 9)}`;
  const [internalValue, setInternalValue] = useState<string | number | Array<string | number>>(
    value !== undefined ? value : defaultValue || (multiple ? [] : '')
  );
  const [isOpen, setIsOpen] = useState(false);
  const [searchTerm, setSearchTerm] = useState('');
  const [highlightedIndex, setHighlightedIndex] = useState(-1);
  
  const containerRef = useRef<HTMLDivElement>(null);
  const searchInputRef = useRef<HTMLInputElement>(null);
  const optionsRef = useRef<HTMLDivElement>(null);

  // Use controlled value if provided, otherwise use internal state
  const currentValue = value !== undefined ? value : internalValue;

  // Filter options based on search term
  const filteredOptions = useMemo(() => {
    if (!searchable || !searchTerm) return options;
    
    return options.filter(option =>
      option.label.toLowerCase().includes(searchTerm.toLowerCase()) ||
      option.value.toString().toLowerCase().includes(searchTerm.toLowerCase())
    );
  }, [options, searchTerm, searchable]);

  // Group options if they have groups
  const groupedOptions = useMemo(() => {
    const groups: { [key: string]: SelectOption[] } = {};
    const ungrouped: SelectOption[] = [];

    filteredOptions.forEach(option => {
      if (option.group) {
        if (!groups[option.group]) {
          groups[option.group] = [];
        }
        groups[option.group].push(option);
      } else {
        ungrouped.push(option);
      }
    });

    return { groups, ungrouped };
  }, [filteredOptions]);

  // Check if option is selected
  const isOptionSelected = (option: SelectOption) => {
    if (multiple && Array.isArray(currentValue)) {
      return currentValue.includes(option.value);
    }
    return currentValue === option.value;
  };

  // Get selected options for display
  const getSelectedOptions = () => {
    if (multiple && Array.isArray(currentValue)) {
      return options.filter(option => currentValue.includes(option.value));
    }
    return options.filter(option => option.value === currentValue);
  };

  // Handle option selection
  const handleOptionSelect = (option: SelectOption) => {
    if (option.disabled) return;

    let newValue: string | number | Array<string | number>;

    if (multiple) {
      const currentArray = Array.isArray(currentValue) ? currentValue : [];
      if (currentArray.includes(option.value)) {
        newValue = currentArray.filter(val => val !== option.value);
      } else {
        newValue = [...currentArray, option.value];
      }
    } else {
      newValue = option.value;
      setIsOpen(false);
    }

    if (value === undefined) {
      setInternalValue(newValue);
    }
    onChange?.(newValue);
  };

  // Handle search input change
  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value;
    setSearchTerm(value);
    setHighlightedIndex(-1);
    onSearch?.(value);
  };

  // Handle clear selection
  const handleClear = (e: React.MouseEvent) => {
    e.stopPropagation();
    const newValue = multiple ? [] : '';
    
    if (value === undefined) {
      setInternalValue(newValue);
    }
    onChange?.(newValue);
  };

  // Handle remove single option in multiple mode
  const handleRemoveOption = (optionValue: string | number, e: React.MouseEvent) => {
    e.stopPropagation();
    if (!multiple || !Array.isArray(currentValue)) return;
    
    const newValue = currentValue.filter(val => val !== optionValue);
    if (value === undefined) {
      setInternalValue(newValue);
    }
    onChange?.(newValue);
  };

  // Handle create new option
  const handleCreate = () => {
    if (!createable || !onCreate || !searchTerm.trim()) return;
    
    onCreate(searchTerm.trim());
    setSearchTerm('');
    setIsOpen(false);
  };

  // Handle keyboard navigation
  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (!isOpen) {
      if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {
        e.preventDefault();
        setIsOpen(true);
      }
      return;
    }

    switch (e.key) {
      case 'Escape':
        setIsOpen(false);
        setSearchTerm('');
        break;
      case 'ArrowDown':
        e.preventDefault();
        setHighlightedIndex(prev => 
          prev < filteredOptions.length - 1 ? prev + 1 : 0
        );
        break;
      case 'ArrowUp':
        e.preventDefault();
        setHighlightedIndex(prev => 
          prev > 0 ? prev - 1 : filteredOptions.length - 1
        );
        break;
      case 'Enter':
        e.preventDefault();
        if (highlightedIndex >= 0 && highlightedIndex < filteredOptions.length) {
          handleOptionSelect(filteredOptions[highlightedIndex]);
        } else if (createable && searchTerm.trim()) {
          handleCreate();
        }
        break;
      case 'Tab':
        setIsOpen(false);
        break;
    }
  };

  // Close dropdown when clicking outside
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
        setIsOpen(false);
        setSearchTerm('');
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, []);

  // Focus search input when dropdown opens
  useEffect(() => {
    if (isOpen && searchable && searchInputRef.current) {
      searchInputRef.current.focus();
    }
  }, [isOpen, searchable]);

  // Scroll highlighted option into view
  useEffect(() => {
    if (highlightedIndex >= 0 && optionsRef.current) {
      const optionElement = optionsRef.current.children[highlightedIndex] as HTMLElement;
      if (optionElement) {
        optionElement.scrollIntoView({ block: 'nearest' });
      }
    }
  }, [highlightedIndex]);

  const hasError = isInvalid || !!error;

  const baseClasses = [
    'relative w-full cursor-pointer',
    'transition-colors duration-200',
    'focus:outline-none',
    {
      'opacity-50 cursor-not-allowed': disabled,
    }
  ];

  const triggerClasses = [
    'flex items-center justify-between w-full px-3 py-2',
    'bg-input-bg border border-input-border rounded-lg',
    'text-left transition-colors duration-200',
    'focus:border-input-border-focus focus:ring-1 focus:ring-input-border-focus',
    {
      'border-input-border-error focus:border-input-border-error focus:ring-input-border-error': hasError,
      'bg-bg-secondary border-transparent focus:bg-input-bg focus:border-input-border-focus': variant === 'filled',
      'bg-transparent border-none focus:ring-0': variant === 'unstyled',
    }
  ];

  const sizeClasses = {
    sm: 'h-8 text-sm',
    md: 'h-10 text-base',
    lg: 'h-12 text-lg',
  };

  const dropdownClasses = [
    'absolute z-50 w-full mt-1 bg-dropdown-bg border border-dropdown-border rounded-lg shadow-lg',
    'transform transition-all duration-200 ease-out',
    {
      'opacity-0 scale-95 pointer-events-none': !isOpen,
      'opacity-100 scale-100': isOpen,
    }
  ];

  const renderSelectedValue = () => {
    const selectedOptions = getSelectedOptions();
    
    if (renderValue) {
      return renderValue(currentValue, selectedOptions);
    }

    if (multiple && Array.isArray(currentValue)) {
      if (currentValue.length === 0) {
        return <span className="text-input-placeholder">{placeholder}</span>;
      }
      
      if (currentValue.length === 1) {
        const option = selectedOptions[0];
        return option ? option.label : currentValue[0];
      }
      
      return <span>{currentValue.length} elementos seleccionados</span>;
    }
    
    const selectedOption = selectedOptions[0];
    if (selectedOption) {
      return (
        <div className="flex items-center gap-2">
          {selectedOption.icon && <span>{selectedOption.icon}</span>}
          <span>{selectedOption.label}</span>
        </div>
      );
    }
    
    return <span className="text-input-placeholder">{placeholder}</span>;
  };

  const renderMultipleValues = () => {
    if (!multiple || !Array.isArray(currentValue) || currentValue.length === 0) {
      return null;
    }

    const selectedOptions = getSelectedOptions();
    
    if (selectedOptions.length <= 3) {
      return (
        <div className="flex flex-wrap gap-1">
          {selectedOptions.map(option => (
            <span
              key={option.value}
              className="inline-flex items-center gap-1 px-2 py-1 bg-bg-tertiary text-text-primary rounded text-sm"
            >
              {option.icon && <span className="text-xs">{option.icon}</span>}
              <span>{option.label}</span>
              <button
                type="button"
                onClick={(e) => handleRemoveOption(option.value, e)}
                className="text-text-tertiary hover:text-text-primary transition-colors duration-150"
              >
                <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                </svg>
              </button>
            </span>
          ))}
        </div>
      );
    }

    return null;
  };

  const renderOptions = () => {
    if (loading) {
      return (
        <div className="px-3 py-2 text-text-secondary">
          {loadingMessage}
        </div>
      );
    }

    if (filteredOptions.length === 0) {
      return (
        <div className="px-3 py-2 text-text-secondary">
          {noOptionsMessage}
          {createable && searchTerm.trim() && (
            <button
              type="button"
              onClick={handleCreate}
              className="block w-full text-left px-3 py-2 text-color-primary hover:bg-dropdown-item-hover transition-colors duration-150"
            >
              {createLabel} "{searchTerm.trim()}"
            </button>
          )}
        </div>
      );
    }

    const renderOptionItem = (option: SelectOption, index: number) => {
      const isSelected = isOptionSelected(option);
      const isHighlighted = index === highlightedIndex;
      
      if (renderOption) {
        return renderOption(option, isSelected);
      }

      return (
        <div
          key={option.value}
          className={clsx(
            'flex items-center justify-between px-3 py-2 cursor-pointer transition-colors duration-150',
            {
              'bg-dropdown-item-hover': isHighlighted,
              'bg-color-primary/10 text-color-primary': isSelected && !multiple,
              'opacity-50 cursor-not-allowed': option.disabled,
            }
          )}
          onClick={() => handleOptionSelect(option)}
          onMouseEnter={() => setHighlightedIndex(index)}
        >
          <div className="flex items-center gap-2 flex-1">
            {multiple && (
              <input
                type="checkbox"
                checked={isSelected}
                readOnly
                className="rounded border-input-border text-color-primary focus:ring-color-primary"
              />
            )}
            {option.icon && <span>{option.icon}</span>}
            <div className="flex-1">
              <div className="font-medium">{option.label}</div>
              {option.description && (
                <div className="text-xs text-text-secondary">{option.description}</div>
              )}
            </div>
          </div>
          {isSelected && !multiple && (
            <svg className="w-4 h-4 text-color-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
            </svg>
          )}
        </div>
      );
    };

    const allOptions: React.ReactNode[] = [];

    // Add ungrouped options
    groupedOptions.ungrouped.forEach((option, index) => {
      allOptions.push(renderOptionItem(option, index));
    });

    // Add grouped options
    Object.entries(groupedOptions.groups).forEach(([groupName, groupOptions]) => {
      allOptions.push(
        <div key={groupName} className="px-3 py-1 text-xs font-semibold text-text-tertiary uppercase tracking-wide">
          {groupName}
        </div>
      );
      
      groupOptions.forEach((option, index) => {
        const globalIndex = groupedOptions.ungrouped.length + index;
        allOptions.push(renderOptionItem(option, globalIndex));
      });
    });

    // Add create option if applicable
    if (createable && searchTerm.trim() && !filteredOptions.some(opt => 
      opt.label.toLowerCase() === searchTerm.toLowerCase() || 
      opt.value.toString().toLowerCase() === searchTerm.toLowerCase()
    )) {
      allOptions.push(
        <button
          key="__create__"
          type="button"
          onClick={handleCreate}
          className="block w-full text-left px-3 py-2 text-color-primary hover:bg-dropdown-item-hover transition-colors duration-150 border-t border-border-primary"
        >
          {createLabel} "{searchTerm.trim()}"
        </button>
      );
    }

    return allOptions;
  };

  return (
    <div className="w-full">
      {label && (
        <label
          htmlFor={selectId}
          className="block text-sm font-medium text-text-primary mb-2"
        >
          {label}
          {isRequired && (
            <span className="text-color-error ml-1">*</span>
          )}
        </label>
      )}

      <div
        ref={ref || containerRef}
        className={clsx(baseClasses, className)}
        onKeyDown={handleKeyDown}
        tabIndex={disabled ? -1 : 0}
        onFocus={onFocus}
        onBlur={onBlur}
        {...props}
      >
        <div
          className={clsx(triggerClasses, sizeClasses[size])}
          onClick={() => !disabled && setIsOpen(!isOpen)}
        >
          <div className="flex-1 min-w-0">
            {multiple && Array.isArray(currentValue) && currentValue.length > 0 && currentValue.length <= 3 ? (
              renderMultipleValues()
            ) : (
              renderSelectedValue()
            )}
          </div>
          
          <div className="flex items-center gap-1 ml-2">
            {clearable && currentValue && (multiple ? (Array.isArray(currentValue) && currentValue.length > 0) : true) && (
              <button
                type="button"
                onClick={handleClear}
                className="text-text-tertiary hover:text-text-primary transition-colors duration-150 p-1"
                tabIndex={-1}
              >
                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                </svg>
              </button>
            )}
            
            <svg
              className={clsx('w-4 h-4 text-text-tertiary transition-transform duration-200', {
                'rotate-180': isOpen,
              })}
              fill="none"
              stroke="currentColor"
              viewBox="0 0 24 24"
            >
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
            </svg>
          </div>
        </div>

        <div className={clsx(dropdownClasses)} style={{ maxHeight: isOpen ? maxHeight : 0 }}>
          {searchable && (
            <div className="p-2 border-b border-border-primary">
              <input
                ref={searchInputRef}
                type="text"
                placeholder="Buscar..."
                value={searchTerm}
                onChange={handleSearchChange}
                className="w-full px-3 py-2 border border-input-border rounded bg-input-bg focus:outline-none focus:ring-2 focus:ring-color-primary/20"
                onClick={(e) => e.stopPropagation()}
              />
            </div>
          )}
          
          <div
            ref={optionsRef}
            className="max-h-60 overflow-y-auto"
            style={{ maxHeight: searchable ? maxHeight - 60 : maxHeight }}
          >
            {renderOptions()}
          </div>
        </div>
      </div>

      {error && (
        <p className="mt-2 text-sm text-color-error">
          {error}
        </p>
      )}

      {helperText && !error && (
        <p className="mt-2 text-sm text-text-secondary">
          {helperText}
        </p>
      )}
    </div>
  );
});

Select.displayName = 'Select';

export default Select;