import { Component, OnInit, OnDestroy, Inject, Optional, ViewEncapsulation, RendererFactory2, PLATFORM_ID, ChangeDetectionStrategy, HostListener, Input, DOCUMENT } from '@angular/core';
import { Router, NavigationStart, NavigationEnd, RouteConfigLoadStart, RouteConfigLoadEnd, ActivatedRoute, PRIMARY_OUTLET } from '@angular/router';
import { Meta, Title, MetaDefinition } from '@angular/platform-browser'; 
import { Subscription, Observable } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
import { Store, Action } from '@ngrx/store';
import { IUser } from '../../models/user';
import { OAuthService, OAuthErrorEvent } from 'angular-oauth2-oidc';
import { FM_COMMON_STARTPAGE } from '../../common.module';

//AppCommon
import { IEventMessage } from '../../models/event.message';
import { IListItem } from '../../models/list.item';
import { EventService } from '../../services/event.service';
import { ItemTypeService } from '../../services/itemtype.service';
import * as  commonActions from '../../actions/app-common.actions';
import { HealthCheckService } from '../../services/healthcheck.service';
import { AppConfig } from '../../shared/app.config';

import * as appReducers from '../../reducers/app-common.reducer';

@Component({
    selector: 'fm-app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss'],
    encapsulation: ViewEncapsulation.None,
    changeDetection: ChangeDetectionStrategy.OnPush,
    standalone: false
})
export class AppComponent implements OnInit, OnDestroy {

  // This will go at the END of your title for example "Home - Angular Universal..." <-- after the dash (-)
  private endPageTitle = 'Farmmaps';
  // If no Title is provided, we'll use a default one before the dash(-)
  private defaultPageTitle = 'Farmmaps';

  private routerSub$: Subscription;
  private eventSub$: Subscription;

