import { Injectable, Inject, NgZone } from '@angular/core';
import { Router } from '@angular/router';

import { of, Observable } from 'rxjs';
import { catchError, exhaustMap, map, tap, switchMap } from 'rxjs/operators';

import { Actions, ofType, createEffect } from '@ngrx/effects';

import {
  PiService,
  Login2Response,
  UserTermsActionResponse
} from '@ucap-webmessenger/pi';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
import {
  DialogService,
  ConfirmDialogComponent,
  ConfirmDialogData,
  ConfirmDialogResult,
  SnackBarService,
  AlertDialogComponent,
  AlertDialogData,
  AlertDialogResult
} from '@ucap-webmessenger/ui';

import {
  loginRedirect,
  logout,
  logoutConfirmation,
  logoutConfirmationDismiss,
  webLogin,
  webLoginSuccess,
  webLoginFailure,
  postLogin,
  privacyAgree,
  privacyDisagree,
  privacyAgreeFailure,
  privacyAgreeSuccess,
  increaseLoginFailCount,
  initialLoginFailCount,
  logoutInitialize,
  userPasswordSet,
  userPasswordSetSuccess,
  userPasswordSetFailure,
  infoUser,
  infoUserSuccess,
  infoUserFailure
} from './actions';
import {
  LoginInfo,
  KEY_LOGIN_INFO,
  EnvironmentsInfo,
  KEY_ENVIRONMENTS_INFO,
  KEY_URL_INFO,
  LogoutInfo,
  KEY_LOGOUT_INFO
} from '@app/types';
import { AppAuthenticationService } from '@app/services/authentication.service';
import { NGXLogger } from 'ngx-logger';
import { Store } from '@ngrx/store';
import {
  SessionStorageService,
  LocalStorageService
} from '@ucap-webmessenger/web-storage';

import {
  AuthenticationProtocolService,
  LoginResponse
} from '@ucap-webmessenger/protocol-authentication';
import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';
import { ProtocolService } from '@ucap-webmessenger/protocol';

import { environment } from '../../../../environments/environment';

import {
  ServiceProtocolService,
  UserPasswordSetResponse
} from '@ucap-webmessenger/protocol-service';
import { DaesangUrlInfoResponse } from '@ucap-webmessenger/api-external';
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';
import { DaesangCipherService, WebLinkType } from '@ucap-webmessenger/daesang';
import { TranslateService } from '@ngx-translate/core';
import {
  InfoProtocolService,
  UserResponse
} from '@ucap-webmessenger/protocol-info';

@Injectable()
export class Effects {
  webLogin$ = createEffect(() =>
    this.actions$.pipe(
      ofType(webLogin),
      map(action => action),
      exhaustMap(
        (params: {
          loginInfo: LoginInfo;
          rememberMe: boolean;
          autoLogin: boolean;
        }) =>
          this.piService
            .login2({
              loginId: params.loginInfo.loginId,
              loginPw: params.loginInfo.loginPw,
              companyCode: params.loginInfo.companyCode
            })
            .pipe(
              map((res: Login2Response) => {
                if ('success' !== res.status.toLowerCase()) {
                  this.store.dispatch(increaseLoginFailCount({}));
                  return webLoginFailure({ error: 'Failed' });
                } else {
                  this.store.dispatch(initialLoginFailCount({}));
                  return webLoginSuccess({
                    loginInfo: params.loginInfo,
                    rememberMe: params.rememberMe,
                    autoLogin: params.autoLogin,
                    login2Response: res
                  });
                }
              }),
              catchError(error => of(webLoginFailure({ error })))
            )
      )
    )
  );

