import {
  Component,
  AfterViewInit,
  ChangeDetectionStrategy,
  Input,
  ViewChildren,
  QueryList,
  HostListener,
  Output,
  EventEmitter,
} from '@angular/core';
import { AutocompleteDTO } from '@swagger/oms';
import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
import { ResultItemComponent } from './result-item';
import { AutocompleteOptions } from '../../defs';

@Component({
  selector: 'app-autocomplete-results',
  templateUrl: 'autocomplete-results.component.html',
  styleUrls: ['./autocomplete-results.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AutocompleteResultsComponent implements AfterViewInit {
  @ViewChildren(ResultItemComponent) items: QueryList<ResultItemComponent>;

  @Input() results: AutocompleteDTO[];
  @Output() selectItem = new EventEmitter<AutocompleteDTO & AutocompleteOptions>();

  private keyManager: ActiveDescendantKeyManager<ResultItemComponent>;

  constructor() {}

  @HostListener('window:keyup', ['$event']) onKeyDown(event: KeyboardEvent) {
    if (this.isUpOrDownKey(event.key)) {
      this.keyManager.onKeydown(event);
      if (this.keyManager.activeItem) {
        this.selectItem.emit(this.keyManager.activeItem.result);
      }
    }

    if (this.shouldDeselectItem(event.key)) {
      this.keyManager.setActiveItem(null);
    }
  }

  ngAfterViewInit() {
    this.keyManager = new ActiveDescendantKeyManager(this.items).withWrap();
  }

  onItemClicked(item: AutocompleteDTO) {
    this.keyManager.setActiveItem(this.getItemIndex(item));
    this.selectItem.emit({
      ...this.keyManager.activeItem.result,
      shouldNavigate: false,
      shouldUpdateAutocomplete: false,
    });
  }

  private getItemIndex(item: AutocompleteDTO): number {
    return this.results.indexOf(item);
  }

  private shouldDeselectItem(key: string): boolean {
    const isBackspace = key === 'Backspace';
    const isLetter = key.length === 1 && /^[a-zA-Z]+$/.test(key);
    const isNumber = key.length === 1 && /^[0-9]+$/.test(key);

    return isBackspace || isLetter || isNumber;
  }

  private isUpOrDownKey(key: string): boolean {
    return key === 'ArrowDown' || key === 'ArrowUp';
  }
}
