import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { NcApplication, NgCortexService, NcMenu, NcPassport, NcRouteRecord } from '@ng-cortex/core';
import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { Observable, of } from 'rxjs';
import { catchError, delay, filter, map, mergeMap, take, tap } from 'rxjs/operators';
import { environment } from '../../../../../environments/environment';

/** 应用布局组件 */
@Component({
  selector: 'nc-application-layout',
  templateUrl: './nc-application-layout.component.html',
  styleUrls: ['./nc-application-layout.component.scss']
})
export class NcApplicationLayoutComponent implements OnInit, OnDestroy {

  /** 应用索引路由 */
  _routeForApplicationIndex!: string;
  /** 菜单折叠状态 */
  _menuCollapsed: boolean = false;
  /** 应用下拉显示状态 */
  _appDropdownVisible: boolean = false;
  /** 用户下拉显示状态 */
  _userDropdownVisible: boolean = false;
  /** 通行证 */
  _passport: NcPassport | null = null;
  /** 应用列表 */
  _applicationList: NcApplication[] = [];
  /** 当前应用 */
  _currentApplication: NcApplication | null = null;
  /** 菜单列表 */
  _menuList: NcMenu[] = [];
  /** 路由记录列表 */
  _routeRecordList: NcRouteRecord[] = [];
  /** 当前路由记录索引 */
  _currentRouteRecordIndex: number = 0;
  /** 未读消息下拉显示状态 */
  _unreadMessageDropdownVisible: boolean = false;
  /** 未读消息列表 */
  _unreadMessageList: any[] = [];
  /** 未读消息总数 */
  _unreadMessageTotal: number = 0;
  /** 未读消息参数 */
  _unreadMessageParams = {
    read: false,
    page: 1,
    size: 5,
    sort: 'id,desc'
  };
  /** 未读消息加载状态 */
  _unreadMessageLoading: boolean = false;
  /** 未读消息下一次加载时间 */
  _unreadMessageNextTime: number = 0;

  /** 取消通行证 */
  private _cancelPassportObserveFn = () => { };
  /** 取消应用列表 */
  private _cancelApplicationListObserveFn = () => { };
  /** 取消当前应用 */
  private _cancelCurrentApplicationObserveFn = () => { };
  /** 取消菜单列表 */
  private _cancelMenuListObserveFn = () => { };
  /** 取消路由记录列表 */
  private _cancelRouteRecordListObserveFn = () => { };
  /** 取消当前路由记录 */
  private _cancelCurrentRouteRecordObserveFn = () => { };
  /** 取消获取未读消息列表 */
  private _cancelGetUnreadMessageListFn = () => { };
  /** 取消轮询未读消息列表 */
  private _cancelPollingUnreadMessageListFn = () => { };

  constructor(
    private _httpClient: HttpClient,
    private _router: Router,
    private _ngCortexService: NgCortexService,
    private _nzContextMenuService: NzContextMenuService,
    private _nzNotificationService: NzNotificationService) { }

  /** 初始化后 */
  ngOnInit(): void {
    this._routeForApplicationIndex = this._ngCortexService.routeForApplicationIndex;
    const passportSubscription = this._ngCortexService.passport.pipe(delay(24)).subscribe(passport => this._passport = passport);
    const applicationListSubscription = this._ngCortexService.applicationList.pipe(delay(24)).subscribe(applicationList => this._applicationList = applicationList);
    const currentApplicationSubscription = this._ngCortexService.currentApplication.pipe(delay(24)).subscribe(application => this._currentApplication = application);
    const menuListSubscription = this._ngCortexService.menuList.pipe(delay(24)).subscribe(menuList => this._menuList = menuList);
    const routeRecordSubscription = this._ngCortexService.routeRecordList.pipe(delay(24)).subscribe(routeRecordList => this._routeRecordList = routeRecordList);
    const currentRouteRecordSubscription = this._ngCortexService.currentRouteRecord.pipe(delay(24)).subscribe(routeRecord => this._currentRouteRecordIndex = this._routeRecordList.indexOf(routeRecord!));
    this._cancelPassportObserveFn = () => { passportSubscription.unsubscribe() };
    this._cancelApplicationListObserveFn = () => { applicationListSubscription.unsubscribe() };
    this._cancelCurrentApplicationObserveFn = () => { currentApplicationSubscription.unsubscribe() };
    this._cancelMenuListObserveFn = () => { menuListSubscription.unsubscribe() };
    this._cancelRouteRecordListObserveFn = () => { routeRecordSubscription.unsubscribe() };
    this._cancelCurrentRouteRecordObserveFn = () => { currentRouteRecordSubscription.unsubscribe() };
    this._pollingUnreadMessageList();
  }

  /** 注销后 */
  ngOnDestroy(): void {
    this._cancelPassportObserveFn();
    this._cancelApplicationListObserveFn();
    this._cancelCurrentApplicationObserveFn();
    this._cancelMenuListObserveFn();
    this._cancelRouteRecordListObserveFn();
    this._cancelCurrentRouteRecordObserveFn();
    this._cancelPollingUnreadMessageListFn();
    this._router.events
      .pipe(filter(event => event instanceof NavigationEnd))
      .pipe(take(1))
      .subscribe(() => {
        if (this._router.url.slice(0, this._routeForApplicationIndex.length) !== this._routeForApplicationIndex) {
          this._ngCortexService.closeCurrentApplication();
        }
      });
  }