  public currentFolder: Observable<IListItem>;
  public folderParents: Observable<IListItem[]>;
  public fullScreen: Observable<boolean> = this.store$.select(appReducers.selectGetFullScreen);
  public isOnline: Observable<boolean> = this.store$.select(appReducers.SelectGetIsOnline);
  public routeLoading: Observable<boolean> = this.store$.select(appReducers.selectGetRouteLoading);
  public menuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetMenuVisible);
  public accountMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAccountMenuVisible);
  public appMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAppMenuVisible);
  public notificationMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetNotificationMenuVisible);
  public settingMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetSettingMenuVisible);
  public helpMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetHelpMenuVisible);
  public unreadNotifications: Observable<number> = this.store$.select(appReducers.SelectgetUnreadNotifications);
  public user: Observable<IUser> = this.store$.select(appReducers.SelectGetUser);
  public isPageMode: Observable<boolean> = this.store$.select(appReducers.SelectGetIsPageMode);
  public settingMenuBackgroundColor: Observable<string> = this.store$.select(appReducers.SelectGetSettingMenuBackgroundColor);
  @Input() showUploadProgress = true;

  constructor(
    @Optional() @Inject(FM_COMMON_STARTPAGE) public startPage: string,
    public router: Router,
    private activatedRoute$: ActivatedRoute,
    private title$: Title,
    private meta$: Meta,
    private store$: Store<appReducers.State>,
    private eventService$: EventService,
    private healthCheckService$: HealthCheckService,
    private itemTypeService$: ItemTypeService,
    private oauthService$: OAuthService,
    private appConfig$: AppConfig
  ) {
  }


  getActionFromEvent(event: IEventMessage): Action {
    let action: Action = null;
    //console.debug(`${event.eventType} Event received`);
    switch (event.eventType) {
      case "ItemChanged": {
        action = new commonActions.ItemChangedEvent(event.itemCode, event.attributes);
        break;
      }
      case "ItemAdded": {
        action = new commonActions.ItemAddedEvent(event.itemCode, event.attributes);
        break;
      }
      case "ItemDeleted": {
        action = new commonActions.ItemDeletedEvent(event.itemCode, event.attributes);
        break;
      }
      case "taskStart": {
        action = new commonActions.TaskStartEvent(event.itemCode, event.attributes);
        break;
      }
      case "taskEnd": {
        action = new commonActions.TaskEndEvent(event.itemCode, event.attributes);
        break;
      }
      case "taskError": {
        action = new commonActions.TaskErrorEvent(event.itemCode, event.attributes);
        break;
      }
      case "taskProgress": {
        action = new commonActions.TaskProgressEvent(event.itemCode, event.attributes);
        break;
      }
      case "deviceUpdate": {
        action = new commonActions.DeviceUpdateEvent(event.itemCode, event.attributes);
        break;
      }
      case "notification": {
        action = new commonActions.NotificationEvent(event.attributes);
        break;
      }
      case "DeleteUser": {
        action = new commonActions.Logout();
        break;
      }
    }
    return action;
  }

  ngOnInit() {
    this.InstallRouteEventHandler();
    this.InstallEventServiceEventHandler();
    this.InstallAuthenticationEventHandler();
    this.InstallHealthCheck();
  }

  @HostListener('document:keyup', ['$event'])
  onKeyUp(event: KeyboardEvent) {
    const x = event.keyCode;
    if (x === 27) {
      this.store$.dispatch(new commonActions.Escape(true, false));
    }
  }

  ngOnDestroy() {
    // Subscription clean-up
    if (this.routerSub$) this.routerSub$.unsubscribe();
    if (this.eventSub$) this.eventSub$.unsubscribe();
  }

  private InstallAuthenticationEventHandler() {
    // auth event handler
    this.oauthService$.events.subscribe((event) => {
      //console.debug(event.type);
      if (event.type == 'token_error' || event.type == 'silent_refresh_timeout' || event.type == 'logout') {
        const e = event as OAuthErrorEvent;
        const p = e.params as any;
        if (event.type == 'silent_refresh_timeout' || event.type == 'logout' || (p.error && p.error == 'login_required')) {
          //console.debug("Session expired");
          this.router.navigate(['loggedout'], { queryParams: { redirectTo: this.router.url } });
        }
      }
      if (event.type == 'token_received') {
        this.oauthService$.loadUserProfile();
        this.store$.dispatch(new commonActions.InitUser());
      }
    });
    if (this.oauthService$.hasValidAccessToken()) {
      this.store$.dispatch(new commonActions.InitUser());
    } else {
      if (this.oauthService$.getRefreshToken() != null) {
        this.oauthService$.refreshToken();
      }
    }
  }

  private InstallRouteEventHandler() {
    const other = this;
    this.routerSub$ = this.router.events.subscribe(event => {
      if (event instanceof RouteConfigLoadStart) {
        other.store$.dispatch(new commonActions.StartRouteLoading());
      }
      if (event instanceof NavigationEnd && (event.url == "/" || event.url.startsWith("/content"))) {
        other.store$.dispatch(new commonActions.SetPageMode(true));
      } else if (event instanceof NavigationEnd) {
        other.store$.dispatch(new commonActions.SetPageMode(false));
      }
      if (event instanceof RouteConfigLoadEnd) {
        other.store$.dispatch(new commonActions.EndRouteLoading());
      }
      if (event instanceof NavigationStart) {
        other.store$.dispatch(new commonActions.SetMenuVisible(false));
      }
    });
  }

  private InstallEventServiceEventHandler() {
    const other = this;
    this.eventSub$ = this.eventService$.event.subscribe(event => {
      const action = other.getActionFromEvent(event);
      if (action) other.store$.dispatch(action);
    });
  }

  private InstallHealthCheck() {
    //check health every 30 seconds
    this.healthCheckService$.check(30000).pipe(distinctUntilChanged()).subscribe((online) => {
      if (online) {
        this.store$.dispatch(new commonActions.Online());
      } else {
        this.store$.dispatch(new commonActions.Offline());
      }
    });
  }

  handleClick(event: MouseEvent) {
    this.store$.dispatch(new commonActions.Escape(false, true));
  }

  handleStopBubble(event: MouseEvent) {
    event.stopPropagation();
  }

  handleToggleMenu(event: MouseEvent) {
    event.stopPropagation();
    this.store$.dispatch(new commonActions.ToggleMenu());
  }

  handleHome(event: MouseEvent) {
    this.router.navigate(['/']);
  }
}

