import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, forwardRef, signal, ElementRef, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
import { faSearch, faTimes, faMicrophone, faCamera, faFilter } from '@fortawesome/free-solid-svg-icons';

export type SearchBarSize = 'sm' | 'md' | 'lg';
export type SearchBarVariant = 'filled' | 'outlined' | 'elevated';
export type SearchBarState = 'default' | 'error' | 'disabled';

export interface SearchSuggestion {
  id: string;
  text: string;
  category?: string;
  icon?: IconDefinition;
}

@Component({
  selector: 'ui-search-bar',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [CommonModule, FormsModule, FontAwesomeModule],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => SearchBarComponent),
      multi: true
    }
  ],
  template: `
    <div class="search-bar-wrapper" [class]="getWrapperClasses()">
      <div class="search-bar" [class]="getSearchBarClasses()" role="combobox" [attr.aria-expanded]="showSuggestions()" [attr.aria-haspopup]="true">
        
        @if (leadingIcon) {
          <div class="search-bar__leading-icon" [class]="getLeadingIconClasses()">
            <fa-icon [icon]="leadingIcon" [attr.aria-label]="leadingIconLabel || 'Search'"></fa-icon>
          </div>
        }

        <div class="search-bar__input-wrapper" [class]="getInputWrapperClasses()">
          @if (label && size !== 'sm') {
            <label class="search-bar__label" [for]="searchId" [class.search-bar__label--floating]="hasValue() || isFocused()">
              {{ label }}
              @if (required) {
                <span class="search-bar__required-indicator">*</span>
              }
            </label>
          }
          
          <input
            #searchInput
            type="search"
            class="search-bar__input"
            [class]="getInputClasses()"
            [id]="searchId"
            [value]="searchValue()"
            [placeholder]="placeholder"
            [disabled]="disabled"
            [readonly]="readonly"
            [required]="required"
            [attr.aria-describedby]="helperText ? searchId + '-helper' : null"
            [attr.aria-invalid]="state === 'error'"
            [attr.aria-label]="ariaLabel || placeholder || 'Search'"
            [attr.aria-autocomplete]="suggestions.length > 0 ? 'list' : 'none'"
            [attr.aria-controls]="suggestions.length > 0 ? searchId + '-suggestions' : null"
            (input)="onInput($event)"
            (focus)="onFocus($event)"
            (blur)="onBlur($event)"
            (keydown)="onKeyDown($event)"
          />
        </div>

        <div class="search-bar__trailing-icons" [class]="getTrailingIconsClasses()">
          @if (searchValue() && clearable) {
            <button
              type="button"
              class="search-bar__icon-button search-bar__clear-button"
              [class]="getIconButtonClasses()"
              (click)="clearSearch()"
              [attr.aria-label]="'Clear search'"
              [disabled]="disabled"
            >
              <fa-icon [icon]="faTimes"></fa-icon>
            </button>
          }
          
          @for (icon of trailingIcons; track icon.id) {
            <button
              type="button"
              class="search-bar__icon-button"
              [class]="getIconButtonClasses()"
              (click)="onTrailingIconClick(icon)"
              [attr.aria-label]="icon.label"
              [disabled]="disabled || icon.disabled"
            >
              <fa-icon [icon]="icon.icon"></fa-icon>
            </button>
          }
        </div>
      </div>

      @if (suggestions.length > 0 && showSuggestions()) {
        <div 
          class="search-bar__suggestions" 
          [class]="getSuggestionsClasses()"
          [id]="searchId + '-suggestions'"
          role="listbox"
          [attr.aria-label]="'Search suggestions'"
        >
          @for (suggestion of suggestions; track suggestion.id; let i = $index) {
            <button
              type="button"
              class="search-bar__suggestion"
              [class]="getSuggestionClasses(i)"
              role="option"
              [attr.aria-selected]="selectedSuggestionIndex() === i"
              (click)="selectSuggestion(suggestion)"
              (mouseenter)="setSelectedSuggestionIndex(i)"
            >
              @if (suggestion.icon) {
                <fa-icon class="search-bar__suggestion-icon" [icon]="suggestion.icon"></fa-icon>
              }
              <span class="search-bar__suggestion-text">{{ suggestion.text }}</span>
              @if (suggestion.category) {
                <span class="search-bar__suggestion-category">{{ suggestion.category }}</span>
              }
            </button>
          }
        </div>
      }

      @if (helperText && state !== 'error') {
        <div class="search-bar__helper-text" [id]="searchId + '-helper'">{{ helperText }}</div>
      }

      @if (errorMessage && state === 'error') {
        <div class="search-bar__error-text" [id]="searchId + '-helper'">{{ errorMessage }}</div>
      }
    </div>
  `,
  styleUrls: ['./search-bar.component.scss']
})
export class SearchBarComponent implements ControlValueAccessor {
  @ViewChild('searchInput', { static: true }) searchInput!: ElementRef<HTMLInputElement>;

