import {
  Component,
  OnInit,
  Inject,
  OnDestroy,
  ChangeDetectorRef,
  ViewChild
} from '@angular/core';
import {
  UCAP_NATIVE_SERVICE,
  NativeService,
  WindowState,
  UpdateInfo
} from '@ucap-webmessenger/native';
import { Observable, Subscription, of } from 'rxjs';
import { Store, select } from '@ngrx/store';

import semver from 'semver';

import * as AppStore from '@app/store';
import * as ChatStore from '@app/store/messenger/chat';
import * as AuthenticationStore from '@app/store/account/authentication';
import * as SettingsStore from '@app/store/messenger/settings';
import * as UpdateStore from '@app/store/setting/update';
import * as SettingNativeStore from '@app/store/setting/native';
import * as StatusStore from '@app/store/messenger/status';

import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { tap, take, map, catchError } from 'rxjs/operators';
import {
  RightDrawer,
  KEY_URL_INFO,
  LoginInfo,
  KEY_LOGIN_INFO,
  KEY_VER_INFO,
  EnvironmentsInfo,
  KEY_ENVIRONMENTS_INFO
} from '@app/types';
import {
  WebLink,
  DaesangUrlInfoResponse
} from '@ucap-webmessenger/api-external';
import {
  SessionStorageService,
  LocalStorageService
} from '@ucap-webmessenger/web-storage';
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';
import { environment } from '../../../../environments/environment';
import {
  DaesangApiService,
  DaesangProtocolService,
  WebLinkType
} from '@ucap-webmessenger/daesang';
import { NGXLogger } from 'ngx-logger';
import {
  VersionInfo2Response,
  PublicApiService
} from '@ucap-webmessenger/api-public';
import {
  ProfileDialogComponent,
  ProfileDialogResult,
  ProfileDialogData
} from '@app/layouts/messenger/dialogs/profile/profile.dialog.component';
import { DialogService } from '@ucap-webmessenger/ui';
import { DOCUMENT } from '@angular/common';
import { MatMenu, MatRadioChange } from '@angular/material';
import { StatusCode, StatusType } from '@ucap-webmessenger/core';
import {
  StatusInfo,
  MessageIndexType,
  MessageUpdateRequest
} from '@ucap-webmessenger/protocol-status';
import {
  IntegratedSearchDialogComponent,
  IntegratedSearchDialogResult,
  IntegratedSearchDialogData
} from '@app/layouts/messenger/dialogs/search/integrated-search.dialog.component';

const zoomFactors = [60, 70, 85, 100, 120, 145, 170, 200];

@Component({
  selector: 'app-layout-native-top-bar',
  templateUrl: './top-bar.component.html',
  styleUrls: ['./top-bar.component.scss']
})
export class TopBarComponent implements OnInit, OnDestroy {
  windowStateChanged$: Observable<WindowState>;
  WindowState = WindowState;

  loginRes: LoginResponse;
  loginResSubscription: Subscription;
  sessionVerinfo: VersionInfo2Response;

  updateInfo$: Observable<UpdateInfo>;

  myStatus: StatusInfo;
  myStatusSubscription: Subscription;

  myIdleCheckTime: number;
  myIdleCheckTimeSubscription: Subscription;

  zoom: number;
  zoomSubscription: Subscription;

  loginInfo: LoginInfo;
  weblink: WebLink[] = [];
  webLinkBadgeMail = 0;
  webLinkBadgePayment = 0;

  appVersion: string;

  WebLinkType = WebLinkType;
  StatusCode = StatusCode;

  checkingUpdate = false;
  checkingUpdateIsProcessing = false;
  checkingUpdateAppVersion: string;
  checkingUpdateIsExist = false;

  readonly awayTimeList = [10, 20, 30];

  @ViewChild('profileMenu', { static: true })
  profileMenu: MatMenu;

  constructor(
    private store: Store<any>,
    @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
    private changeDetectorRef: ChangeDetectorRef,
    private dialogService: DialogService,
    private localStorageService: LocalStorageService,
    private sessionStorageService: SessionStorageService,
    private publicApiService: PublicApiService,
    private daesangApiService: DaesangApiService,
    private daesangProtocolService: DaesangProtocolService,
    @Inject(DOCUMENT) private document: Document,
    private logger: NGXLogger
  ) {}

