/**
 * PushNotification Effects
 */
import {Injectable} from '@angular/core';
import {Actions, Effect, ofType} from '@ngrx/effects';
import {Store} from '@ngrx/store';
import {Observable} from 'rxjs/Observable';
import {of} from 'rxjs/observable/of';
import {catchError, map, mergeMap, switchMap} from 'rxjs/operators';
import {environment} from '../../environments/environment';
import {CoreAction} from '../app-store.domain';
import {<%= pascalCase(loginSubStorePluralName) %>Actions} from '../<%= paramCase(loginSubStorePluralName) %>/<%= paramCase(loginSubStorePluralName) %>.actions';
import {PushNotificationsActions} from './push-notifications.actions';
import {PushNotification} from './push-notifications.domain';
import {PushNotificationsService} from './push-notifications.service';

@Injectable()
export class PushNotificationsEffects {
  constructor(private actions$: Actions,
              private pushNotificationsService: PushNotificationsService,
              private store: Store<any>) {
  }

  @Effect()
  createOne$: Observable<CoreAction> = this.actions$.pipe(
    ofType(PushNotificationsActions.Type.CreateOneRemoteRequest),
    mergeMap((action: CoreAction) => {
      const { payload, token } = action;
      return this.pushNotificationsService.createOne(payload).pipe(
        switchMap((data: PushNotification) => [
          // Success Action
          new PushNotificationsActions.CreateOneRemoteSuccess(data, token),
          // Add the id and set to filed
          new PushNotificationsActions.UpdateOne(data),
          // Report the last success result to the view
          new PushNotificationsActions.ReportLastResult({ data, success: true, token }),
        ]),
        catchError((err: any) => {
          // Report the last failure result to the view
          this.store.dispatch(new PushNotificationsActions.ReportLastResult({ data: payload, success: false, token }));
          // Failure Action
          return of(new PushNotificationsActions.CreateOneRemoteFailure(err, token));
        }),
      );
    }),
  );

  @Effect()
  fetchAll$: Observable<CoreAction> = this.actions$.pipe(
    ofType(PushNotificationsActions.Type.FetchAllRemoteRequest),
    mergeMap((action: CoreAction) => {
      const { token } = action;
      return this.pushNotificationsService.fetchAll().pipe(
        switchMap((data: PushNotification[]) => [
          // Success Action
          new PushNotificationsActions.FetchAllRemoteSuccess(data, token),
          // Add the id and set to filed
          new PushNotificationsActions.AddAll(data),
          // Report the last success result to the view
          new PushNotificationsActions.ReportLastResult({ data, success: true, token }),
        ]),
        catchError((err: any) => {
          // Report the last failure result to the view
          this.store.dispatch(new PushNotificationsActions.ReportLastResult({ data: null, success: false, token }));
          // Failure Action
          return of(new PushNotificationsActions.FetchAllRemoteFailure(err, token));
        }),
      );
    }),
  );

  @Effect()
  fetchOne$: Observable<CoreAction> = this.actions$.pipe(
    ofType(PushNotificationsActions.Type.FetchOneRemoteRequest),
    mergeMap((action: CoreAction) => {
      const { payload, token } = action;
      return this.pushNotificationsService.fetchOne(payload).pipe(
        switchMap((data: PushNotification) => [
          // Success Action
          new PushNotificationsActions.FetchOneRemoteSuccess(data, token),
          // Add the id and set to filed
          new PushNotificationsActions.AddOne(data),
          // Report the last success result to the view
          new PushNotificationsActions.ReportLastResult({ data, success: true, token }),
        ]),
        catchError((err: any) => {
          // Report the last failure result to the view
          this.store.dispatch(new PushNotificationsActions.ReportLastResult({ data: null, success: false, token }));
          // Failure Action
          return of(new PushNotificationsActions.FetchOneRemoteFailure(err, token));
        }),
      );
    }),
  );

  @Effect()
  deleteUserTags$: Observable<CoreAction> = this.actions$.pipe(
    ofType(PushNotificationsActions.Type.DeleteUserTagsRequest),
    mergeMap(() => this.pushNotificationsService.deleteUserTags().pipe(
      map(() => new PushNotificationsActions.DeleteUserTagsSuccess()),
      catchError((err: any) => of(new PushNotificationsActions.DeleteUserTagsFailure(err))),
    )),
  );

  @Effect()
  init$: Observable<CoreAction> = this.actions$.pipe(
    ofType(PushNotificationsActions.Type.InitRequest),
    mergeMap(() => this.pushNotificationsService.init().pipe(
      map(() => new PushNotificationsActions.InitSuccess()),
      catchError((err: any) => of(new PushNotificationsActions.InitFailure(err)))
    )),
  );

  @Effect()
  mapSet<%= pascalCase(loginSubStoreName) %>Id$: Observable<CoreAction> = this.actions$.pipe(
    ofType(<%= pascalCase(loginSubStorePluralName) %>Actions.Type.SetCurrentId),
    map((action: CoreAction) => {
      const { payload } = action;
      const { pushEnvironment } = environment;
      return new PushNotificationsActions.SendUserTagsRequest([
        { key: 'agentId', value: payload },
        { key: 'pushEnvironment', value: pushEnvironment }
      ]);
    }),
  );

  @Effect()
  sendUserTags$: Observable<CoreAction> = this.actions$.pipe(
    ofType(PushNotificationsActions.Type.SendUserTagsRequest),
    mergeMap((action: CoreAction) => {
      const { payload } = action;
      return this.pushNotificationsService.sendUserTags(payload).pipe(
        map(() => new PushNotificationsActions.SendUserTagsSuccess(payload)),
        catchError((err: any) => of(new PushNotificationsActions.SendUserTagsFailure(err)))
      );
    }),
  );

  @Effect()
  subscribe: Observable<CoreAction> = this.actions$.pipe(
    ofType(PushNotificationsActions.Type.SubscribeRequest),
    mergeMap(() => {
      return this.pushNotificationsService.subscribe().pipe(
        map(() => new PushNotificationsActions.SubscribeSuccess()),
        catchError((err: any) => of(new PushNotificationsActions.SubscribeFailure(err)))
      );
    }),
  );

  @Effect()
  unsubscribe: Observable<CoreAction> = this.actions$.pipe(
    ofType(PushNotificationsActions.Type.UnsubscribeRequest),
    mergeMap(() => {
      return this.pushNotificationsService.unsubscribe().pipe(
        map(() => new PushNotificationsActions.UnsubscribeSuccess()),
        catchError((err: any) => of(new PushNotificationsActions.UnsubscribeFailure(err)))
      );
    }),
  );
}
