import { AfterViewInit, Component, ElementRef, EventEmitter, HostListener, OnDestroy, OnInit, Output, Renderer2, ViewChild } from '@angular/core';
import { ActivatedRoute, Event, NavigationStart, Router, ResolveEnd } from '@angular/router';

import { TranslateDirective, TranslateService } from '@ngx-translate/core';

import { Subscription } from 'rxjs/Subscription';

import { HeaderService, IMenuItem, MenuItem, IUserAccounts, LoaderService, RouterExtService, TokenService, UserService, IKnokOngoingDataList } from '../../shared';
// import { Element } from '@angular/compiler';

import * as MDC from 'material-components-web';
import { MediaChange, MediaMonitor, ObservableMedia } from '@angular/flex-layout';

import { trigger, style, transition, animate, keyframes, query, stagger, state } from '@angular/animations';
import { AnimationTriggerMetadata } from '@angular/animations/src/animation_metadata';
import 'web-animations-js';
import { Subject } from 'rxjs/Subject';
import { IUser } from '../../shared/user';
import { Observable } from 'rxjs/Observable';
import { has as _has } from 'lodash/object';

function fade(): AnimationTriggerMetadata {
  return trigger('fade', [
    state('false', style({opacity: 0.0})),
    state('true', style({opacity: 1.0})),
    transition('void => true, * => true, false => true', [
      style({opacity: 0.0}),
      animate('250ms ease-in-out', style({opacity: 1.0}))
    ]),
    transition('void => false, * => false, true => false, * => void', [
      style({opacity: 1.0}),
      animate('250ms ease-in-out', style({opacity: 0.0}))
    ])
  ]);
}

@Component({
  selector: 'knk-header',
  styleUrls: ['./header.component.scss'],
  templateUrl: './header.component.html',
  animations: [fade()]
})
export class HeaderComponent implements OnDestroy, OnInit {
  @Output() sidePanelAction: EventEmitter<boolean> = new EventEmitter<boolean>();
  @Output() modeToggled: EventEmitter<boolean> = new EventEmitter<boolean>(true);
  @ViewChild('accountMenu') accountMenu: ElementRef;
  @ViewChild('accountMenuToggle') accountMenuToggle: ElementRef;

  lang: string;
  menuItems: IMenuItem[] = [];
  menuPublishedItems: IMenuItem[] = [];
  completeMenu: IMenuItem[] = [];
  completePublishedMenu: IMenuItem[] = [];
  userAccounts: IUserAccounts;
  modeToggledState: boolean = true;
  uniqueId: number;

  private ngUnsubscribe: Subject<void> = new Subject<void>();
  private loaderSubscription: Subscription;
  private pollSubscription: Subscription;

  constructor(private headerService: HeaderService,
              private tokenService: TokenService,
              private userService: UserService,
              private loaderService: LoaderService,
              private router: Router,
              private route: ActivatedRoute,
              private routerExt: RouterExtService,
              private translateService: TranslateService,
              private renderer: Renderer2,
              public media: ObservableMedia,
              public monitor: MediaMonitor) {
    this.loaderSubscription = this.loaderService.subscribeLoader(this);
  }

  ngOnInit(): void {
    this.uniqueId = Date.now();
    this.lang = this.translateService.currentLang || this.translateService.defaultLang;
    this.router.events
      .filter((e: Event) => e instanceof ResolveEnd)
      .takeUntil(this.ngUnsubscribe)
      .subscribe(() => {
        this.lang = this.translateService.currentLang || this.translateService.defaultLang;
        this.checkMenu();
      });

    this.menuItems = this.headerService.getMenu();
    this.menuPublishedItems = this.headerService.getPublishedMenu();

    this.media
      .asObservable()
      .takeUntil(this.ngUnsubscribe)
      .subscribe((change: MediaChange): void => {
        this.makeMenu();
        // console.warn(change);
      });

    this.userService.userChanged
      .takeUntil(this.ngUnsubscribe)
      .subscribe((user: IUser): void => {
        this.uniqueId = Date.now();
        // todo: refresh user and tokens
        if (this.userAccounts !== null) {
          this.userAccounts.user = user;

          if (_has(this.userService.userAccounts, ['accounts', 0, 'currentBalance'])) {
            this.userAccounts.accounts[0].currentBalance = this.userService.userAccounts.accounts[0].currentBalance;
          }
        }
        this.makeMenu();
        // console.warn(user);
      });

    this.tokenService.authorizationChanged
      .takeUntil(this.ngUnsubscribe)
      .subscribe(isLogin => {
        this.userService.loadUser()
          .take(1)
          .subscribe(userAccounts => {
            this.userAccounts = userAccounts;
            this.pollUser();
            this.makeMenu();
          }, error => {
            this.userAccounts = null;
            this.makeMenu();
          });
      });

    if (this.tokenService.isLogin) {
      this.userService.loadUser()
        .take(1)
        .subscribe(userAccounts => {
          this.userAccounts = userAccounts;
          this.makeMenu();
        });
    }

    if (this.loaderSubscription) {
      this.loaderSubscription.unsubscribe();
    }

    this.loaderService.loaderComplete
      .takeUntil(this.ngUnsubscribe)
      .subscribe((isLoaded: boolean) => {
        if (isLoaded) {
          this.checkMenu();
        }
      });

    this.pollUser();
  }