  ngOnInit() {
    this.windowStateChanged$ = this.nativeService.windowStateChanged();

    this.loginResSubscription = this.store
      .pipe(
        select(AppStore.AccountSelector.AuthenticationSelector.loginRes),
        tap(loginRes => {
          this.loginRes = loginRes;

          this.loginInfo = this.sessionStorageService.get<LoginInfo>(
            KEY_LOGIN_INFO
          );

          this.sessionVerinfo = this.sessionStorageService.get<
            VersionInfo2Response
          >(KEY_VER_INFO);

          // WebLink init..
          this.initWebLink(loginRes);
        })
      )
      .subscribe();

    this.myStatusSubscription = this.store
      .pipe(select(AppStore.MessengerSelector.StatusSelector.selectMyStatus))
      .subscribe(myStatus => {
        this.myStatus = myStatus;
      });

    this.myIdleCheckTimeSubscription = this.store
      .pipe(
        select(AppStore.MessengerSelector.StatusSelector.selectMyIdleCheckTime)
      )
      .subscribe(myIdleCheckTime => {
        this.myIdleCheckTime = myIdleCheckTime;
      });

    this.zoomSubscription = this.store
      .pipe(select(AppStore.SettingSelector.NativeSelector.selectZoom))
      .subscribe(zoom => {
        this.zoom = zoom;
      });

    this.updateInfo$ = this.store.pipe(
      select(AppStore.SettingSelector.UpdateSelector.updateInfo)
    );

    this.nativeService.getVersionInfo().then(ver => {
      this.appVersion = ver;
    });
  }

  ngOnDestroy(): void {
    if (!!this.loginResSubscription) {
      this.loginResSubscription.unsubscribe();
      this.loginResSubscription = undefined;
    }
    if (!!this.myStatusSubscription) {
      this.myStatusSubscription.unsubscribe();
      this.myStatusSubscription = undefined;
    }
    if (!!this.myIdleCheckTimeSubscription) {
      this.myIdleCheckTimeSubscription.unsubscribe();
      this.myIdleCheckTimeSubscription = undefined;
    }
    if (!!this.zoomSubscription) {
      this.zoomSubscription.unsubscribe();
      this.zoomSubscription = undefined;
    }
  }

