import { animate, keyframes, query, stagger, state, style, transition, trigger } from '@angular/animations';
import { AfterViewInit, ChangeDetectorRef, Component, HostListener, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { MatSelectionList } from '@angular/material/list';
import { MatTabChangeEvent } from '@angular/material/tabs';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { opacityAnimation , slideAnimation} from '../../../animations';
import { ApplicationService } from '../../../application.service';
import { Category } from '../../../models';
import { Application } from '../../../models/application/application.interface';
import { TenantSelectionService } from '../../../tenant-selection.service';
import { MenuOption } from '../../navbar';
import { SearchBarComponent } from '../../search-bar';
import { Tenant } from './../../../models/customer/tenant.interface';
import { StartupService } from './../../../startup.service';
import { MenuOverlayRef } from './menu-overlay-ref';

@Component({
  selector: 'vitamui-common-menu',
  templateUrl: './menu.component.html',
  styleUrls: ['./menu.component.scss'],
  animations: [
    opacityAnimation,
    slideAnimation,
  ]
})
export class MenuComponent implements OnInit, AfterViewInit {

  public state = '';
  public appMap: Map<Category, Application[]>;
  public filteredApplications: Application[] = null;
  public criteria: string;
  public tabSelectedIndex = 0;
  public selectedCategory: Category;
  public selectedTenant: MenuOption;
  public tenants: MenuOption[];

  private firstResult: any;
  private firstResultFocused = false;
  private destroyer$ = new Subject();

  @ViewChild('searchBar', { static: true }) searchBar: SearchBarComponent;
  @ViewChildren(MatSelectionList) selectedList: QueryList<MatSelectionList>;
  @HostListener('document:keydown', ['$event'])
  handleKeyboardEvent(event: KeyboardEvent) {
      if (event.key === 'ArrowRight') {
        if (this.tabSelectedIndex < this.selectedList.length - 1) {
          this.tabSelectedIndex++;
        }
      } else if (event.key === 'ArrowLeft') {
        if (this.tabSelectedIndex > 0) {
          this.tabSelectedIndex--;
        }
      } else if (event.key === 'ArrowDown') {
        if (this.firstResult && !this.firstResultFocused) {
          this.firstResult.focus();
          this.firstResultFocused = true;
        }
      }
  }

  constructor(
    private dialogRef: MenuOverlayRef,
    private applicationService: ApplicationService,
    private cdrRef: ChangeDetectorRef,
    private router: Router,
    private tenantService: TenantSelectionService,
    private startupService: StartupService) { }

  ngOnInit() {
    this.dialogRef.overlay.backdropClick().subscribe(() => this.onClose());
    this.tenants = this.tenantService.getTenants().map((tenant: Tenant) => {
      return {value: tenant, label: tenant.name};
    });

    // Display application list depending on the current active tenant.
    // If no active tenant is set, then use the last tenant identifier.
    this.selectedTenant = {value: this.tenantService.getSelectedTenant(), label: this.tenantService.getSelectedTenant().name};
    if (this.selectedTenant) {
      this.updateApps(this.selectedTenant);
    } else {
      this.tenantService.getLastTenantIdentifier$().pipe(takeUntil(this.destroyer$)).subscribe((identifier: number) => {
        this.updateApps(this.tenants.find(option => option.value.identifier === identifier));
      });
    }
  }

  ngAfterViewInit(): void {
    this.searchBar.onFocus();
  }

  public onSearch(value: string): void {
    if (value) {
      this.criteria = value;
      this.firstResultFocused = false;
      const flattenApps: Application[] = Array.from(new Set([].concat.apply([], Array.from(this.appMap.values()))));

      this.filteredApplications = flattenApps.filter((application: Application) => {
        return application.name.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase()
          .includes(value.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase());
      });
      this.cdrRef.detectChanges();

      if (this.filteredApplications.length > 0) {
        this.firstResult = document.getElementById('searchResults').firstElementChild as any;
      }
    } else {
      this.resetSearch();
    }
  }

  public resetSearch(): void {
    this.filteredApplications = null;
    this.criteria = '';
    this.searchBar.onFocus();
  }

  public onClose(): void {
    this.state = 'close';
    setTimeout(() => this.dialogRef.close(), 500);
  }

  public changeTabFocus(value?: MatTabChangeEvent): void {
    if (value && value.index !== this.tabSelectedIndex) {
      this.tabSelectedIndex = value.index; // when clicking
    }
    setTimeout(() => {
      // tslint:disable-next-line: variable-name
      const firstElem = this.selectedList.find((_select, index) => index === this.tabSelectedIndex);
      if (firstElem && firstElem.options && firstElem.options.first) {
        firstElem.options.first.focus();
      }
    }, 300);
  }

  public openApplication(app: Application) {
    this.onClose();
    this.applicationService.
      openApplication(app, this.router, this.startupService.getConfigStringValue('UI_URL'), this.selectedTenant.value.identifier);
  }

  public updateApps(tenant: MenuOption) {
    if (tenant) {
      this.selectedTenant = tenant;
      this.appMap = this.applicationService.getTenantAppMap(tenant.value);
    }
  }
}