  webLoginSuccess$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(webLoginSuccess),
        tap(params => {
          this.nativeService.checkForUpdates(params.login2Response.version);
          this.appAuthenticationService.login(
            params.loginInfo,
            params.rememberMe,
            params.autoLogin
          );
          this.router.navigate(['/messenger']);
        })
      ),
    { dispatch: false }
  );

  loginRedirect$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(loginRedirect),
        tap(authed => {
          // this.ngZone.run(() => {
          // location.href = this.router.parseUrl('/account/login').toString();
          this.protocolService.disconnect();
          this.router.navigate(['/account/login']);
          this.appAuthenticationService.logout();
          this.store.dispatch(logoutInitialize());
          // });
        })
      ),
    { dispatch: false }
  );

  logout$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(logout),
        switchMap(action => {
          return this.authenticationProtocolService.logout({}).pipe(
            map(res => {
              this.sessionStorageService.set<LogoutInfo>(KEY_LOGOUT_INFO, {
                personLogout: true
              } as LogoutInfo);

              this.store.dispatch(loginRedirect());
            }),
            catchError(error => of(error))
          );
        })
      );
    },
    { dispatch: false }
  );

  logoutConfirmation$ = createEffect(() =>
    this.actions$.pipe(
      ofType(logoutConfirmation),
      exhaustMap(async () => {
        const loginRes = this.sessionStorageService.get<LoginResponse>(
          KEY_LOGIN_RES_INFO
        );

        if (!!loginRes && loginRes.userSeq) {
          const result = await this.dialogService.open<
            ConfirmDialogComponent,
            ConfirmDialogData,
            ConfirmDialogResult
          >(ConfirmDialogComponent, {
            data: {
              title: this.translateService.instant('accounts.logout'),
              message: this.translateService.instant('accounts.confirmLogout')
            }
          });

          if (!!result && !!result.choice && result.choice) {
            return true;
          } else {
            return false;
          }
        } else {
          return false;
        }
      }),
      map(result => (result ? logout() : logoutConfirmationDismiss()))
    )
  );

  postLogin$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(postLogin),
        map(action => action.loginRes),
        tap(async loginRes => {
          const loginInfo = this.sessionStorageService.get<LoginInfo>(
            KEY_LOGIN_INFO
          );
          const environmentsInfo = this.sessionStorageService.get<
            EnvironmentsInfo
          >(KEY_ENVIRONMENTS_INFO);

          if (
            environment.productConfig.authentication
              .usePrivateInformationAgree &&
            !loginRes.privateInformationAgree
          ) {
            const privacyTotalUrl = this.piService.privacyTotalUrl({
              companyCode: loginInfo.companyCode,
              userSeq: loginRes.userSeq,
              token: loginRes.tokenString,
              deviceType: environmentsInfo.deviceType,
              localeCode: loginInfo.localeCode,
              textOnly: 'true'
            });

            const result = await this.dialogService.open<
              ConfirmDialogComponent,
              ConfirmDialogData,
              ConfirmDialogResult
            >(ConfirmDialogComponent, {
              width: '100%',
              height: '500px',
              disableClose: true,
              data: {
                title: this.translateService.instant(
                  'accounts.consentOfPrivacy'
                ),
                html: `<iframe id="ifm_privacy" src="${privacyTotalUrl}" style="width: 100%;height: 300px;" />`
              }
            });

            if (result.choice) {
              this.store.dispatch(privacyAgree({ loginRes }));
            } else {
              this.store.dispatch(privacyDisagree());
              return;
            }
          }

          if (!!loginInfo.initPw) {
            this.store.dispatch(logout());

            const passwordInitStep1Url = this.piService.passwordInitStep1Url({
              localeCode: loginInfo.localeCode
            });

            const result = await this.dialogService.open<
              ConfirmDialogComponent,
              ConfirmDialogData,
              ConfirmDialogResult
            >(ConfirmDialogComponent, {
              width: '100%',
              height: '500px',
              disableClose: true,
              data: {
                title: this.translateService.instant('accounts.resetPassword'),
                html: `<iframe id="ifm_privacy" src="${passwordInitStep1Url}" style="width: 100%;height: 300px;" />`
              }
            });

            if (result.choice) {
            } else {
              return;
            }
          }

          if (!loginRes.passwordValid) {
            // [Daesang]
            const urlInfo: DaesangUrlInfoResponse = this.sessionStorageService.get<
              DaesangUrlInfoResponse
            >(KEY_URL_INFO);

            await this.dialogService.open<
              AlertDialogComponent,
              AlertDialogData,
              AlertDialogResult
            >(AlertDialogComponent, {
              data: {
                title: this.translateService.instant(
                  'accounts.passwordExpired'
                ),
                html: this.translateService.instant(
                  'accounts.descriptionOfPasswordExpired'
                )
              }
            });

            const passwordChangeUrl = urlInfo.webLink.filter(
              weblink => weblink.key === WebLinkType.ChgPassword
            );
            if (passwordChangeUrl.length > 0) {
              const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
                KEY_APP_USER_INFO,
                environment.customConfig.appKey
              );
              const loginPw = appUserInfo.loginPw;
              const loginId = appUserInfo.loginId;

              const url = passwordChangeUrl[0].url
                .replace(/(\(%USER_ID%\))/g, loginId)
                .replace(
                  /(\(%USER_PASS%\))/g,
                  this.daesangCipherService.encryptForWebLink(loginPw)
                );

              this.nativeService.openDefaultBrowser(url);
            }

            this.store.dispatch(logout());

            // // [GROUP]
            // const result = await this.dialogService.open<
            //   ChangePasswordDialogComponent,
            //   ChangePasswordDialogData,
            //   ChangePasswordDialogResult
            // >(ChangePasswordDialogComponent, {
            //   width: '500px',
            //   height: '500px',
            //   disableClose: false,
            //   data: {
            //     loginId: loginInfo.loginId,
            //     encryptedLoginPw: loginInfo.loginPw,
            //     phoneNumber: loginRes.userInfo.hpNumber
            //   }
            // });

            // if (!!result && result.choice) {
            //   this.store.dispatch(
            //     userPasswordSet({
            //       req: {
            //         companyCode: loginInfo.companyCode,
            //         loginId: loginInfo.loginId,
            //         oldLoginPw: result.currentLoginPw,
            //         newLoginPw: result.newLoginPw
            //       }
            //     })
            //   );
            // } else {
            //   this.store.dispatch(logout());
            //   return;
            // }
          }
        })
      ),
    { dispatch: false }
  );

  privacyAgree$ = createEffect(() =>
    this.actions$.pipe(
      ofType(privacyAgree),
      map(action => {
        const loginInfo = this.sessionStorageService.get<LoginInfo>(
          KEY_LOGIN_INFO
        );
        const environmentsInfo = this.sessionStorageService.get<
          EnvironmentsInfo
        >(KEY_ENVIRONMENTS_INFO);

        return {
          loginInfo,
          environmentsInfo,
          loginResponse: action.loginRes
        };
      }),
      exhaustMap(params =>
        this.piService
          .userTermsAction({
            userSeq: params.loginResponse.userSeq,
            token: params.loginResponse.tokenString,
            deviceType: params.environmentsInfo.deviceType
          })
          .pipe(
            map((res: UserTermsActionResponse) => {
              if ('00' !== res.responseCode) {
                return privacyAgreeFailure({ error: 'Failed' });
              } else {
                return privacyAgreeSuccess();
              }
            }),
            catchError(error => of(privacyAgreeFailure({ error })))
          )
      )
    )
  );

  userPasswordSet$ = createEffect(() =>
    this.actions$.pipe(
      ofType(userPasswordSet),
      map(action => action.req),
      exhaustMap(req =>
        this.serviceProtocolService.userPasswordSet(req).pipe(
          map((res: UserPasswordSetResponse) => {
            return userPasswordSetSuccess({
              res
            });
          }),
          catchError(error => of(userPasswordSetFailure({ error })))
        )
      )
    )
  );

  userPasswordSetSuccess$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(userPasswordSetSuccess),
        tap(async action => {
          await this.dialogService.open<
            AlertDialogComponent,
            AlertDialogData,
            AlertDialogResult
          >(AlertDialogComponent, {
            width: '360px',
            disableClose: true,
            data: {
              title: this.translateService.instant('accounts.changePassword'),
              message: this.translateService.instant(
                'accounts.results.changedPassword'
              )
            }
          });

          this.store.dispatch(logout());
        })
      );
    },
    { dispatch: false }
  );

  userPasswordSetFailure$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(userPasswordSetFailure),
        tap(action => {
          this.snackBarService.open(
            this.translateService.instant(
              'accounts.errors.failToChangePassword'
            ),
            '',
            {
              duration: 3000,
              verticalPosition: 'bottom'
            }
          );
        })
      );
    },
    { dispatch: false }
  );

  infoUser$ = createEffect(() =>
    this.actions$.pipe(
      ofType(infoUser),
      map(action => action.req),
      exhaustMap(req =>
        this.infoProtocolService.user(req).pipe(
          map((res: UserResponse) => {
            return infoUserSuccess({
              res
            });
          }),
          catchError(error => of(infoUserFailure({ error })))
        )
      )
    )
  );

  constructor(
    private actions$: Actions,
    private ngZone: NgZone,
    private router: Router,
    private store: Store<any>,
    private localStorageService: LocalStorageService,
    private sessionStorageService: SessionStorageService,
    private piService: PiService,
    private appAuthenticationService: AppAuthenticationService,
    private protocolService: ProtocolService,
    private authenticationProtocolService: AuthenticationProtocolService,
    private infoProtocolService: InfoProtocolService,
    private serviceProtocolService: ServiceProtocolService,
    private translateService: TranslateService,
    private dialogService: DialogService,
    private snackBarService: SnackBarService,
    @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
    private logger: NGXLogger,
    private daesangCipherService: DaesangCipherService
  ) {}
}
