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

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

interface PaginatedSelectProps {
  label: string;
  required?: boolean;
  error?: string;
  helperText?: string;
  placeholder?: string;
  value: string;
  onValueChange: (value: string) => void;
  onLoadOptions: (page: number, limit: number) => Promise<{
    options: PaginatedSelectOption[];
    pagination: {
      page: number;
      limit: number;
      total: number;
      totalPages: number;
      hasMore: boolean;
    };
  }>;
  className?: string;
  id?: string;
}

export const PaginatedSelect = ({
  label,
  required = false,
  error,
  helperText,
  placeholder = 'Select Item',
  value,
  onValueChange,
  onLoadOptions,
  className,
  id,
}: PaginatedSelectProps): ReactElement => {
  const [isOpen, setIsOpen] = useState<boolean>(false);
  const [options, setOptions] = useState<PaginatedSelectOption[]>([]);
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [isLoadingMore, setIsLoadingMore] = useState<boolean>(false);
  const [pagination, setPagination] = useState<{
    page: number;
    limit: number;
    total: number;
    totalPages: number;
    hasMore: boolean;
  }>({
    page: 1,
    limit: 20,
    total: 0,
    totalPages: 1,
    hasMore: false,
  });

  const dropdownRef = useRef<HTMLDivElement>(null);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const dropdownMenuRef = useRef<HTMLDivElement>(null);
  const scrollContainerRef = useRef<HTMLUListElement>(null);
  const [dropdownStyle, setDropdownStyle] = useState<{
    top?: string;
    bottom?: string;
    left: string;
    width: string;
  }>({ left: '0', width: '0' });

  // Load initial options
  const loadOptions = useCallback(
    async (page: number = 1, append: boolean = false) => {
      try {
        if (page === 1) {
          setIsLoading(true);
        } else {
          setIsLoadingMore(true);
        }

        const result = await onLoadOptions(page, pagination.limit);
        
        if (append) {
          setOptions((prev) => [...prev, ...result.options]);
        } else {
          setOptions(result.options);
        }
        
        setPagination(result.pagination);
      } catch (err) {
        console.error('Error loading options:', err);
      } finally {
        setIsLoading(false);
        setIsLoadingMore(false);
      }
    },
    [onLoadOptions, pagination.limit]
  );

  // Load options when dropdown opens
  useEffect(() => {
    if (isOpen) {
      if (options.length === 0) {
        loadOptions(1, false);
      }
    } else {
      // Reset pagination when dropdown closes (but keep options for faster reopening)
      // Only reset if we want fresh data each time
      // setOptions([]);
      // setPagination({ page: 1, limit: 20, total: 0, totalPages: 1, hasMore: false });
    }
  }, [isOpen, options.length, loadOptions]);

  // Handle scroll for infinite loading
  useEffect(() => {
    const scrollContainer = scrollContainerRef.current;
    if (!scrollContainer || !isOpen) return;

    const handleScroll = () => {
      const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
      const isNearBottom = scrollTop + clientHeight >= scrollHeight - 50;

      if (isNearBottom && pagination.hasMore && !isLoadingMore && !isLoading) {
        loadOptions(pagination.page + 1, true);
      }
    };

    scrollContainer.addEventListener('scroll', handleScroll);
    return () => {
      scrollContainer.removeEventListener('scroll', handleScroll);
    };
  }, [isOpen, pagination, isLoadingMore, isLoading, loadOptions]);

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

    if (isOpen && buttonRef.current) {
      document.addEventListener('mousedown', handleClickOutside);

      const rect = buttonRef.current.getBoundingClientRect();
      const spaceBelow = window.innerHeight - rect.bottom;
      const spaceAbove = rect.top;
      const dropdownHeight = Math.min(240, 240);

      const shouldOpenUp = spaceBelow < dropdownHeight && spaceAbove > spaceBelow;

      if (shouldOpenUp) {
        setDropdownStyle({
          bottom: `${window.innerHeight - rect.top + 5}px`,
          left: `${rect.left}px`,
          width: `${rect.width}px`,
        });
      } else {
        setDropdownStyle({
          top: `${rect.bottom + 5}px`,
          left: `${rect.left}px`,
          width: `${rect.width}px`,
        });
      }
    }

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

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

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

  return (
    <div className="flex flex-col gap-2 pb-4">
      <label
        htmlFor={fieldId}
        className="flex items-center gap-1.5 text-[13px] font-medium text-[#0e1b2a]"
      >
        <span>{label}</span>
        {required && <span className="text-[#e02424] text-[8px]">*</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',
            value ? '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}
              className="fixed bg-white border border-[rgba(0,0,0,0.2)] rounded-md shadow-lg z-[250] max-h-60 overflow-hidden flex flex-col"
              style={dropdownStyle}
              data-dropdown-menu="true"
            >
              {isLoading && options.length === 0 ? (
                <div className="flex items-center justify-center py-8">
                  <Loader2 className="w-5 h-5 text-[#112868] animate-spin" />
                </div>
              ) : (
                <>
                  <ul
                    ref={scrollContainerRef}
                    role="listbox"
                    className="py-1.5 overflow-y-auto flex-1"
                  >
                    {options.map((option) => (
                      <li key={option.value} role="option" aria-selected={value === 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',
                            value === option.value && 'bg-gray-50'
                          )}
                        >
                          {option.label}
                        </button>
                      </li>
                    ))}
                    {isLoadingMore && (
                      <li className="flex items-center justify-center py-2">
                        <Loader2 className="w-4 h-4 text-[#112868] animate-spin" />
                      </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>
      )}
    </div>
  );
};
