/**
 * QuickAddPopup - Shared popup component used by QuickAddButton,
 * QuickAddConditionButton, and QuickAddEventButton.
 *
 * Provides the common popup shell: search bar, favorite sorting,
 * click-outside detection, focus trapping, and component list rendering.
 */

import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react';
import { createPortal } from 'react-dom';
import { FiSearch, FiX, FiStar } from 'react-icons/fi';
import { useStore, Component } from '../store/store';
import { useContextFilter } from '../hooks/useContextFilter';
import { t } from '../utils/translation';
import { useFocusTrap } from '../hooks/useFocusTrap';
import { useClickOutside } from '../hooks/useClickOutside';
import { THRESHOLDS } from '../constants/dimensions';
import { isComponentFavorite, sortWithFavorites, filterComponentsBySearch } from '../utils/componentUtils';
import DocumentationButton from './DocumentationButton';

export interface QuickAddPopupConfig {
  /** Title shown in the popup header */
  title: string;
  /** Placeholder for the search input */
  searchPlaceholder: string;
  /** aria-label for the search input */
  searchAriaLabel: string;
  /** Text shown when the filtered list is empty */
  emptyMessage: string;
  /** CSS class applied to the popup container (in addition to 'quick-add-popup') */
  popupClassName?: string;
  /** Popup width for position calculations */
  popupWidth?: number;
  /** Popup height for position calculations */
  popupHeight?: number;
  /** Filter function: which components from the store to show */
  componentFilter: (components: Component[]) => Component[];
  /** Render a category icon for a given component */
  renderComponentIcon: (component: Component) => React.ReactNode;
  /** Calculate popup position from button rect */
  getPopupPosition?: (buttonRect: DOMRect) => { top: number; left: number };
  /** Whether to merge unfiltered "Others" category when context is active (only for QuickAddButton) */
  mergeOthersCategory?: boolean;
}

interface QuickAddPopupProps {
  isOpen: boolean;
  onClose: () => void;
  onSelect: (component: Component) => void;
  config: QuickAddPopupConfig;
  buttonRef: React.RefObject<HTMLButtonElement | null>;
  /** Optional: category tabs configuration (only used by QuickAddButton) */
  categoryTabs?: {
    availableCategories: string[];
    selectedCategory: string | null;
    onSelectCategory: (category: string | null) => void;
    renderCategoryIcon: (category: string) => React.ReactNode;
  };
}

