// File: web/frontend/src/components/UIX/TagInput/TagInput.jsx

import React, { memo, useState, useRef, useEffect, useMemo, useCallback } from "react";
import { XMarkIcon } from "@heroicons/react/24/outline";
import { useUIXTheme } from "../themes/useUIXTheme.jsx";

// Move static default values outside component to prevent recreation
const DEFAULT_PLACEHOLDER = "Type to search and add...";
const DEFAULT_MAX_SUGGESTIONS = 5;

/**
 * TagInput Component - Performance Optimized
 * A text input that shows selected items as pill-shaped tags
 * and provides autocomplete suggestions as you type
 *
 * Performance optimizations:
 * - Component memoization with React.memo
 * - Static default values moved outside component
 * - Memoized theme classes to prevent multiple getThemeClasses calls
 * - Memoized className strings
 * - Memoized event handlers with useCallback
 * - Memoized filtered suggestions computation
 * - Memoized selected options computation
 * - Memoized inputId generation
 * - Prevented unnecessary re-renders
 *
 * Features:
 * - Type directly in the input field
 * - Autocomplete suggestions appear below as you type
 * - Selected items show as removable pill-shaped tags
 * - Click suggestions to add them
 * - Backspace to remove last tag
 * - Keyboard navigation (up/down arrows, enter to select)
 */
