import {
  Component,
  ChangeDetectionStrategy,
  ContentChildren,
  QueryList,
  AfterContentInit,
  ChangeDetectorRef,
  HostListener,
} from '@angular/core';
import { UiSearchboxAutocompleteOptionDirective } from './ui-searchbox-autocomplete-option.directive';

@Component({
  selector: 'ui-searchbox-autocomplete',
  templateUrl: 'ui-searchbox-autocomplete.component.html',
  styleUrls: ['ui-searchbox-autocomplete.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UiSearchboxAutocompleteComponent implements AfterContentInit {
  public show = false;

  @ContentChildren(UiSearchboxAutocompleteOptionDirective, {
    read: UiSearchboxAutocompleteOptionDirective,
  })
  options: QueryList<UiSearchboxAutocompleteOptionDirective>;

  onSelect = (value: string) => {};

  showChanged = (value: boolean) => {};

  constructor(private cdr: ChangeDetectorRef) {}

  ngAfterContentInit(): void {
    this.registerOptionOnSelect();
    this.options.changes.subscribe((_) => {
      this.registerOptionOnSelect();
    });
  }

  registerOptionOnSelect() {
    this.options.forEach((option) => option.registerOnSelect((value) => this.selectValue(value)));
  }

  registerOnSelect(fn: any) {
    this.onSelect = fn;
  }

  registerOnShowChanged(fn: any) {
    this.showChanged = fn;
  }

  toggle() {
    this.show = !this.show;
    this.showChanged(this.show);
    this.cdr.markForCheck();
  }

  open() {
    this.show = true;
    this.showChanged(this.show);
    this.cdr.markForCheck();
  }

  close() {
    this.show = false;
    this.showChanged(this.show);
    this.cdr.markForCheck();
  }

  selectValue(value: string) {
    this.onSelect(value);
  }

  @HostListener('window:keydown', ['$event'])
  onKeydown(event: KeyboardEvent) {
    if (!this.show) {
      return;
    }

    const currentIndex = this.getSelectedIndex();

    let nextIndex: number;

    if (event.key === 'ArrowDown' && currentIndex === -1) {
      nextIndex = 0;
    } else if (event.key === 'ArrowDown' && this.options.length > currentIndex + 1) {
      nextIndex = currentIndex + 1;
    } else if (event.key === 'ArrowUp' && currentIndex > 0) {
      nextIndex = currentIndex - 1;
    }

    if (nextIndex !== undefined) {
      event.preventDefault();
      this.selectOptionAt(nextIndex);
    }
  }

  getSelectedIndex() {
    return this.options.toArray().findIndex((option) => option.selected);
  }

  selectOptionAt(index: number) {
    this.unselectOptions();
    const option = this.options.find((o, i) => i === index);
    if (option) {
      option.selected = true;
      option.select();
    }
  }

  unselectOptions() {
    this.options.forEach((option) => (option.selected = false));
  }
}
