import { useState, useRef, useEffect } from 'react';
import { createPortal } from 'react-dom';
import type { ReactElement, SelectHTMLAttributes } from 'react';
import { ChevronDown } from 'lucide-react';
import { cn } from '@/lib/utils';

interface SelectOption {
  value: string;
  label: string;
}

interface FormSelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, 'onChange'> {
  label: string;
  required?: boolean;
  error?: string;
  helperText?: string;
  options: SelectOption[];
  placeholder?: string;
  onValueChange?: (value: string) => void;
}

export const FormSelect = ({
  label,
  required = false,
  error,
  helperText,
  options,
  placeholder = 'Select Item',
  className,
  id,
  value,
  onValueChange,
  ...props
}: FormSelectProps): ReactElement => {
  const [isOpen, setIsOpen] = useState<boolean>(false);
  const [selectedValue, setSelectedValue] = useState<string>(value as string || '');
  const [dropdownStyle, setDropdownStyle] = useState<{ top?: string; bottom?: string; left: string; width: string }>({ left: '0', width: '0' });
  const dropdownRef = useRef<HTMLDivElement>(null);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const dropdownMenuRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        dropdownRef.current &&
        !dropdownRef.current.contains(event.target as Node) &&
        dropdownMenuRef.current &&
        !dropdownMenuRef.current.contains(event.target as Node)
      ) {
        setIsOpen(false);
      }
    };

    const handleScroll = (event: Event) => {
      // Don't close if scrolling inside the dropdown menu itself
      const target = event.target as HTMLElement;
      if (dropdownMenuRef.current && (dropdownMenuRef.current === target || dropdownMenuRef.current.contains(target))) {
        return;
      }
      setIsOpen(false);
    };

    if (isOpen && buttonRef.current) {
      document.addEventListener('mousedown', handleClickOutside);
      window.addEventListener('scroll', handleScroll, true);
      // Calculate position when dropdown opens
      const rect = buttonRef.current.getBoundingClientRect();
      const spaceBelow = window.innerHeight - rect.bottom;
      const spaceAbove = rect.top;
      const dropdownHeight = 240; // max-h-60 = 240px
      
      // Determine if should open upward or downward
      const shouldOpenUp = spaceBelow < dropdownHeight && spaceAbove > spaceBelow;
      
      // Calculate dropdown position
      const left = rect.left;
      const width = rect.width;
      
      if (shouldOpenUp) {
        // Position above the button
        const bottom = window.innerHeight - rect.top;
        setDropdownStyle({
          bottom: `${bottom}px`,
          left: `${left}px`,
          width: `${width}px`,
        });
      } else {
        // Position below the button
        const top = rect.bottom;
        setDropdownStyle({
          top: `${top}px`,
          left: `${left}px`,
          width: `${width}px`,
        });
      }
    }

    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
      window.removeEventListener('scroll', handleScroll, true);
    };
  }, [isOpen]);

  useEffect(() => {
    if (value !== undefined) {
      setSelectedValue(value as string);
    }
  }, [value]);

  const fieldId = id || `select-${label.toLowerCase().replace(/\s+/g, '-')}`;
  const hasError = Boolean(error);
  const selectedOption = options.find((opt) => opt.value === selectedValue);

  const handleSelect = (optionValue: string) => {
    setSelectedValue(optionValue);
    if (onValueChange) {
      onValueChange(optionValue);
    }
    setIsOpen(false);
  };

  return (
    <div className="flex flex-col gap-2 pb-4">
      <label
        htmlFor={fieldId}
        className="flex items-center gap-1 text-[13px] font-medium text-[#0e1b2a]"
      >
        <span>{label}</span>
        {required && <span className="text-[#e02424]">*</span>}
      </label>
      <div className="relative" ref={dropdownRef}>
        <button
          ref={buttonRef}
          type="button"
          id={fieldId}
          onClick={() => setIsOpen(!isOpen)}
          className={cn(
            'h-10 w-full px-3.5 py-1 bg-white border rounded-md text-sm transition-colors',
            'flex items-center justify-between',
            hasError
              ? 'border-[#ef4444] focus-visible:border-[#ef4444] focus-visible:ring-[#ef4444]/20'
              : 'border-[rgba(0,0,0,0.08)] focus-visible:border-[#112868] focus-visible:ring-[#112868]/20',
            'focus-visible:outline-none focus-visible:ring-2',
            selectedValue ? 'text-[#0e1b2a]' : 'text-[#9aa6b2]',
            className
          )}
          aria-invalid={hasError}
          aria-expanded={isOpen}
          aria-haspopup="listbox"
        >
          <span>{selectedOption ? selectedOption.label : placeholder}</span>
          <ChevronDown
            className={cn('w-4 h-4 transition-transform', isOpen && 'rotate-180')}
          />
        </button>

        {isOpen && buttonRef.current && createPortal(
          <div
            ref={dropdownMenuRef}
            data-dropdown-menu="true"
            className="fixed bg-white border border-[rgba(0,0,0,0.2)] rounded-md shadow-lg z-[250] max-h-60 overflow-y-auto"
            style={dropdownStyle}
          >
            <ul role="listbox" className="py-1.5">
              {options.map((option) => (
                <li key={option.value} role="option" aria-selected={selectedValue === option.value}>
                  <button
                    type="button"
                    onClick={() => handleSelect(option.value)}
                    className={cn(
                      'w-full px-3 py-2 text-left text-sm text-[#0e1b2a] hover:bg-gray-50 transition-colors',
                      selectedValue === option.value && 'bg-gray-50'
                    )}
                  >
                    {option.label}
                  </button>
                </li>
              ))}
            </ul>
          </div>,
          document.body
        )}
      </div>
      {error && (
        <p id={`${fieldId}-error`} className="text-sm text-[#ef4444]" role="alert">
          {error}
        </p>
      )}
      {helperText && !error && (
        <p id={`${fieldId}-helper`} className="text-sm text-[#6b7280]">
          {helperText}
        </p>
      )}
      <select
        value={selectedValue}
        onChange={(e) => handleSelect(e.target.value)}
        className="sr-only"
        aria-hidden="true"
        tabIndex={-1}
        {...props}
      >
        <option value="">{placeholder}</option>
        {options.map((option) => (
          <option key={option.value} value={option.value}>
            {option.label}
          </option>
        ))}
      </select>
    </div>
  );
};