const TagInput = memo(function TagInput({
  id,
  label,
  options = [], // Array of {value, label} objects
  value = [], // Array of selected values
  onChange,
  placeholder = DEFAULT_PLACEHOLDER,
  error,
  disabled = false,
  required = false,
  helperText,
  className = "",
  maxSuggestions = DEFAULT_MAX_SUGGESTIONS,
}) {
  const { getThemeClasses } = useUIXTheme();
  const [inputValue, setInputValue] = useState("");
  const [showSuggestions, setShowSuggestions] = useState(false);
  const [selectedSuggestionIndex, setSelectedSuggestionIndex] = useState(-1);
  const inputRef = useRef(null);
  const containerRef = useRef(null);

  // Memoize all theme classes to prevent multiple calls on each render
  const themeClasses = useMemo(
    () => ({
      textPrimary: getThemeClasses('text-primary'),
      textDanger: getThemeClasses('text-danger'),
      textMuted: getThemeClasses('text-muted'),
    }),
    [getThemeClasses],
  );

  // Generate a unique id for the input field if none provided
  const inputId = useMemo(() => {
    return id || `tag-input-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
  }, [id]);

  // Filter options based on input value and exclude already selected
  const filteredSuggestions = useMemo(() => {
    if (!inputValue.trim()) return [];

    return options
      .filter(option =>
        !value.includes(option.value) &&
        option.label.toLowerCase().includes(inputValue.toLowerCase())
      )
      .slice(0, maxSuggestions);
  }, [options, value, inputValue, maxSuggestions]);

  // Get selected option labels for display
  const selectedOptions = useMemo(() => {
    return options.filter(option => value.includes(option.value));
  }, [options, value]);

  // Close suggestions when clicking outside
  useEffect(() => {
    const handleClickOutside = (event) => {
      if (containerRef.current && !containerRef.current.contains(event.target)) {
        setShowSuggestions(false);
        setSelectedSuggestionIndex(-1);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  // Handle input change
  const handleInputChange = useCallback((e) => {
    const newValue = e.target.value;
    setInputValue(newValue);
    setShowSuggestions(newValue.trim().length > 0);
    setSelectedSuggestionIndex(-1);
  }, []);

  // Add a tag
  const addTag = useCallback((optionValue) => {
    if (!value.includes(optionValue)) {
      onChange([...value, optionValue]);
      setInputValue("");
      setShowSuggestions(false);
      setSelectedSuggestionIndex(-1);
      inputRef.current?.focus();
    }
  }, [value, onChange]);

  // Remove a tag
  const removeTag = useCallback((optionValue) => {
    onChange(value.filter(v => v !== optionValue));
    inputRef.current?.focus();
  }, [value, onChange]);

  // Handle keyboard navigation
  const handleKeyDown = useCallback((e) => {
    if (e.key === 'ArrowDown') {
      e.preventDefault();
      setSelectedSuggestionIndex(prev =>
        prev < filteredSuggestions.length - 1 ? prev + 1 : prev
      );
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      setSelectedSuggestionIndex(prev => prev > 0 ? prev - 1 : -1);
    } else if (e.key === 'Enter') {
      e.preventDefault();
      if (selectedSuggestionIndex >= 0 && filteredSuggestions[selectedSuggestionIndex]) {
        addTag(filteredSuggestions[selectedSuggestionIndex].value);
      }
    } else if (e.key === 'Escape') {
      setShowSuggestions(false);
      setSelectedSuggestionIndex(-1);
    } else if (e.key === 'Backspace' && inputValue === '' && selectedOptions.length > 0) {
      // Remove last tag when backspace on empty input
      removeTag(selectedOptions[selectedOptions.length - 1].value);
    }
  }, [filteredSuggestions, selectedSuggestionIndex, addTag, inputValue, selectedOptions, removeTag]);

  // Memoize className strings
  const labelClassName = useMemo(() => {
    return `block text-base sm:text-lg font-semibold ${themeClasses.textPrimary} mb-3 flex items-center`;
  }, [themeClasses.textPrimary]);

  const requiredClassName = useMemo(() => {
    return `ml-1 ${themeClasses.textDanger}`;
  }, [themeClasses.textDanger]);

  const helperTextClassName = useMemo(() => {
    return `mt-2 text-sm ${themeClasses.textMuted}`;
  }, [themeClasses.textMuted]);

  const errorClassName = useMemo(() => {
    return `mt-2 text-sm ${themeClasses.textDanger} flex items-center animate-fade-in`;
  }, [themeClasses.textDanger]);

  return (
    <div className={className}>
      {label && (
        <label htmlFor={inputId} className={labelClassName}>
          {label}
          {required && <span className={requiredClassName}>*</span>}
        </label>
      )}

      <div className="relative" ref={containerRef}>
        {/* Main Input Container */}
        <div
          className={`
            w-full px-5 py-4 text-base sm:text-lg
            border-2 rounded-xl shadow-sm
            transition-all duration-200
            bg-white
            min-h-[58px]
            flex flex-wrap items-center gap-2
            ${error ? 'border-red-500' : 'border-gray-300'}
            ${disabled ? 'bg-gray-50 cursor-not-allowed opacity-60' : ''}
            focus-within:ring-4 focus-within:ring-blue-500/20 focus-within:border-blue-500
          `}
        >
          {/* Selected Tags */}
          {selectedOptions.map((option) => (
            <span
              key={option.value}
              className="inline-flex items-center gap-1 px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium"
            >
              {option.label}
              {!disabled && (
                <button
                  type="button"
                  onClick={() => removeTag(option.value)}
                  className="flex items-center justify-center w-4 h-4 rounded-full hover:bg-blue-200 transition-colors"
                >
                  <XMarkIcon className="w-3 h-3" />
                </button>
              )}
            </span>
          ))}

          {/* Input Field */}
          <input
            id={inputId}
            ref={inputRef}
            type="text"
            value={inputValue}
            onChange={handleInputChange}
            onKeyDown={handleKeyDown}
            onFocus={() => inputValue.trim() && setShowSuggestions(true)}
            placeholder={selectedOptions.length === 0 ? placeholder : ""}
            disabled={disabled}
            autoComplete="off"
            className="flex-1 min-w-[120px] bg-transparent border-none outline-none placeholder-gray-400 text-base sm:text-lg"
          />
        </div>

        {/* Autocomplete Suggestions */}
        {showSuggestions && filteredSuggestions.length > 0 && !disabled && (
          <div className="absolute z-50 w-full mt-1 bg-white border-2 border-gray-200 rounded-xl shadow-lg max-h-48 overflow-y-auto">
            {filteredSuggestions.map((option, index) => (
              <div
                key={option.value}
                onClick={() => addTag(option.value)}
                className={`
                  px-4 py-3 cursor-pointer text-sm transition-colors
                  ${index === selectedSuggestionIndex
                    ? 'bg-blue-50 text-blue-700'
                    : 'hover:bg-gray-50 text-gray-700'
                  }
                  ${index === 0 ? 'rounded-t-xl' : ''}
                  ${index === filteredSuggestions.length - 1 ? 'rounded-b-xl' : ''}
                `}
              >
                {option.label}
              </div>
            ))}
          </div>
        )}
      </div>

      {helperText && !error && (
        <p className={helperTextClassName}>
          {helperText}
        </p>
      )}
      {error && (
        <p className={errorClassName}>
          {error}
        </p>
      )}
    </div>
  );
});

// Set display name for React DevTools
TagInput.displayName = 'TagInput';

export default TagInput;