import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { createPortal } from 'react-dom';
import apiService from '../services/apiService';

interface LinkFieldProps {
  label: string;
  doctype: string;
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
  disabled?: boolean;
  filters?: Record<string, any>;
  compact?: boolean;
  usePortal?: boolean; // New prop to enable portal rendering
}

// Stable empty object to avoid re-renders
const EMPTY_FILTERS: Record<string, any> = {};

const LinkField: React.FC<LinkFieldProps> = ({
  label,
  doctype,
  value,
  onChange,
  placeholder,
  disabled = false,
  filters,
  compact = false,
  usePortal = false, // Default to false for backward compatibility
}) => {
  const [searchResults, setSearchResults] = useState<{ value: string; description?: string }[]>([]);
  const [searchText, setSearchText] = useState('');
  const [isDropdownOpen, setDropdownOpen] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [dropdownPosition, setDropdownPosition] = useState<{ top: number; left: number; width: number }>({ top: 0, left: 0, width: 0 });
  const containerRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  const dropdownRef = useRef<HTMLDivElement>(null);
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const lastSearchRef = useRef<string>('');
  const hasLoadedRef = useRef<boolean>(false);
  
  // Use stable empty object if filters not provided
  const stableFilters = filters || EMPTY_FILTERS;
  
  // Stringify filters for comparison (avoid object reference issues)
  const filtersKey = useMemo(() => JSON.stringify(stableFilters), [stableFilters]);

  // Fetch link options from ERPNext with filters
  const searchLink = useCallback(async (text: string = '', force: boolean = false) => {
    // Prevent duplicate calls for the same search text
    const searchKey = `${text}-${filtersKey}`;
    if (!force && lastSearchRef.current === searchKey) {
      return;
    }
    lastSearchRef.current = searchKey;
    
    setIsLoading(true);
    try {
      const params = new URLSearchParams({ 
        doctype, 
        txt: text,
      });

      // Add filters if provided
      if (stableFilters && Object.keys(stableFilters).length > 0) {
        params.append('filters', JSON.stringify(stableFilters));
      }

      const response = await apiService.apiCall<{ value: string; description?: string }[]>(
        `/api/method/frappe.desk.search.search_link?${params.toString()}`
      );
      setSearchResults(response || []);
    } catch (error) {
      console.error(`Error fetching ${doctype} links:`, error);
      setSearchResults([]);
    } finally {
      setIsLoading(false);
    }
  }, [doctype, filtersKey, stableFilters]);

  // Debounced search for typing
  const debouncedSearch = useCallback((text: string) => {
    if (debounceRef.current) {
      clearTimeout(debounceRef.current);
    }
    debounceRef.current = setTimeout(() => {
      searchLink(text);
    }, 300);
  }, [searchLink]);

  // Fetch default options ONLY when dropdown first opens
  useEffect(() => {
    if (isDropdownOpen && !hasLoadedRef.current) {
      hasLoadedRef.current = true;
      searchLink(searchText || '', true);
    }
    
    // Reset the loaded flag when dropdown closes
    if (!isDropdownOpen) {
      hasLoadedRef.current = false;
      lastSearchRef.current = '';
    }
  }, [isDropdownOpen]); // Only depend on isDropdownOpen

  // Cleanup debounce on unmount
  useEffect(() => {
    return () => {
      if (debounceRef.current) {
        clearTimeout(debounceRef.current);
      }
    };
  }, []);

  // Calculate dropdown position for portal rendering
  const updateDropdownPosition = useCallback(() => {
    if (usePortal && inputRef.current) {
      const rect = inputRef.current.getBoundingClientRect();
      setDropdownPosition({
        top: rect.bottom + window.scrollY,
        left: rect.left + window.scrollX,
        width: rect.width
      });
    }
  }, [usePortal]);

  // Update position when dropdown opens or on scroll/resize
  useEffect(() => {
    if (isDropdownOpen && usePortal) {
      updateDropdownPosition();
      
      const handleUpdate = () => updateDropdownPosition();
      window.addEventListener('scroll', handleUpdate, true);
      window.addEventListener('resize', handleUpdate);
      
      return () => {
        window.removeEventListener('scroll', handleUpdate, true);
        window.removeEventListener('resize', handleUpdate);
      };
    }
  }, [isDropdownOpen, usePortal, updateDropdownPosition]);

  // Close dropdown when clicking outside
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      const target = event.target as Node;
      const clickedOutsideContainer = containerRef.current && !containerRef.current.contains(target);
      const clickedOutsideDropdown = usePortal && dropdownRef.current && !dropdownRef.current.contains(target);
      
      // Close if clicked outside both container and dropdown (when using portal)
      if (usePortal) {
        if (clickedOutsideContainer && clickedOutsideDropdown) {
          setDropdownOpen(false);
          setSearchText('');
        }
      } else {
        if (clickedOutsideContainer) {
          setDropdownOpen(false);
          setSearchText('');
        }
      }
    };
    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, [usePortal]);

  // Handle selecting an item from dropdown
  const handleSelect = (selectedValue: string) => {
    onChange(selectedValue);
    setSearchText('');
    setDropdownOpen(false);
  };

  // Handle clearing the field
  const handleClear = () => {
    onChange('');
    setSearchText('');
    setDropdownOpen(false);
  };

  // Render dropdown content
  const renderDropdown = () => {
    const dropdownClasses = `bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 
      rounded-md w-full shadow-lg ${compact ? 'mt-0.5' : 'mt-1'}`;
    
    const positionStyle = usePortal ? {
      position: 'fixed' as const,
      top: `${dropdownPosition.top}px`,
      left: `${dropdownPosition.left}px`,
      width: `${dropdownPosition.width}px`,
      zIndex: 1050,
      marginTop: compact ? '2px' : '4px'
    } : {};

    if (!isDropdownOpen || disabled) return null;

    const dropdownContent = (
      <div ref={dropdownRef}>
        {/* Loading indicator */}
        {isLoading && (
          <div className={`${usePortal ? '' : 'absolute z-[1050]'} ${dropdownClasses} text-center text-gray-500 dark:text-gray-400
            ${compact ? 'p-1.5 text-[10px]' : 'p-3 text-sm'}`}
            style={positionStyle}>
            <span className="inline-block animate-spin mr-2">⏳</span>
            Loading...
          </div>
        )}

        {/* Results list */}
        {!isLoading && searchResults.length > 0 && (
          <ul className={`${usePortal ? '' : 'absolute z-[1050]'} ${dropdownClasses} overflow-auto
            ${compact ? 'max-h-36' : 'max-h-48'}`}
            style={positionStyle}>
            {searchResults.map((item, idx) => (
              <li
                key={idx}
                onClick={() => handleSelect(item.value)}
                className={`cursor-pointer text-gray-900 dark:text-gray-100 
                  hover:bg-blue-500 dark:hover:bg-blue-600 hover:text-white
                  ${compact ? 'px-2 py-1 text-xs' : 'px-3 py-2 text-sm'}
                  ${value === item.value ? 'bg-blue-50 dark:bg-blue-700 font-semibold' : ''}`}
              >
                {item.value}
                {item.description && (
                  <span className={`text-gray-600 dark:text-gray-300 ml-2
                    ${compact ? 'text-[9px] ml-1' : 'text-xs ml-2'}`}>
                    {item.description}
                  </span>
                )}
              </li>
            ))}
          </ul>
        )}

        {/* No results message */}
        {!isLoading && searchResults.length === 0 && (
          <div className={`${usePortal ? '' : 'absolute z-[1050]'} ${dropdownClasses} text-center text-gray-500 dark:text-gray-400
            ${compact ? 'p-1.5 text-[10px]' : 'p-3 text-sm'}`}
            style={positionStyle}>
            No results found
          </div>
        )}
      </div>
    );

    return usePortal ? createPortal(dropdownContent, document.body) : dropdownContent;
  };

  return (
    <div ref={containerRef} className={`relative w-full ${compact ? 'mb-2' : 'mb-4'}`}>
      <label className={`block font-medium text-gray-700 dark:text-gray-300 ${compact ? 'text-[10px] mb-0.5' : 'text-sm mb-1'}`}>
        {label}
      </label>

      <div className="relative">
        <input
          ref={inputRef}
          type="text"
          value={isDropdownOpen ? searchText : value}
          placeholder={placeholder || `Select ${label}`}
          disabled={disabled}
          className={`w-full border border-gray-300 dark:border-gray-600 rounded-md 
            focus:outline-none disabled:bg-gray-100 dark:disabled:bg-gray-700 
            bg-white dark:bg-gray-700 text-gray-900 dark:text-white
            ${compact 
              ? 'px-2 py-1 text-xs focus:ring-1 focus:ring-blue-500 rounded' 
              : 'px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500'
            }
            ${value ? (compact ? 'pr-5' : 'pr-8') : ''}`}
          onFocus={() => {
            if (!disabled) {
              setDropdownOpen(true);
              setSearchText('');
              if (usePortal) {
                updateDropdownPosition();
              }
            }
          }}
          onChange={(e) => {
            const text = e.target.value;
            setSearchText(text);
            debouncedSearch(text); // Use debounced search to prevent rapid API calls
          }}
        />
        
        {/* Clear button */}
        {value && !disabled && !isDropdownOpen && (
          <button
            type="button"
            onClick={handleClear}
            className={`absolute top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300
              ${compact ? 'right-1 text-xs' : 'right-2 text-sm'}`}
          >
            ✕
          </button>
        )}
      </div>

      {/* Render dropdown */}
      {renderDropdown()}
    </div>
  );
};

export default LinkField;
