import { Injectable } from '@angular/core';
import {
  Resolve,
  ActivatedRouteSnapshot,
  RouterStateSnapshot
} from '@angular/router';
import { Observable, throwError, forkJoin } from 'rxjs';
import {
  map,
  tap,
  catchError,
  take,
  switchMap,
  withLatestFrom
} from 'rxjs/operators';

import { Store, select } from '@ngrx/store';

import { ProtocolService } from '@ucap-webmessenger/protocol';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import {
  PublicApiService,
  VersionInfo2Response
} from '@ucap-webmessenger/api-public';

import {
  LoginInfo,
  KEY_LOGIN_INFO,
  EnvironmentsInfo,
  KEY_ENVIRONMENTS_INFO
} from '@app/types';
import { InnerProtocolService } from '@ucap-webmessenger/protocol-inner';
import {
  AuthenticationProtocolService,
  SSOMode,
  LoginResponse
} from '@ucap-webmessenger/protocol-authentication';

import * as AuthenticationStore from '@app/store/account/authentication';
import { NGXLogger } from 'ngx-logger';
import { QueryProtocolService } from '@ucap-webmessenger/protocol-query';
import { OptionProtocolService } from '@ucap-webmessenger/protocol-option';

import * as AppStore from '@app/store';
import * as CompanyStore from '@app/store/setting/company';
import * as VersionInfoStore from '@app/store/setting/version-info';
import * as OptionStore from '@app/store/messenger/option';
import * as QueryStore from '@app/store/messenger/query';
import * as SyncStore from '@app/store/messenger/sync';
import { KEY_VER_INFO } from '@app/types/ver-info.type';
import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';

@Injectable()
export class AppMessengerResolver implements Resolve<void> {
  constructor(
    private store: Store<any>,
    private sessionStorageService: SessionStorageService,
    private publicApiService: PublicApiService,
    private protocolService: ProtocolService,
    private queryProtocolService: QueryProtocolService,
    private optionProtocolService: OptionProtocolService,
    private authenticationProtocolService: AuthenticationProtocolService,
    private innerProtocolService: InnerProtocolService,
    private logger: NGXLogger
  ) {}

  resolve(
    activatedRouteSnapshot: ActivatedRouteSnapshot,
    routerStateSnapshot: RouterStateSnapshot
  ): void | Observable<void> | Promise<void> {
    return new Promise<void>((resolve, reject) => {
      let loginRes: LoginResponse;

      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),
          tap(res => {
            this.sessionStorageService.set<VersionInfo2Response>(
              KEY_VER_INFO,
              res
            );
            this.store.dispatch(VersionInfoStore.versionInfo2Success({ res }));
          }),
          switchMap(res => {
            return this.protocolService.connect(res.serverIp);
          }),
          switchMap(() => this.innerProtocolService.conn({})),
          switchMap(res => {
            return this.authenticationProtocolService.login({
              loginId: loginInfo.loginId,
              loginPw: loginInfo.loginPw,
              deviceType: environmentsInfo.deviceType,
              deviceId: ' ',
              token: '',
              localeCode: loginInfo.localeCode,
              pushId: ' ',
              companyCode: loginInfo.companyCode,
              passwordEncodingType: 1,
              clientVersion: '',
              reconnect: false,
              ip: 'localhost',
              hostName: '',
              ssoMode: SSOMode.AUTH,
              userSpecificInformation: 'PRO_000482',
              productId: 'PRO_000482',
              productName: 'EZMessenger'
            });
          }),
          switchMap(res => {
            loginRes = res;

            this.sessionStorageService.set<LoginResponse>(KEY_LOGIN_RES_INFO, {
              ...loginRes
            });

            return forkJoin([
              this.queryProtocolService.auth({
                deviceType: environmentsInfo.deviceType
              }),
              this.optionProtocolService.regView({})
            ]);
          }),
          map(([authRes, regViewRes]) => {
            this.store.dispatch(
              OptionStore.regViewSuccess({ res: regViewRes })
            );
            this.store.dispatch(QueryStore.authSuccess({ res: authRes }));

            this.store.dispatch(
              CompanyStore.companyList({
                companyGroupCode: 'LG'
              })
            );

            // this.store.dispatch(AuthenticationStore.postLogin({ loginRes }));
          }),
          withLatestFrom(
            this.store.pipe(
              select(
                AppStore.MessengerSelector.SyncSelector.selectBuddy2SyncDate
              )
            ),
            this.store.pipe(
              select(
                AppStore.MessengerSelector.SyncSelector.selectGroup2SyncDate
              )
            ),
            this.store.pipe(
              select(AppStore.MessengerSelector.SyncSelector.selectRoomSyncDate)
            )
          ),
          map(([_, buddy2SyncDate, group2SyncDate, roomSyncDate]) => {
            this.store.dispatch(SyncStore.buddy2({ syncDate: buddy2SyncDate }));
            this.store.dispatch(SyncStore.group2({ syncDate: group2SyncDate }));
            this.store.dispatch(
              SyncStore.room({
                syncDate: roomSyncDate,
                localeCode: loginInfo.localeCode
              })
            );
            this.store.dispatch(
              QueryStore.dept({
                divCd: 'ORG',
                companyCode: loginInfo.companyCode
              })
            );
          }),
          catchError(err => {
            return throwError(err);
          })
        )
        .subscribe(
          () => {
            this.store.dispatch(
              AuthenticationStore.loginSuccess({
                loginRes
              })
            );
            resolve();
          },
          err => {
            reject(err);
          }
        );
    });
  }
}
