import { Injectable } from '@angular/core';

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

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

import { NGXLogger } from 'ngx-logger';

import { of } from 'rxjs';
import { switchMap, map, catchError, withLatestFrom } from 'rxjs/operators';

import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { KEY_ENVIRONMENTS_INFO } from './../../../types/environment.type';
import { EnvironmentsInfo } from '@app/types';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { MessageStatusCode } from '@ucap-webmessenger/api';
import { DialogService } from '@ucap-webmessenger/ui';
import {
  retrieveMessage,
  retrieveMessageFailure,
  retrieveMessageSuccess,
  searchMessage,
  searchMessageSuccess,
  searchMessageFailure,
  retrieveUnreadCount,
  retrieveUnreadCountSuccess,
  retrieveUnreadCountFailure,
  deleteMessage,
  deleteMessageSuccess,
  deleteMessageFailure,
  cancelReservationMessage,
  cancelReservationMessageSuccess,
  cancelReservationMessageFailure,
  detailMessage,
  detailMessageFailure,
  detailMessageSuccess
} from './actions';
import {
  MessageApiService,
  RetrieveRequest,
  MessageType,
  RetrieveSearchRequest,
  MessageSearchType,
  DelRequest,
  CancelReservationRequest,
  DetailRequest,
  UnreadCountRequest
} from '@ucap-webmessenger/api-message';