  /**
   * 改变未读消息下拉可见状态
   * @param visible 可见状态
   */
  _changeUnreadMessageDropdownVisible(visible: boolean): void {
    if (visible) {
      this._getUnreadMessageList().subscribe();
    } else {
      this._unreadMessageList = this._unreadMessageList.filter(message => !message.read);
    }
  }

  /**
   * 读取未读消息
   * @param message 消息
   */
  _readUnreadMessage(message: any): void {
    message.read = true;
    this._router.navigateByUrl('/apps/system-message-detail?systemMessageId=' + message.id);
  }

  /** 查询未读消息列表 */
  _queryUnreadMessageList(): void {
    this._getUnreadMessageList().subscribe();
  }

  /** 登出 */
  _logout(): void {
    this._ngCortexService.logout();
  }

  /**
   * 跳转标签
   * @param route 路由地址
   */
  _navigateTo(route: string): void {
    this._router.navigateByUrl(route);
  }

  /**
   * 关闭路由
   * @param routeOrIndex 路由或者索引
   */
  _closeRoute(routeOrIndex: string | number): void {
    let route: string;
    if (typeof routeOrIndex === 'string') {
      route = routeOrIndex;
    } else {
      route = this._routeRecordList[routeOrIndex].route;
    }
    this._ngCortexService.closeRoute(route);
  }

  /**
   * 关闭其它路由
   * @param route 路由
   */
  _closeOtherRoutes(route: string): void {
    this._ngCortexService.closeOtherRoutes(route);
  }

  /**
   * 关闭右侧路由
   * @param route 路由
   */
  _closeRightRoutes(route: string): void {
    this._ngCortexService.closeRightRoutes(route);
  }

  /**
   * 关闭全部路由
   */
  _closeAllRoutes(): void {
    this._ngCortexService.closeAllRoutes();
  }

  /**
   * 打开标签下拉菜单
   * @param event 鼠标事件
   * @param menu 菜单模板
   */
  _openTabDropdownMenu(event: MouseEvent, menu: NzDropdownMenuComponent): void {
    this._nzContextMenuService.create(event, menu);
  }

  /** 轮询未读消息列表 */
  private _pollingUnreadMessageList(): void {
    const pollingId = requestAnimationFrame(() => {
      if (Date.now() >= this._unreadMessageNextTime) {
        this._getUnreadMessageList().subscribe(() => this._pollingUnreadMessageList());
      } else {
        this._pollingUnreadMessageList();
      }
    });
    this._cancelPollingUnreadMessageListFn = () => {
      cancelAnimationFrame(pollingId);
    };
  }

  /** 获取未读消息列表 */
  private _getUnreadMessageList(): Observable<HttpErrorResponse | Error | null> {
    this._cancelGetUnreadMessageListFn();
    return new Observable(subscriber => {
      this._unreadMessageLoading = true;
      const completeGetUnreadMessageListFn = () => {
        this._cancelGetUnreadMessageListFn = () => { };
        this._unreadMessageLoading = false;
        this._unreadMessageNextTime = Date.now() + environment.pollingUnreadMessageDelay;
      };
      const url = '@' + environment.coreService + '/api/system-message-deliveries';
      const params: any = { ...this._unreadMessageParams };
      params.page--;
      const getUnreadMessageListSubscription = this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
        .pipe(mergeMap(httpResponse => {
          const unreadMessageList = httpResponse.body!;
          const unreadMessageTotal = Number(httpResponse.headers.get('X-Total-Count'));
          if (unreadMessageList.length === 0 && unreadMessageTotal > 0) {
            this._unreadMessageParams.page = Math.ceil(unreadMessageTotal / params.size);
            params.page = this._unreadMessageParams.page - 1;
            return this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
              .pipe(map(httpResponse => {
                const unreadMessageList = httpResponse.body!;
                const unreadMessageTotal = Number(httpResponse.headers.get('X-Total-Count'));
                return { unreadMessageList, unreadMessageTotal };
              }));
          }
          return of({ unreadMessageList, unreadMessageTotal });
        }))
        .pipe(tap(() => subscriber.next(null)))
        .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
          this._nzNotificationService.error('获取未读消息列表失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
          subscriber.next(httpErrorResponse);
          return of({ unreadMessageList: [], unreadMessageTotal: 0 });
        }))
        .subscribe(({ unreadMessageList, unreadMessageTotal }) => {
          completeGetUnreadMessageListFn();
          this._unreadMessageList = unreadMessageList;
          this._unreadMessageTotal = unreadMessageTotal;
          subscriber.complete();
        });
      this._cancelGetUnreadMessageListFn = () => {
        getUnreadMessageListSubscription.unsubscribe();
        completeGetUnreadMessageListFn();
        subscriber.next(new Error('取消获取未读消息列表'));
        subscriber.complete();
      };
    });
  }

}
