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

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

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

import {
  LoginInfo,
  KEY_LOGIN_INFO,
  EnvironmentsInfo,
  KEY_ENVIRONMENTS_INFO,
  KEY_URL_INFO,
  KEY_AUTH_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,
  AuthResponse
} from '@ucap-webmessenger/protocol-query';
import { OptionProtocolService } from '@ucap-webmessenger/protocol-option';

import { TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui';

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 * as StatusStore from '@app/store/messenger/status';
import * as SettingInitStore from '@app/store/setting/init';
import { KEY_LOGIN_RES_INFO, KEY_VER_INFO } from '@app/types';

import { environment } from '../../environments/environment';
import { SnackBarService } from '@ucap-webmessenger/ui';
import { AppNativeService } from '@app/services/native.service';
import {
  ExternalApiService,
  UrlInfoResponse,
  DaesangUrlInfoResponse
} from '@ucap-webmessenger/api-external';
import { StatusCode } from '@ucap-webmessenger/api';
import { UCAP_NATIVE_SERVICE, NativeService } from '@ucap-webmessenger/native';
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';

@Injectable()
export class AppMessengerResolver implements Resolve<void> {
  constructor(
    @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
    private store: Store<any>,
    private sessionStorageService: SessionStorageService,
    private localStorageService: LocalStorageService,
    private publicApiService: PublicApiService,
    private externalApiService: ExternalApiService,
    private protocolService: ProtocolService,
    private queryProtocolService: QueryProtocolService,
    private optionProtocolService: OptionProtocolService,
    private authenticationProtocolService: AuthenticationProtocolService,
    private innerProtocolService: InnerProtocolService,
    private appNativeService: AppNativeService,
    private snackBarService: SnackBarService,
    private logger: NGXLogger
  ) {}

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

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

      let localIp = '';
      let localMac = '';

      // get network info
      await this.nativeService
        .getNetworkInfo()
        .then(result => {
          if (!!result && result.length > 0) {
            if (!!result[0].ip) {
              localIp = result[0].ip;
            }
            if (!!result[0].mac) {
              localMac = result[0].mac;
            }
          }
        })
        .catch(reason => {});

      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(() => {
            return this.externalApiService
              .urlInfoDaesang({
                deviceType: environmentsInfo.deviceType,
                loginId: loginInfo.loginId
              })
              .pipe(
                map(response => {
                  if (response.statusCode === StatusCode.Success) {
                    this.sessionStorageService.set<
                      UrlInfoResponse | DaesangUrlInfoResponse
                    >(KEY_URL_INFO, response);
                  } else {
                  }
                }),
                catchError(error => of(this.logger.error({ error })))
              );
          }),
          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: localIp,
                hostName: localMac,
                ssoMode: SSOMode.AUTH,
                userSpecificInformation: 'PRO_000482',
                andId: '',
                andPushRefreshYn: ''
              })
              .pipe(
                catchError(err => {
                  switch (err as ServerErrorCode) {
                    case ServerErrorCode.ERRCD_IDPW:
                      break;

                    default:
                      break;
                  }
                  return throwError(err);
                })
              );
          }),
          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.sessionStorageService.set<AuthResponse>(KEY_AUTH_INFO, {
              ...authRes
            });

            this.store.dispatch(QueryStore.authSuccess({ res: authRes }));

            this.store.dispatch(
              CompanyStore.companyList({
                companyGroupCode: environment.companyConfig.companyGroupCode
              })
            );
          }),
          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
              })
            );
            this.store.dispatch(AuthenticationStore.postLogin({ loginRes }));
            this.appNativeService.subscribeAfterLogin();

            const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
              KEY_APP_USER_INFO,
              environment.customConfig.appKey
            );
            this.store.dispatch(
              StatusStore.changeMyIdleCheckTime({
                checkTime: appUserInfo.idleCheckTime
              })
            );

            resolve();
          },
          err => {
            reject(err);
          }
        );
    });
  }
}