@Injectable()
export class Effects {
  detailMessage$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(detailMessage),
        withLatestFrom(
          this.store.pipe(
            select(
              (state: any) =>
                state.account.authentication.loginRes as LoginResponse
            )
          )
        ),
        switchMap(([req, loginResInfo]) => {
          const environmentsInfo = this.sessionStorageService.get<
            EnvironmentsInfo
          >(KEY_ENVIRONMENTS_INFO);

          const request: DetailRequest = {
            userSeq: loginResInfo.userSeq,
            deviceType: environmentsInfo.deviceType,
            tokenKey: loginResInfo.tokenString,
            type: req.messageType,
            msgId: req.msgId
          };
          return this.messageApiService.detailMessage(request).pipe(
            map(res => {
              this.store.dispatch(
                detailMessageSuccess({
                  res
                })
              );
            }),
            catchError(error => of(detailMessageFailure({ error })))
          );
        })
      );
    },
    { dispatch: false }
  );

  retrieveUnreadCount$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(retrieveUnreadCount),
        withLatestFrom(
          this.store.pipe(
            select(
              (state: any) =>
                state.account.authentication.loginRes as LoginResponse
            )
          )
        ),
        switchMap(([req, loginResInfo]) => {
          // const loginResInfo: LoginResponse = this.sessionStorageService.get<
          //   LoginResponse
          // >(KEY_LOGIN_RES_INFO);
          const environmentsInfo = this.sessionStorageService.get<
            EnvironmentsInfo
          >(KEY_ENVIRONMENTS_INFO);

          const request: UnreadCountRequest = {
            userSeq: loginResInfo.userSeq,
            deviceType: environmentsInfo.deviceType,
            tokenKey: loginResInfo.tokenString
          };
          return this.messageApiService.retrieveUnreadCount(request).pipe(
            map(res => {
              if (res.responseCode === MessageStatusCode.Success) {
                this.store.dispatch(
                  retrieveUnreadCountSuccess({
                    count: res.unreadCount
                  })
                );
              }
            }),
            catchError(error => of(retrieveUnreadCountFailure({ error })))
          );
        })
      );
    },
    { dispatch: false }
  );

  retrieveMessage$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(retrieveMessage),
        withLatestFrom(
          this.store.pipe(
            select(
              (state: any) =>
                state.account.authentication.loginRes as LoginResponse
            )
          )
        ),
        switchMap(([req, loginResInfo]) => {
          const environmentsInfo = this.sessionStorageService.get<
            EnvironmentsInfo
          >(KEY_ENVIRONMENTS_INFO);

          const request: RetrieveRequest = {
            userSeq: loginResInfo.userSeq,
            deviceType: environmentsInfo.deviceType,
            tokenKey: loginResInfo.tokenString,
            type: req.messageType,
            pageSize: !!req.pageSize ? req.pageSize : 1000,
            pageCount: !!req.pageCount ? req.pageCount : 0
          };

          switch (req.messageType) {
            case MessageType.Receive: {
              return this.messageApiService
                .retrieveReceiveMessage(request)
                .pipe(
                  map(res => {
                    if (res.responseCode === MessageStatusCode.Success) {
                      this.store.dispatch(
                        retrieveMessageSuccess({
                          res,
                          messageType: req.messageType
                        })
                      );
                    }
                  }),
                  catchError(error => of(retrieveMessageFailure({ error })))
                );
            }
            case MessageType.Send: {
              return this.messageApiService.retrieveSendMessage(request).pipe(
                map(res => {
                  if (res.responseCode === MessageStatusCode.Success) {
                    this.store.dispatch(
                      retrieveMessageSuccess({
                        res,
                        messageType: req.messageType
                      })
                    );
                  }
                }),
                catchError(error => of(retrieveMessageFailure({ error })))
              );
            }
            case MessageType.Reservation: {
              return this.messageApiService
                .retrieveReservationMessage(request)
                .pipe(
                  map(res => {
                    if (res.responseCode === MessageStatusCode.Success) {
                      this.store.dispatch(
                        retrieveMessageSuccess({
                          res,
                          messageType: req.messageType
                        })
                      );
                    }
                  }),
                  catchError(error => of(retrieveMessageFailure({ error })))
                );
            }
          }
        })
      );
    },
    { dispatch: false }
  );

  searchMessage$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(searchMessage),
        withLatestFrom(
          this.store.pipe(
            select(
              (state: any) =>
                state.account.authentication.loginRes as LoginResponse
            )
          )
        ),
        switchMap(([req, loginResInfo]) => {
          const environmentsInfo = this.sessionStorageService.get<
            EnvironmentsInfo
          >(KEY_ENVIRONMENTS_INFO);

          const request: RetrieveRequest = {
            userSeq: loginResInfo.userSeq,
            deviceType: environmentsInfo.deviceType,
            tokenKey: loginResInfo.tokenString,
            type: req.messageType,
            pageSize: !!req.pageSize ? req.pageSize : 1000,
            pageCount: !!req.pageCount ? req.pageCount : 0
          };

          return this.messageApiService
            .retrieveSearchMessage({
              ...request,
              searchTitle:
                req.searchType === MessageSearchType.Title ? req.searchStr : '',
              searchName:
                req.searchType === MessageSearchType.Name ? req.searchStr : '',
              searchContent:
                req.searchType === MessageSearchType.Contents
                  ? req.searchStr
                  : ''
            } as RetrieveSearchRequest)
            .pipe(
              map(res => {
                if (res.responseCode === MessageStatusCode.Success) {
                  this.store.dispatch(
                    searchMessageSuccess({
                      res,
                      messageType: req.messageType
                    })
                  );
                }
              }),
              catchError(error => of(searchMessageFailure({ error })))
            );
        })
      );
    },
    { dispatch: false }
  );

  deleteMessage$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(deleteMessage),
        withLatestFrom(
          this.store.pipe(
            select(
              (state: any) =>
                state.account.authentication.loginRes as LoginResponse
            )
          )
        ),
        switchMap(([action, loginResInfo]) => {
          const environmentsInfo = this.sessionStorageService.get<
            EnvironmentsInfo
          >(KEY_ENVIRONMENTS_INFO);

          const request: DelRequest = {
            userSeq: loginResInfo.userSeq,
            deviceType: environmentsInfo.deviceType,
            tokenKey: loginResInfo.tokenString,
            type: action.messageType,
            msgList: action.msgList
          };

          return this.messageApiService.deleteMessage(request).pipe(
            map(res => {
              if (res.responseCode === MessageStatusCode.Success) {
                this.store.dispatch(
                  deleteMessageSuccess({
                    messageType: action.messageType,
                    msgList: action.msgList
                  })
                );
              }
            }),
            catchError(error => of(deleteMessageFailure({ error })))
          );
        })
      );
    },
    { dispatch: false }
  );

  cancelReservationMessage$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(cancelReservationMessage),
        withLatestFrom(
          this.store.pipe(
            select(
              (state: any) =>
                state.account.authentication.loginRes as LoginResponse
            )
          )
        ),
        switchMap(([action, loginResInfo]) => {
          const environmentsInfo = this.sessionStorageService.get<
            EnvironmentsInfo
          >(KEY_ENVIRONMENTS_INFO);

          const request: CancelReservationRequest = {
            userSeq: loginResInfo.userSeq,
            deviceType: environmentsInfo.deviceType,
            tokenKey: loginResInfo.tokenString,
            type: action.messageType,
            msgId: action.msgId
          };

          return this.messageApiService.cancelReservationMessage(request).pipe(
            map(res => {
              if (res.responseCode === MessageStatusCode.Success) {
                this.store.dispatch(
                  cancelReservationMessageSuccess({
                    messageType: action.messageType,
                    msgId: action.msgId
                  })
                );
              }
            }),
            catchError(error => of(cancelReservationMessageFailure({ error })))
          );
        })
      );
    },
    { dispatch: false }
  );

  constructor(
    private actions$: Actions,
    private store: Store<any>,
    private messageApiService: MessageApiService,
    private sessionStorageService: SessionStorageService,
    private dialogService: DialogService,
    private logger: NGXLogger
  ) {}
}