  initWebLink(loginRes: LoginResponse): void {
    if (!!loginRes) {
      const urlInfo: DaesangUrlInfoResponse = this.sessionStorageService.get<
        DaesangUrlInfoResponse
      >(KEY_URL_INFO);

      if (!!urlInfo && !!urlInfo.webLink) {
        // order by webLinkAllowedList..
        this.weblink = urlInfo.webLinkAllowedList
          .filter(
            showWebLink =>
              urlInfo.webLink.filter(wl => wl.key === showWebLink).length > 0
          )
          .map(showWeblink =>
            urlInfo.webLink.find(weblink => weblink.key === showWeblink)
          );

        if (urlInfo.webLinkAllowedList.indexOf(WebLinkType.Mail) > -1) {
          // 메일 카운트 체크.
          const link = urlInfo.webLink.filter(
            weblink => weblink.key === WebLinkType.MailCnt
          );
          if (link.length > 0) {
            const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
              KEY_APP_USER_INFO,
              environment.customConfig.appKey
            );

            const WebLinkMailCnt = link[0];
            const loginPw = appUserInfo.loginPw;
            const loginPw2 = this.loginInfo.loginPw;
            const loginId = this.loginInfo.loginId;
            const token = loginRes.tokenString;

            const url = WebLinkMailCnt.url
              .replace(/(\(%USER_TOKEN%\))/g, token)
              .replace(/(\(%USER_ID%\))/g, loginId)
              .replace(/(\(%USER_PASS%\))/g, loginPw);

            this.daesangApiService
              .retrieveMailCount(url)
              .pipe(
                take(1),
                map(res => (this.webLinkBadgeMail = res.count)),
                catchError(error => of(this.logger.log(error)))
              )
              .subscribe();
          }
        }
        if (urlInfo.webLinkAllowedList.indexOf(WebLinkType.Payment) > -1) {
          // 결제 카운트 체크.
          const link = urlInfo.webLink.filter(
            weblink => weblink.key === WebLinkType.PaymentCnt
          );
          if (link.length > 0) {
            const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
              KEY_APP_USER_INFO,
              environment.customConfig.appKey
            );

            const WebLinkPaymentCnt = link[0];
            const loginPw = appUserInfo.loginPw;
            const loginPw2 = this.loginInfo.loginPw;
            const loginId = this.loginInfo.loginId;
            const token = loginRes.tokenString;

            const url = WebLinkPaymentCnt.url
              .replace(/(\(%USER_TOKEN%\))/g, token)
              .replace(/(\(%USER_ID%\))/g, loginId)
              .replace(/(\(%USER_PASS%\))/g, loginPw);

            this.daesangApiService
              .retrievePaymentCount(url)
              .pipe(
                take(1),
                map(res => {
                  this.webLinkBadgePayment = res.count;
                }),
                catchError(error => of(this.logger.log(error)))
              )
              .subscribe();
          }
        }
      }
    }
  }

  onClickClose() {
    this.nativeService.windowClose();
  }

  onClickMinimize() {
    this.nativeService.windowMinimize();
  }

  onClickMaxmize() {
    this.nativeService.windowMaximize();
  }

  onClickSettings(): void {
    this.store.dispatch(SettingsStore.showDialog());
  }

  onClickLogout(): void {
    this.store.dispatch(AuthenticationStore.logoutConfirmation());
  }

  onClickQuit(): void {
    this.nativeService.appExit();
  }

  getMyProfileImageWidget(): string {
    if (!!this.loginRes) {
      return this.loginRes.userInfo.profileImageFile;
    } else {
      return '';
    }
  }

  onClickOpenProfile(event: Event) {
    // [GROUP]
    // this.queryProtocolService
    //   .dataUser({
    //     divCd: 'OPENPROF',
    //     seq: userInfo.seq,
    //     senderCompanyCode: this.loginRes.userInfo.companyCode,
    //     senderEmployeeType: this.loginRes.userInfo.employeeType
    //   })
    //   .pipe(
    //     take(1),
    //     map(res => {
    //       if (!!res && !!res.userInfo) {
    //         this.dialogService.open<
    //           ProfileDialogComponent,
    //           ProfileDialogData,
    //           ProfileDialogResult
    //         >(ProfileDialogComponent, {
    //           data: {
    //             userInfo: res.userInfo
    //           }
    //         });
    //       }
    //     })
    //   )
    //   .subscribe();
    event.preventDefault();

    // [Daesang]
    this.daesangProtocolService
      .dataUserDaesang({
        divCd: 'OPENPROF',
        seq: this.loginRes.userSeq,
        senderCompanyCode: this.loginRes.userInfo.companyCode,
        senderEmployeeType: this.loginRes.userInfo.employeeType
      })
      .pipe(
        take(1),
        map(res => {
          if (!!res && !!res.userInfo) {
            this.dialogService.open<
              ProfileDialogComponent,
              ProfileDialogData,
              ProfileDialogResult
            >(ProfileDialogComponent, {
              data: {
                userInfo: res.userInfo
              }
            });
          }
        })
      )
      .subscribe();
  }

  onClickNotice(): void {
    this.store.dispatch(
      ChatStore.selectedRightDrawer({
        req: RightDrawer.Notice
      })
    );
  }

  /** About WebLink */
  onClickWebLink(link: WebLink): void {
    const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
      KEY_APP_USER_INFO,
      environment.customConfig.appKey
    );

    const loginPw = appUserInfo.loginPw;
    const loginPw2 = this.loginInfo.loginPw;
    const loginId = this.loginInfo.loginId;
    const token = this.loginRes.tokenString;

    const url = link.url
      .replace(/(\(%USER_TOKEN%\))/g, token)
      .replace(/(\(%USER_ID%\))/g, loginId)
      .replace(/(\(%USER_PASS%\))/g, loginPw);

    this.nativeService.openDefaultBrowser(url);
  }

  onClosedProfileMenu() {
    this.checkingUpdate = false;
    this.checkingUpdateIsProcessing = false;
    this.checkingUpdateAppVersion = undefined;
    this.checkingUpdateIsExist = false;
  }

  onClickUpdate() {
    this.store.dispatch(UpdateStore.applyInstantUpdate());
  }

  onClickZoomOut(event: Event) {
    const i = zoomFactors.indexOf(this.zoom);
    if (-1 === i || 0 === i) {
      return;
    }

    const zoom = zoomFactors[i - 1];
    this.store.dispatch(SettingNativeStore.changeZoom({ zoom }));
  }

  onClickZoomLabel(event: Event) {
    this.store.dispatch(SettingNativeStore.changeZoom({ zoom: 100 }));
  }

  onClickZoomIn(event: Event) {
    const i = zoomFactors.indexOf(this.zoom);
    if (-1 === i || zoomFactors.length - 1 === i) {
      return;
    }

    const zoom = zoomFactors[i + 1];
    this.store.dispatch(SettingNativeStore.changeZoom({ zoom }));
  }

  onClickRemoteSupport(event: Event) {
    this.nativeService.executeProcess('AeroAdmin');
  }

  onClickStatusOnline(event: Event) {
    this.store.dispatch(
      StatusStore.status({
        req: {
          statusDivisionType: StatusType.Messenger,
          statusType: StatusCode.OnLine
        }
      })
    );
  }

  onClickStatusAway(event: Event) {
    this.store.dispatch(
      StatusStore.status({
        req: {
          statusDivisionType: StatusType.Messenger,
          statusType: StatusCode.Away
        }
      })
    );
  }

  onClickStatusBusy(event: Event, index: number) {
    let statusMessage = '';
    switch (index) {
      case 1:
        statusMessage = this.loginRes.statusMessage1;
        break;
      case 2:
        statusMessage = this.loginRes.statusMessage2;
        break;
      case 3:
        statusMessage = this.loginRes.statusMessage3;
        break;
    }

    this.store.dispatch(
      StatusStore.status({
        req: {
          statusDivisionType: StatusType.Messenger,
          statusType: StatusCode.Busy,
          statusMessage
        }
      })
    );
  }

  onApplyStatusMessage(index: MessageIndexType, statusMessage: string) {
    this.logger.debug('StatusMessage', index, statusMessage);

    this.store.dispatch(
      StatusStore.messageUpdate({
        index,
        statusMessage
      } as MessageUpdateRequest)
    );
  }

  onClickChangeStatusBusy(event: Event, index: number) {
    event.stopPropagation();
  }

  onChangeAwayTime(event: MatRadioChange) {
    this.store.dispatch(
      StatusStore.changeMyIdleCheckTime({ checkTime: Number(event.value) })
    );
  }

  onMenuOpenedinformationMenu() {
    if (this.checkingUpdate) {
      return;
    }

    this.checkForUpdates();
  }

  checkForUpdates() {
    this.checkingUpdate = true;
    this.checkingUpdateIsProcessing = true;

    const loginInfo = this.sessionStorageService.get<LoginInfo>(KEY_LOGIN_INFO);
    const environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>(
      KEY_ENVIRONMENTS_INFO
    );

    this.publicApiService
      .versionInfo2({
        deviceType: environmentsInfo.deviceType,
        companyGroupType: loginInfo.companyGroupType,
        companyCode: loginInfo.companyCode,
        loginId: loginInfo.loginId
      })
      .pipe(take(1))
      .subscribe(
        res => {
          this.checkingUpdateAppVersion = res.appVersion;
          if (semver.lt(this.appVersion, res.appVersion)) {
            this.checkingUpdateIsExist = true;
          } else {
            this.checkingUpdateIsExist = false;
          }
        },
        error => {},
        () => {
          this.checkingUpdateIsProcessing = false;
        }
      );
  }

  onClickApplyUpdate(event: Event) {
    this.nativeService.checkForUpdates(this.checkingUpdateAppVersion);
  }

  onIntegratedSearch(keyword: string) {
    if (!keyword || keyword.trim().length === 0) {
      return;
    }

    this.dialogService.open<
      IntegratedSearchDialogComponent,
      IntegratedSearchDialogData,
      IntegratedSearchDialogResult
    >(IntegratedSearchDialogComponent, {
      data: {
        keyword
      }
    });
  }
}
