/**
 * Concept Selector component with search and autocomplete functionality.
 * Allows users to search and select XBRL concepts from a list.
 */

import React, { useState, useCallback, useRef, useEffect, useMemo } from 'react';
import { Search, ChevronDown, X } from 'lucide-react';
import type { AvailableXbrlConcept } from '../../types/financial';

interface ConceptSelectorProps {
  /** Array of available XBRL concepts to select from */
  concepts: AvailableXbrlConcept[];
  /** Currently selected concept */
  selectedConcept: AvailableXbrlConcept | null;
  /** Callback when a concept is selected */
  onSelect: (concept: AvailableXbrlConcept) => void;
  /** Placeholder text for the search input */
  placeholder?: string;
  /** Optional period ID for context */
  periodId?: string;
  /** Optional disabled state */
  disabled?: boolean;
}

interface SuggestionItem {
  concept: AvailableXbrlConcept;
  displayText: string;
  searchText: string;
  score: number;
}

export function ConceptSelector({
  concepts,
  selectedConcept,
  onSelect,
  placeholder = 'Search for an XBRL concept...',
  periodId,
  disabled = false,
}: ConceptSelectorProps) {
  const [isOpen, setIsOpen] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');
  const [highlightedIndex, setHighlightedIndex] = useState<number>(-1);
  const containerRef = useRef<HTMLDivElement>(null);
  const searchInputRef = useRef<HTMLInputElement>(null);
  const listRef = useRef<HTMLDivElement>(null);

  // Filter and score concepts based on search query
  const filteredConcepts = useMemo<SuggestionItem[]>(() => {
    if (!searchQuery.trim()) {
      // Return top concepts when no search query
      return concepts.slice(0, 20).map((concept) => ({
        concept,
        displayText: `${concept.taxonomy}:${concept.concept}`,
        searchText: `${concept.taxonomy}:${concept.concept} ${concept.label || ''}`.toLowerCase(),
        score: 0,
      }));
    }

    const query = searchQuery.toLowerCase().trim();
    const queryParts = query.split(/\s+/).filter(Boolean);

    return concepts
      .map((concept) => {
        const displayText = `${concept.taxonomy}:${concept.concept}`;
        const searchText = `${concept.taxonomy}:${concept.concept} ${concept.label || ''}`.toLowerCase();

        // Score the match
        let score = 0;

        // Exact match on full display text
        if (displayText.toLowerCase() === query) {
          score = 1000;
        }
        // Prefix match on taxonomy
        else if (concept.taxonomy.toLowerCase() === query) {
          score = 900;
        }
        // Prefix match on concept name
        else if (concept.concept.toLowerCase().startsWith(query)) {
          score = 800;
        }
        // Concept name contains query
        else if (concept.concept.toLowerCase().includes(query)) {
          score = 600;
        }
        // Label contains query
        else if (concept.label?.toLowerCase().includes(query)) {
          score = 500;
        }
        // Taxonomy contains query
        else if (concept.taxonomy.toLowerCase().includes(query)) {
          score = 400;
        }

        // Bonus for matching multiple query parts
        if (queryParts.length > 1) {
          const matchedParts = queryParts.filter(
            (part) =>
              concept.concept.toLowerCase().includes(part) ||
              concept.taxonomy.toLowerCase().includes(part) ||
              concept.label?.toLowerCase().includes(part)
          );
          score += matchedParts.length * 50;
        }

        return { concept, displayText, searchText, score };
      })
      .filter((item) => item.score > 0)
      .sort((a, b) => {
        // Sort by score (descending)
        if (b.score !== a.score) {
          return b.score - a.score;
        }
        // Then by taxonomy
        if (a.concept.taxonomy !== b.concept.taxonomy) {
          return a.concept.taxonomy.localeCompare(b.concept.taxonomy);
        }
        // Then by concept name
        return a.concept.concept.localeCompare(b.concept.concept);
      })
      .slice(0, 50); // Limit to 50 results
  }, [concepts, searchQuery]);

  // Reset highlighted index when filtered results change
  useEffect(() => {
    setHighlightedIndex(-1);
  }, [filteredConcepts]);

  // Scroll highlighted item into view
  useEffect(() => {
    if (highlightedIndex >= 0 && listRef.current) {
      const items = listRef.current.querySelectorAll('[data-index]');
      const selectedItem = items[highlightedIndex] as HTMLElement;
      if (selectedItem) {
        selectedItem.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
      }
    }
  }, [highlightedIndex]);

  const handleOpen = useCallback(() => {
    if (!disabled) {
      setIsOpen(true);
      setTimeout(() => searchInputRef.current?.focus(), 0);
    }
  }, [disabled]);

  const handleClose = useCallback(() => {
    setIsOpen(false);
    setSearchQuery('');
    setHighlightedIndex(-1);
  }, []);

  const handleSelectConcept = useCallback((concept: AvailableXbrlConcept) => {
    onSelect(concept);
    handleClose();
  }, [onSelect, handleClose]);

  const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    setSearchQuery(e.target.value);
    setHighlightedIndex(-1);
  }, []);

  const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
    if (!isOpen) return;

    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        setHighlightedIndex((prev) => {
          if (filteredConcepts.length === 0) return -1;
          return prev < filteredConcepts.length - 1 ? prev + 1 : 0;
        });
        break;

      case 'ArrowUp':
        e.preventDefault();
        setHighlightedIndex((prev) => {
          if (filteredConcepts.length === 0) return -1;
          return prev > 0 ? prev - 1 : filteredConcepts.length - 1;
        });
        break;

      case 'Enter':
        e.preventDefault();
        if (highlightedIndex >= 0 && highlightedIndex < filteredConcepts.length) {
          handleSelectConcept(filteredConcepts[highlightedIndex].concept);
        }
        break;

      case 'Escape':
        e.preventDefault();
        handleClose();
        break;

      case 'Tab':
        if (isOpen) {
          handleClose();
        }
        break;
    }
  }, [isOpen, filteredConcepts, highlightedIndex, handleSelectConcept, handleClose]);

  // Handle clicks outside the component
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
        handleClose();
      }
    };

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

  // Highlight matching text in the display string
  const highlightMatch = useCallback((text: string, query: string): React.ReactNode => {
    if (!query.trim()) {
      return text;
    }

    const regex = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
    const parts = text.split(regex);

    return parts.map((part, index) =>
      regex.test(part) ? (
        <mark key={index} className="rounded bg-info/20 text-info font-semibold">
          {part}
        </mark>
      ) : (
        part
      )
    );
  }, []);

  const selectedDisplayText = selectedConcept
    ? `${selectedConcept.taxonomy}:${selectedConcept.concept}`
    : '';

  return (
    <div ref={containerRef} className="relative">
      {/* Trigger Button */}
      <button
        type="button"
        onClick={isOpen ? handleClose : handleOpen}
        disabled={disabled}
        className={`
          flex w-full items-center justify-between gap-2 rounded-md border
          bg-term-surface px-3 py-2 text-sm text-left text-term-text
          outline-none transition-all
          ${disabled
            ? 'cursor-not-allowed opacity-50 border-term-border-subtle'
            : 'cursor-pointer border-term-border hover:border-term-border-focus'
          }
          ${isOpen ? 'border-info ring-1 ring-info/50' : ''}
        `}
        aria-haspopup="listbox"
        aria-expanded={isOpen}
        aria-labelledby="concept-selector-label"
      >
        <div className="flex flex-1 items-center gap-2 overflow-hidden">
          {selectedConcept ? (
            <span className="truncate font-mono text-sm text-term-text">
              {selectedDisplayText}
            </span>
          ) : (
            <span className="text-sm text-term-text-muted">
              {placeholder}
            </span>
          )}
        </div>
        <div className="flex items-center gap-1">
          {selectedConcept && !disabled && (
            <button
              type="button"
              onClick={(e) => {
                e.stopPropagation();
                onSelect(null as any); // Clear selection
              }}
              className="rounded p-1 text-term-text-muted hover:bg-term-bg hover:text-term-text"
              aria-label="Clear selection"
            >
              <X className="h-3 w-3" />
            </button>
          )}
          <ChevronDown
            className={`h-4 w-4 text-term-text-muted transition-transform ${
              isOpen ? 'rotate-180' : ''
            }`}
          />
        </div>
      </button>

      {/* Dropdown */}
      {isOpen && (
        <div className="absolute z-50 mt-1 w-full rounded-lg border border-term-border bg-term-elevated shadow-lg">
          {/* Search Header */}
          <div className="flex items-center gap-2 border-b border-term-border-subtle px-3 py-2">
            <Search className="h-4 w-4 text-term-text-muted flex-shrink-0" />
            <input
              ref={searchInputRef}
              type="text"
              value={searchQuery}
              onChange={handleSearchChange}
              onKeyDown={handleKeyDown}
              placeholder={placeholder}
              className="flex-1 bg-transparent text-sm text-term-text outline-none placeholder:text-term-text-tertiary"
              autoComplete="off"
              autoCapitalize="off"
              spellCheck={false}
            />
            {searchQuery && (
              <button
                type="button"
                onClick={() => {
                  setSearchQuery('');
                  searchInputRef.current?.focus();
                }}
                className="rounded p-1 text-term-text-muted hover:bg-term-bg hover:text-term-text"
                aria-label="Clear search"
              >
                <X className="h-3 w-3" />
              </button>
            )}
          </div>

          {/* Results Count */}
          <div className="flex items-center justify-between border-b border-term-border-subtle bg-term-surface px-3 py-1.5">
            <span className="text-[10px] font-mono uppercase tracking-[0.2em] text-term-text-muted">
              {filteredConcepts.length} concept{filteredConcepts.length === 1 ? '' : 's'}
            </span>
            {periodId && (
              <span className="text-[10px] font-mono text-term-text-tertiary">
                {periodId}
              </span>
            )}
          </div>

          {/* Suggestions List */}
          <div
            ref={listRef}
            className="max-h-60 overflow-y-auto"
            role="listbox"
            aria-label="Available XBRL concepts"
            aria-activedescendant={highlightedIndex >= 0 ? `concept-option-${highlightedIndex}` : undefined}
          >
            {filteredConcepts.length === 0 ? (
              <div className="px-3 py-8 text-center text-sm text-term-text-muted">
                No concepts found matching "{searchQuery}"
              </div>
            ) : (
              filteredConcepts.map((item, index) => (
                <button
                  key={`${item.concept.taxonomy}:${item.concept.concept}-${index}`}
                  type="button"
                  data-index={index}
                  id={`concept-option-${index}`}
                  onClick={() => handleSelectConcept(item.concept)}
                  onMouseEnter={() => setHighlightedIndex(index)}
                  className={`
                    flex w-full flex-col gap-1 border-b border-term-border-subtle
                    px-3 py-2.5 text-left transition-colors last:border-b-0
                    ${index === highlightedIndex
                      ? 'bg-info/10'
                      : 'hover:bg-term-surface'
                    }
                    ${selectedConcept?.taxonomy === item.concept.taxonomy &&
                        selectedConcept?.concept === item.concept.concept
                      ? 'bg-info/5'
                      : ''
                    }
                  `}
                  role="option"
                  aria-selected={selectedConcept?.taxonomy === item.concept.taxonomy &&
                                selectedConcept?.concept === item.concept.concept}
                >
                  <div className="flex items-center justify-between gap-2">
                    <span className="flex-1 truncate font-mono text-sm text-info">
                      {highlightMatch(item.displayText, searchQuery)}
                    </span>
                    {item.score > 0 && (
                      <span className="text-[10px] font-mono text-term-text-tertiary">
                        {item.score}
                      </span>
                    )}
                  </div>

                  {/* Metadata */}
                  <div className="flex items-center gap-2 text-[11px] leading-tight text-term-text-muted">
                    <span className="rounded bg-term-surface border border-term-border-subtle px-1.5 py-0.5">
                      {item.concept.taxonomy}
                    </span>
                    {item.concept.unitFamily && (
                      <span className="text-term-text-tertiary">
                        [{item.concept.unitFamily.replace(/_/g, '-')}]
                      </span>
                    )}
                    {item.concept.label && (
                      <span className="truncate">
                        {item.concept.label}
                      </span>
                    )}
                  </div>
                </button>
              ))
            )}
          </div>
        </div>
      )}
    </div>
  );
}