  // Core inputs
  @Input() placeholder: string = 'Search...';
  @Input() label: string = '';
  @Input() size: SearchBarSize = 'md';
  @Input() variant: SearchBarVariant = 'outlined';
  @Input() state: SearchBarState = 'default';
  
  // Icon inputs
  @Input() leadingIcon: IconDefinition = faSearch;
  @Input() leadingIconLabel: string = '';
  @Input() trailingIcons: Array<{
    id: string;
    icon: IconDefinition;
    label: string;
    disabled?: boolean;
  }> = [];
  
  // Behavior inputs
  @Input() disabled = false;
  @Input() readonly = false;
  @Input() required = false;
  @Input() clearable = true;
  @Input() autofocus = false;
  
  // Suggestions
  @Input() suggestions: SearchSuggestion[] = [];
  @Input() maxSuggestions = 10;
  
  // Accessibility
  @Input() ariaLabel: string = '';
  @Input() helperText: string = '';
  @Input() errorMessage: string = '';
  @Input() searchId: string = `search-${Math.random().toString(36).substr(2, 9)}`;

  // Outputs
  @Output() searchChange = new EventEmitter<string>();
  @Output() searchSubmit = new EventEmitter<string>();
  @Output() searchFocus = new EventEmitter<FocusEvent>();
  @Output() searchBlur = new EventEmitter<FocusEvent>();
  @Output() suggestionSelect = new EventEmitter<SearchSuggestion>();
  @Output() trailingIconClick = new EventEmitter<{id: string, icon: IconDefinition}>();

  // Font Awesome icons
  protected readonly faSearch = faSearch;
  protected readonly faTimes = faTimes;
  protected readonly faMicrophone = faMicrophone;
  protected readonly faCamera = faCamera;
  protected readonly faFilter = faFilter;

  // Internal state
  protected searchValue = signal<string>('');
  protected isFocused = signal<boolean>(false);
  protected showSuggestions = signal<boolean>(false);
  protected selectedSuggestionIndex = signal<number>(-1);

  // ControlValueAccessor implementation
  private onChange = (value: string) => {};
  private onTouched = () => {};

  ngAfterViewInit(): void {
    if (this.autofocus) {
      this.searchInput.nativeElement.focus();
    }
  }

  writeValue(value: string): void {
    this.searchValue.set(value || '');
  }

