import React, { useState, useEffect, useCallback, useRef } from 'react';

interface PropertySuggestion {
  id: string;
  label: string;
  availableInItems: string[]; // Wikidata IDs that have this property
}

interface PropertyInputProps {
  propertyCache: Record<string, Record<string, string>>; // wikidataId -> properties
  propertyLabels: Record<string, string>; // propertyId -> label
  onAddProperty: (propertyId: string) => void;
  onFetchPropertyLabels: (propertyIds: string[]) => Promise<Record<string, string>>;
  className?: string;
}

export function PropertyInput({
  propertyCache,
  propertyLabels,
  onAddProperty,
  onFetchPropertyLabels,
  className = ''
}: PropertyInputProps) {
  const [inputValue, setInputValue] = useState('');
  const [suggestions, setSuggestions] = useState<PropertySuggestion[]>([]);
  const [showSuggestions, setShowSuggestions] = useState(false);
  const [selectedIndex, setSelectedIndex] = useState(-1);
  const [isLoading, setIsLoading] = useState(false);
  
  const inputRef = useRef<HTMLInputElement>(null);
  const suggestionsRef = useRef<HTMLDivElement>(null);

  // Aggregate all available properties from all Wikidata items
  const aggregateAvailableProperties = useCallback((): PropertySuggestion[] => {
    const propertyMap = new Map<string, Set<string>>();
    
    // Collect all properties from all cached Wikidata items
    Object.entries(propertyCache).forEach(([wikidataId, properties]) => {
      Object.keys(properties).forEach(propertyId => {
        if (!propertyMap.has(propertyId)) {
          propertyMap.set(propertyId, new Set());
        }
        propertyMap.get(propertyId)!.add(wikidataId);
      });
    });
    
    // Convert to PropertySuggestion array
    const suggestions: PropertySuggestion[] = [];
    propertyMap.forEach((wikidataIds, propertyId) => {
      const label = propertyLabels[propertyId] || propertyId;
      suggestions.push({
        id: propertyId,
        label: label,
        availableInItems: Array.from(wikidataIds)
      });
    });
    
    // Sort by label for better UX
    return suggestions.sort((a, b) => a.label.localeCompare(b.label));
  }, [propertyCache, propertyLabels]);

  // Update suggestions when propertyCache or propertyLabels change
  useEffect(() => {
    const availableProperties = aggregateAvailableProperties();
    setSuggestions(availableProperties);
    
    // Fetch labels for properties that don't have labels yet
    const unlabeledProperties = availableProperties
      .filter(prop => !propertyLabels[prop.id] || propertyLabels[prop.id] === prop.id)
      .map(prop => prop.id);
    
    if (unlabeledProperties.length > 0) {
      setIsLoading(true);
      onFetchPropertyLabels(unlabeledProperties)
        .finally(() => setIsLoading(false));
    }
  }, [propertyCache, propertyLabels, aggregateAvailableProperties, onFetchPropertyLabels]);

  // Filter suggestions based on input
  const filteredSuggestions = suggestions.filter(suggestion =>
    suggestion.label.toLowerCase().includes(inputValue.toLowerCase()) ||
    suggestion.id.toLowerCase().includes(inputValue.toLowerCase())
  );

  // Handle input changes
  const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value;
    setInputValue(value);
    setShowSuggestions(value.trim().length > 0);
    setSelectedIndex(-1);
  }, []);

  // Handle keyboard navigation
  const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
    if (!showSuggestions || filteredSuggestions.length === 0) {
      if (e.key === 'Enter') {
        e.preventDefault();
        // Try to add property directly if it looks like a property ID
        if (inputValue.trim()) {
          onAddProperty(inputValue.trim());
          setInputValue('');
          setShowSuggestions(false);
        }
      }
      return;
    }

    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        setSelectedIndex(prev => 
          prev < filteredSuggestions.length - 1 ? prev + 1 : 0
        );
        break;
        
      case 'ArrowUp':
        e.preventDefault();
        setSelectedIndex(prev => 
          prev > 0 ? prev - 1 : filteredSuggestions.length - 1
        );
        break;
        
      case 'Enter':
        e.preventDefault();
        if (selectedIndex >= 0 && selectedIndex < filteredSuggestions.length) {
          const selectedProperty = filteredSuggestions[selectedIndex];
          handlePropertySelect(selectedProperty);
        } else if (inputValue.trim()) {
          // Add property directly
          onAddProperty(inputValue.trim());
          setInputValue('');
          setShowSuggestions(false);
        }
        break;
        
      case 'Escape':
        e.preventDefault();
        setShowSuggestions(false);
        setSelectedIndex(-1);
        inputRef.current?.blur();
        break;
        
      case 'Tab':
        setShowSuggestions(false);
        setSelectedIndex(-1);
        break;
    }
  }, [showSuggestions, filteredSuggestions, selectedIndex, inputValue, onAddProperty]);

  // Handle property selection
  const handlePropertySelect = useCallback((property: PropertySuggestion) => {
    console.log('Property selected:', property);
    onAddProperty(property.id);
    setInputValue('');
    setShowSuggestions(false);
    setSelectedIndex(-1);
    inputRef.current?.focus();
  }, [onAddProperty]);

  // Handle focus
  const handleFocus = useCallback(() => {
      // Show all suggestions immediately on focus
      setShowSuggestions(true);
  }, []);

  // Handle blur
  const handleBlur = useCallback((e: React.FocusEvent<HTMLInputElement>) => {
    // Delay hiding suggestions to allow for clicks on suggestions
    setTimeout(() => {
      const relatedTarget = e.relatedTarget as HTMLElement;
      if (!suggestionsRef.current?.contains(relatedTarget)) {
        setShowSuggestions(false);
        setSelectedIndex(-1);
      }
    }, 150);
  }, []);

  // Handle suggestion click
  const handleSuggestionClick = useCallback((property: PropertySuggestion) => {
    handlePropertySelect(property);
  }, [handlePropertySelect]);

  // Handle clicking outside to close suggestions
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      const target = event.target as HTMLElement;
      if (
        inputRef.current && 
        !inputRef.current.contains(target) &&
        suggestionsRef.current &&
        !suggestionsRef.current.contains(target)
      ) {
        setShowSuggestions(false);
        setSelectedIndex(-1);
      }
    };

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

  return (
    <div className={`relative ${className}`}>
      <input
        ref={inputRef}
        type="text"
        value={inputValue}
        onChange={handleInputChange}
        onKeyDown={handleKeyDown}
        onFocus={handleFocus}
        onBlur={handleBlur}
        placeholder="Add New Property"
        className="px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors duration-200 text-sm"
        autoComplete="off"
      />
      
      {/* Loading indicator */}
      {isLoading && (
        <div className="absolute right-2 top-1/2 transform -translate-y-1/2">
          <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-500"></div>
        </div>
      )}
      
      {/* Suggestions dropdown */}
      {showSuggestions && filteredSuggestions.length > 0 && (
        <div
          ref={suggestionsRef}
          className="absolute z-50 w-full mt-2 bg-white border border-gray-200 rounded-lg shadow-xl max-h-80 overflow-y-auto"
          style={{
            boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)'
          }}
        >
          <div className="py-2">
            {filteredSuggestions.map((suggestion, index) => {
              const isSelected = index === selectedIndex;
              
              return (
                <div
                  key={suggestion.id}
                  className={`
                    px-4 py-3 cursor-pointer transition-colors duration-150 ease-in-out
                    ${isSelected 
                      ? 'bg-blue-50 text-blue-900 border-l-4 border-blue-500' 
                      : 'hover:bg-gray-50 border-l-4 border-transparent'
                    }
                  `}
                  onClick={() => handleSuggestionClick(suggestion)}
                  onMouseEnter={() => setSelectedIndex(index)}
                >
                  <div className="flex items-center justify-between">
                    <div className="flex-1 min-w-0">
                      <div className="font-medium text-sm text-gray-900 truncate">
                        {suggestion.label}
                      </div>
                      <div className="text-xs text-gray-500 mt-1">
                        ID: {suggestion.id}
                      </div>
                      <div className="text-xs text-blue-600 mt-1 font-medium">
                        Available in {suggestion.availableInItems.length} item{suggestion.availableInItems.length !== 1 ? 's' : ''}
                      </div>
                    </div>
                    <div className="ml-3 flex-shrink-0">
                      <svg 
                        className={`w-4 h-4 transition-colors duration-150 ${isSelected ? 'text-blue-500' : 'text-gray-400'}`}
                        fill="none" 
                        stroke="currentColor" 
                        viewBox="0 0 24 24"
                      >
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
                      </svg>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}
      
      {/* No suggestions message */}
      {showSuggestions && inputValue.trim().length > 0 && filteredSuggestions.length === 0 && (
        <div className="absolute z-50 w-full mt-2 bg-white border border-gray-200 rounded-lg shadow-xl p-4">
          <div className="text-sm text-gray-600 text-center">
            {`No matching properties found. Press Enter to add "${inputValue}" as a custom property.`}
          </div>
        </div>
      )}
    </div>
  );
}