  ngOnDestroy(): void {
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();

    if (this.loaderSubscription) {
      this.loaderSubscription.unsubscribe();
    }
  }

  pollUser(): void {
    // todo: refresh user and tokens
    if (this.pollSubscription) {
      this.pollSubscription.unsubscribe();
    }

    let fetch$: Observable<IUserAccounts> = this.userService.loadUser();
    let timer$: Observable<number> = Observable.timer(10, 15000);
    let poll$: Observable<any> = timer$.exhaustMap(() => fetch$);
    this.pollSubscription = poll$
      .takeUntil(this.ngUnsubscribe)
      .subscribe(userAccounts => {
        this.userAccounts = userAccounts;
        this.makeMenu();
      });
  }

  makeMenu(): void {
    this.completeMenu = Object.assign([], this.menuItems);
    this.completePublishedMenu = [];
    if (this.userService.userIsKnokser) {
      if (this.media.isActive('lt-lg')) {
        this.completeMenu.push(new MenuItem({name: 'More', translateKey: 'More', rout: 'published', isActive: false, isVisible: true, disabled: false, subMenu: this.menuPublishedItems}));
      } else {
        this.completePublishedMenu.push(new MenuItem({name: 'Published Knoks', translateKey: 'Published Knoks', rout: 'published', isActive: false, isVisible: true, disabled: false, subMenu: this.menuPublishedItems}));
      }
    }
    this.checkMenu();
  }

  checkMenu(): void {
    const timeout: any = setTimeout((): void => {
      this.completeMenu.forEach((value: IMenuItem) => {
        value.isActive = this.router.routerState.snapshot.url.indexOf(value.rout) !== -1;
      });
      this.completePublishedMenu.forEach((value: IMenuItem) => {
        value.isActive = this.router.routerState.snapshot.url.indexOf(value.rout) !== -1;
      });
      clearTimeout(timeout);
    }, 10);
  }

  modeToggle(state: boolean): void {
    this.modeToggledState = state;
    this.modeToggled.emit(state);
  }

  setSettingMenu(event: CustomEvent): void {
    const target: HTMLElement | null = event.target as HTMLElement | null;
    const menu: any = event.detail.component;
    menu.setAnchorCorner(MDC.menu.MDCMenuFoundation.Corner.BOTTOM_START);
    menu.setAnchorMargin({top: 8, bottom: 8, left: 0, right: 0});
    menu.rememberSelection = false;
    menu.quickOpen = false;
  }

  accountMenuSelectedHandler(event: CustomEvent): void {
    let detail: any = event.detail;
    let menu: any = this.accountMenu.nativeElement.MDCMenu;
    let toggle: any = this.accountMenuToggle.nativeElement.MDCIconToggle;
    toggle.on = !!menu.open;
    // console.log(detail);
  }

  accountMenuCancelHandler(event: CustomEvent): void {
    let menu: any = this.accountMenu.nativeElement.MDCMenu;
    let toggle: any = this.accountMenuToggle.nativeElement.MDCIconToggle;
    toggle.on = !menu.open;
  }

  accountMenuToggleHandler(event: CustomEvent): void {
    let menu: any = this.accountMenu.nativeElement.MDCMenu;
    let toggle: any = this.accountMenuToggle.nativeElement.MDCIconToggle;
    menu.open = !menu.open;
    toggle.on = !!menu.open;
  }

  openSideNav(): void {
    this.sidePanelAction.emit();
  }

  get isLogin(): boolean {
    return this.tokenService.isLogin;
  }

  // todo: remove
  get selectedIndex(): number {
    let res: number = 0;
    this.menuItems.forEach((item, i) => {
      if (item.isActive) {
        res = i;
        return false;
      }
    });
    return res;
  }

  get userName(): string {
    if (this.userAccounts && this.userAccounts.user) {
      return this.userAccounts.user.firstName + ' ' + this.userAccounts.user.lastName;
    }
    return '';
  }

  get avatarHref(): string {
    return `${SETTINGS.API_URL}${this.userAccounts.user.avatarUrl}?${this.uniqueId}`;
  }

  get balance(): number {
    if (this.userAccounts && this.userAccounts.accounts && this.userAccounts.accounts.length > 0) {
      return this.userAccounts.accounts[0].currentBalance;
    } else {
      return 0;
    }
  }

  doSearch(query: string): void {
    if (typeof query === 'string') {
      if (query.length > 2) {
        console.log('do search...');
      }
    }
  }

  public logout(): void {
    this.routerExt.goToHome();
    this.tokenService.releaseToken();
  }
}