  registerOnChange(fn: (value: string) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  // Event handlers
  onInput(event: Event): void {
    const target = event.target as HTMLInputElement;
    const value = target.value;
    
    this.searchValue.set(value);
    this.onChange(value);
    this.searchChange.emit(value);
    
    // Show/hide suggestions based on input
    this.showSuggestions.set(value.length > 0 && this.suggestions.length > 0);
    this.selectedSuggestionIndex.set(-1);
  }

  onFocus(event: FocusEvent): void {
    this.isFocused.set(true);
    this.showSuggestions.set(this.searchValue().length > 0 && this.suggestions.length > 0);
    this.searchFocus.emit(event);
  }

  onBlur(event: FocusEvent): void {
    this.isFocused.set(false);
    this.onTouched();
    
    // Delay hiding suggestions to allow for suggestion clicks
    setTimeout(() => {
      this.showSuggestions.set(false);
      this.selectedSuggestionIndex.set(-1);
    }, 150);
    
    this.searchBlur.emit(event);
  }

  onKeyDown(event: KeyboardEvent): void {
    const suggestions = this.suggestions.slice(0, this.maxSuggestions);
    
    switch (event.key) {
      case 'ArrowDown':
        event.preventDefault();
        if (this.showSuggestions()) {
          const nextIndex = this.selectedSuggestionIndex() + 1;
          this.selectedSuggestionIndex.set(nextIndex >= suggestions.length ? 0 : nextIndex);
        }
        break;
        
      case 'ArrowUp':
        event.preventDefault();
        if (this.showSuggestions()) {
          const prevIndex = this.selectedSuggestionIndex() - 1;
          this.selectedSuggestionIndex.set(prevIndex < 0 ? suggestions.length - 1 : prevIndex);
        }
        break;
        
      case 'Enter':
        event.preventDefault();
        if (this.showSuggestions() && this.selectedSuggestionIndex() >= 0) {
          this.selectSuggestion(suggestions[this.selectedSuggestionIndex()]);
        } else {
          this.submitSearch();
        }
        break;
        
      case 'Escape':
        this.showSuggestions.set(false);
        this.selectedSuggestionIndex.set(-1);
        this.searchInput.nativeElement.blur();
        break;
    }
  }

  clearSearch(): void {
    this.searchValue.set('');
    this.onChange('');
    this.searchChange.emit('');
    this.showSuggestions.set(false);
    this.searchInput.nativeElement.focus();
  }

  selectSuggestion(suggestion: SearchSuggestion): void {
    this.searchValue.set(suggestion.text);
    this.onChange(suggestion.text);
    this.searchChange.emit(suggestion.text);
    this.showSuggestions.set(false);
    this.selectedSuggestionIndex.set(-1);
    this.suggestionSelect.emit(suggestion);
  }

  setSelectedSuggestionIndex(index: number): void {
    this.selectedSuggestionIndex.set(index);
  }

  submitSearch(): void {
    this.searchSubmit.emit(this.searchValue());
    this.showSuggestions.set(false);
  }

  onTrailingIconClick(iconData: {id: string, icon: IconDefinition, label: string, disabled?: boolean}): void {
    if (!iconData.disabled) {
      this.trailingIconClick.emit({id: iconData.id, icon: iconData.icon});
    }
  }

  hasValue(): boolean {
    return this.searchValue().length > 0;
  }

  // CSS class getters
  getWrapperClasses(): string {
    const classes = [
      `search-bar-wrapper--${this.size}`,
      `search-bar-wrapper--${this.variant}`,
      `search-bar-wrapper--${this.state}`
    ];

    if (this.disabled) classes.push('search-bar-wrapper--disabled');
    if (this.readonly) classes.push('search-bar-wrapper--readonly');
    if (this.isFocused()) classes.push('search-bar-wrapper--focused');
    if (this.hasValue()) classes.push('search-bar-wrapper--has-value');

    return classes.join(' ');
  }

  getSearchBarClasses(): string {
    const classes = [
      `search-bar--${this.size}`,
      `search-bar--${this.variant}`,
      `search-bar--${this.state}`
    ];

    if (this.disabled) classes.push('search-bar--disabled');
    if (this.readonly) classes.push('search-bar--readonly');
    if (this.isFocused()) classes.push('search-bar--focused');

    return classes.join(' ');
  }

  getLeadingIconClasses(): string {
    return `search-bar__leading-icon--${this.size}`;
  }

  getInputWrapperClasses(): string {
    return `search-bar__input-wrapper--${this.size}`;
  }

  getInputClasses(): string {
    const classes = [`search-bar__input--${this.size}`];
    if (this.hasValue()) classes.push('search-bar__input--has-value');
    return classes.join(' ');
  }

  getTrailingIconsClasses(): string {
    return `search-bar__trailing-icons--${this.size}`;
  }

  getIconButtonClasses(): string {
    return `search-bar__icon-button--${this.size}`;
  }

  getSuggestionsClasses(): string {
    return `search-bar__suggestions--${this.size}`;
  }

  getSuggestionClasses(index: number): string {
    const classes = [`search-bar__suggestion--${this.size}`];
    if (this.selectedSuggestionIndex() === index) {
      classes.push('search-bar__suggestion--selected');
    }
    return classes.join(' ');
  }
}