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;
  leftIcon?: React.ReactNode;
  rightIcon?: React.ReactNode;
}

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',
  leftIcon,
  rightIcon,
  className,
  id,
  disabled,
  ...props
}, ref) => {
  const selectId = id || `select-${Math.random().toString(36).substr(2, 9)}`;

  // Filter out non-DOM props to avoid React warnings
  const {
    // Remove Select-specific props that shouldn't be passed to DOM
    label: _label,
    error: _error,
    helperText: _helperText,
    placeholder: _placeholder,
    size: _size,
    variant: _variant,
    options: _options,
    value: _value,
    defaultValue: _defaultValue,
    multiple: _multiple,
    searchable: _searchable,
    clearable: _clearable,
    loading: _loading,
    isRequired: _isRequired,
    isInvalid: _isInvalid,
    maxHeight: _maxHeight,
    dropdownPosition: _dropdownPosition,
    createable: _createable,
    onCreate: _onCreate,
    onSearch: _onSearch,
    onChange: _onChange,
    renderOption: _renderOption,
    renderValue: _renderValue,
    noOptionsMessage: _noOptionsMessage,
    loadingMessage: _loadingMessage,
    createLabel: _createLabel,
    leftIcon: _leftIcon,
    rightIcon: _rightIcon,
    ...domProps
  } = props as any;
  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 gap-2',
    'bg-[var(--bg-primary,#ffffff)] border border-[var(--border-primary,#e5e7eb)] rounded-lg',
    'text-[var(--text-primary,#111827)] text-left transition-colors duration-200',
    'focus:border-[var(--color-primary,#3b82f6)] focus:ring-1 focus:ring-[var(--color-primary,#3b82f6)]',
    {
      'border-[var(--color-error,#ef4444)] focus:border-[var(--color-error,#ef4444)] focus:ring-[var(--color-error,#ef4444)]': hasError,
      'bg-[var(--bg-secondary,#f9fafb)] border-transparent focus:bg-[var(--bg-primary,#ffffff)] focus:border-[var(--color-primary,#3b82f6)]': variant === 'filled',
      'bg-transparent border-none focus:ring-0': variant === 'unstyled',
    }
  ];

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

  const dropdownClasses = [
    'absolute z-50 w-full mt-1 bg-[var(--bg-primary,#ffffff)] border border-[var(--border-primary,#e5e7eb)] 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-[var(--text-tertiary,#6b7280)] break-words">{placeholder}</span>;
      }

      if (currentValue.length === 1) {
        const option = selectedOptions[0];
        return option ? <span className="break-words">{option.label}</span> : <span className="break-words">{currentValue[0]}</span>;
      }

      return <span className="break-words">{currentValue.length} elementos seleccionados</span>;
    }
    
    const selectedOption = selectedOptions[0];
    if (selectedOption) {
      return (
        <div className="flex items-center gap-2">
          {selectedOption.icon && <span className="flex-shrink-0">{selectedOption.icon}</span>}
          <span className="break-words">{selectedOption.label}</span>
        </div>
      );
    }

    return <span className="text-[var(--text-tertiary,#6b7280)] break-words">{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-[var(--bg-tertiary,#f3f4f6)] text-[var(--text-primary,#111827)] 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-[var(--text-tertiary,#6b7280)] hover:text-[var(--text-primary,#111827)] 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-[var(--text-secondary,#4b5563)]">
          {loadingMessage}
        </div>
      );
    }

    if (filteredOptions.length === 0) {
      return (
        <div className="px-3 py-2 text-[var(--text-secondary,#4b5563)]">
          {noOptionsMessage}
          {createable && searchTerm.trim() && (
            <button
              type="button"
              onClick={handleCreate}
              className="block w-full text-left px-3 py-2 text-[var(--color-primary,#3b82f6)] hover:bg-[var(--bg-secondary,#f9fafb)] 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-[var(--bg-secondary,#f9fafb)]': isHighlighted,
              'bg-[var(--color-primary,#3b82f6)]/10 text-[var(--color-primary,#3b82f6)]': 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-[var(--border-primary,#e5e7eb)] text-[var(--color-primary,#3b82f6)] focus:ring-[var(--color-primary,#3b82f6)]"
              />
            )}
            {option.icon && <span>{option.icon}</span>}
            <div className="flex-1">
              <div className="font-medium">{option.label}</div>
              {option.description &&
               !option.description.startsWith('descriptions.') &&
               !option.description.includes('.') &&
               option.description !== option.value && (
                <div className="text-xs text-[var(--text-secondary,#4b5563)]">{option.description}</div>
              )}
            </div>
          </div>
          {isSelected && !multiple && (
            <svg className="w-4 h-4 text-[var(--color-primary,#3b82f6)]" 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-[var(--text-tertiary,#6b7280)] 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-[var(--color-primary,#3b82f6)] hover:bg-[var(--bg-secondary,#f9fafb)] transition-colors duration-150 border-t border-[var(--border-primary,#e5e7eb)]"
        >
          {createLabel} "{searchTerm.trim()}"
        </button>
      );
    }

    return allOptions;
  };

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

      <div
        ref={ref || containerRef}
        className={clsx(baseClasses, className)}
        onKeyDown={handleKeyDown}
        tabIndex={disabled ? -1 : 0}
        onFocus={onFocus}
        onBlur={onBlur}
        {...domProps}
      >
        <div
          className={clsx(triggerClasses, sizeClasses[size])}
          onClick={() => !disabled && setIsOpen(!isOpen)}
        >
          <div className="flex-1 overflow-hidden">
            {multiple && Array.isArray(currentValue) && currentValue.length > 0 && currentValue.length <= 3 ? (
              renderMultipleValues()
            ) : (
              renderSelectedValue()
            )}
          </div>

          <div className="flex items-center gap-1 flex-shrink-0">
            {clearable && currentValue && (multiple ? (Array.isArray(currentValue) && currentValue.length > 0) : true) && (
              <button
                type="button"
                onClick={handleClear}
                className="text-[var(--text-tertiary,#6b7280)] hover:text-[var(--text-primary,#111827)] 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-[var(--text-tertiary,#6b7280)] 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-[var(--border-primary,#e5e7eb)]">
              <input
                ref={searchInputRef}
                type="text"
                placeholder="Buscar..."
                value={searchTerm}
                onChange={handleSearchChange}
                className="w-full px-3 py-2 border border-[var(--border-primary,#e5e7eb)] rounded bg-[var(--bg-primary,#ffffff)] text-[var(--text-primary,#111827)] focus:outline-none focus:ring-2 focus:ring-[var(--color-primary,#3b82f6)]/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-[var(--color-error,#ef4444)]">
          {error}
        </p>
      )}

      {helperText && !error && (
        <p className="mt-2 text-sm text-[var(--text-secondary,#4b5563)]">
          {helperText}
        </p>
      )}
    </div>
  );
});

Select.displayName = 'Select';

export default Select;