const QuickAddPopup: React.FC<QuickAddPopupProps> = ({
  isOpen,
  onClose,
  onSelect,
  config,
  buttonRef,
  categoryTabs,
}) => {
  const [searchTerm, setSearchTerm] = useState('');
  const popupRef = useRef<HTMLDivElement>(null);
  const searchInputRef = useRef<HTMLInputElement>(null);

  // Get components and favorites from store
  const allComponents = useStore(state => state.components);
  const favoriteComponents = useStore(state => state.favoriteComponents);
  const selectedContextId = useStore(state => state.selectedContextId);

  // Filter by active context
  const contextFilteredComponents = useContextFilter(allComponents);

  // Merge context-filtered components with unfiltered Others (only when configured)
  const components = useMemo(() => {
    if (!config.mergeOthersCategory || !selectedContextId) return contextFilteredComponents;
    if (!Array.isArray(contextFilteredComponents) || !Array.isArray(allComponents)) return contextFilteredComponents;

    const filteredPlugins = new Set(contextFilteredComponents.map(c => c.plugin));
    const othersComponents = allComponents.filter(comp => comp.category === 'Others');
    const merged = [...contextFilteredComponents];
    for (const otherComp of othersComponents) {
      if (!filteredPlugins.has(otherComp.plugin)) {
        merged.push(otherComp);
      }
    }
    return merged;
  }, [allComponents, contextFilteredComponents, selectedContextId, config.mergeOthersCategory]);

  // Apply component filter (e.g., only conditions, only events, etc.)
  const baseComponents = useMemo(() => {
    if (!Array.isArray(components)) return [];
    return config.componentFilter(components);
  }, [components, config]);

  // Compute available categories from base components (for category tabs)
  const availableCategories = useMemo(() => {
    if (!categoryTabs) return [];
    const categories = new Set<string>();
    baseComponents.forEach(comp => {
      if (comp.category) {
        categories.add(comp.category);
      }
    });
    return Array.from(categories);
  }, [baseComponents, categoryTabs]);

  // Apply category filter if tabs are active
  const categoryFilteredComponents = useMemo(() => {
    if (!categoryTabs?.selectedCategory) return baseComponents;
    return baseComponents.filter(comp => comp.category === categoryTabs.selectedCategory);
  }, [baseComponents, categoryTabs?.selectedCategory]);

  // Filter by search term and sort with favorites
  const filteredComponents = useMemo(() => {
    const searched = filterComponentsBySearch(categoryFilteredComponents, searchTerm);
    return sortWithFavorites(searched, favoriteComponents, selectedContextId);
  }, [categoryFilteredComponents, searchTerm, favoriteComponents, selectedContextId]);

  // Count of favorite components in current filtered list
  const favoriteCount = useMemo(() => {
    return filteredComponents.filter(c => isComponentFavorite(c, favoriteComponents, selectedContextId)).length;
  }, [filteredComponents, favoriteComponents, selectedContextId]);

  // Handle component selection
  const handleSelectComponent = useCallback((e: React.MouseEvent, component: Component) => {
    e.stopPropagation();
    e.preventDefault();
    onSelect(component);
  }, [onSelect]);

  // Focus trap
  useFocusTrap({
    isActive: isOpen,
    onClose,
    containerRef: popupRef,
    autoFocus: false,
  });

  // Whether to show the search field (hide when few components)
  const showSearch = baseComponents.length >= THRESHOLDS.SEARCH_VISIBILITY_MIN_COMPONENTS;

  // Focus search input when popup opens
  useEffect(() => {
    if (isOpen && showSearch && searchInputRef.current) {
      const timer = setTimeout(() => searchInputRef.current?.focus(), 50);
      return () => clearTimeout(timer);
    }
  }, [isOpen, showSearch]);

  // Reset search when popup opens/closes
  useEffect(() => {
    if (!isOpen) {
      setSearchTerm('');
    }
  }, [isOpen]);

  // Click outside detection
  const refs = useMemo(() => [popupRef, buttonRef], [buttonRef]);
  useClickOutside(isOpen, refs, onClose);

  // Calculate popup position
  const popupPosition = useMemo(() => {
    if (!buttonRef.current) return { top: 0, left: 0 };

    const buttonRect = buttonRef.current.getBoundingClientRect();

    if (config.getPopupPosition) {
      return config.getPopupPosition(buttonRect);
    }

    // Default positioning: to the right of the button
    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;
    const popupWidth = config.popupWidth || 320;
    const popupHeight = config.popupHeight || 400;

    let left = buttonRect.right + 8;
    let top = buttonRect.top;

    if (left + popupWidth > viewportWidth - 20) {
      left = buttonRect.left - popupWidth - 8;
    }
    if (top + popupHeight > viewportHeight - 20) {
      top = viewportHeight - popupHeight - 20;
    }
    if (top < 20) {
      top = 20;
    }

    return { top, left };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isOpen, config]);

  if (!isOpen) return null;

  return createPortal(
    <div
      ref={popupRef}
      className={`quick-add-popup ${config.popupClassName || ''}`}
      style={popupPosition}
      role="dialog"
      aria-modal="true"
      aria-label={config.title}
    >
      <div className="quick-add-popup-header">
        <h2>{config.title}</h2>
        <button
          className="quick-add-popup-close"
          onClick={onClose}
          title={t('Close')}
          aria-label={t('Close')}
        >
          <FiX size={16} />
        </button>
      </div>

      {showSearch && (
        <div className="quick-add-popup-search">
          <FiSearch className="search-icon" />
          <input
            ref={searchInputRef}
            type="text"
            placeholder={config.searchPlaceholder}
            aria-label={config.searchAriaLabel}
            value={searchTerm}
            onChange={(e) => setSearchTerm(e.target.value)}
          />
        </div>
      )}

      {categoryTabs && (
        <div className="quick-add-popup-categories">
          <button
            className={`category-btn ${categoryTabs.selectedCategory === null ? 'active' : ''}`}
            onClick={() => categoryTabs.onSelectCategory(null)}
          >
            {t('All')}
          </button>
          {availableCategories.map(category => (
            <button
              key={category}
              className={`category-btn ${categoryTabs.selectedCategory === category ? 'active' : ''}`}
              onClick={() => categoryTabs.onSelectCategory(category)}
            >
              {categoryTabs.renderCategoryIcon(category)}
              <span>{t(category)}</span>
            </button>
          ))}
        </div>
      )}

      <div className="quick-add-popup-components">
        {filteredComponents.length === 0 ? (
          <div className="quick-add-popup-empty">
            {config.emptyMessage}
          </div>
        ) : (
          filteredComponents.map((component, index) => {
            const isFavorite = isComponentFavorite(component, favoriteComponents, selectedContextId);
            const isLastFavorite = isFavorite &&
              (index === filteredComponents.length - 1 ||
                !isComponentFavorite(filteredComponents[index + 1], favoriteComponents, selectedContextId));

            return (
              <React.Fragment key={`${component.plugin}-${index}`}>
                <button
                  className={`quick-add-component-item ${isFavorite ? 'favorite' : ''}`}
                  onClick={(e) => handleSelectComponent(e, component)}
                  title={component.description || component.label}
                >
                  <span className="component-category-indicator" data-category={component.category}>
                    {config.renderComponentIcon(component)}
                  </span>
                  <span className="component-label">{component.label}</span>
                  {isFavorite && (
                    <span className="favorite-indicator">
                      <FiStar size={12} />
                    </span>
                  )}
                  {component.documentationUrl && (
                    <DocumentationButton
                      url={component.documentationUrl}
                      title={component.label || ''}
                      className="quick-add-documentation-btn"
                      size={12}
                    />
                  )}
                </button>
                {isLastFavorite && favoriteCount < filteredComponents.length && (
                  <div className="quick-add-divider" />
                )}
              </React.Fragment>
            );
          })
        )}
      </div>
    </div>,
    document.querySelector('.modeler') || document.body
  );
};

export default QuickAddPopup;
