/**
 * <%= pascalCase(singularDomainName) %> Service
 */
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {OneSignal, OSNotification, OSNotificationOpenedResult, OSPermissionSubscriptionState} from '@ionic-native/onesignal';
import {Store} from '@ngrx/store';
import {getISOTimestamp, isPropertyDefined} from '@zionapps/core';
import {Observable} from 'rxjs/Observable';
import {fromPromise} from 'rxjs/observable/fromPromise';
import {environment} from '../../../environments/environment';
import {PushNotification, PushNotificationTag} from './push-notifications.domain';
import {PushNotificationsActions} from './push-notifications.actions';

@Injectable()
export class <%= pascalCase(pluralDomainName) %>Service {
readonly endpoint = environment.<%= camelCase(baseUri) %> + '/<%= paramCase(pluralDomainName) %>';

  constructor(private http: HttpClient,
              private oneSignal: OneSignal,
              private store: Store<any>) {
  }

  /**
   * Asynchronous Remote Service Methods
   */

  createOne(payload: <%= pascalCase(singularDomainName) %>): Observable<<%= pascalCase(singularDomainName) %>> {
    return this.http.post<<%= pascalCase(singularDomainName) %>>(this.endpoint, payload);
  }

  deleteUserTags(): Observable<void> {
    return fromPromise(new Promise((resolve, reject) => {
      try {
        setTimeout(() => {
          this.oneSignal.deleteTags(['agent_id', 'push_environment']);
          resolve();
        }, 0);
      } catch (e) {
        console.error(e);
        reject(e);
      }
    }));
  }

  fetchAll(): Observable<<%= pascalCase(singularDomainName) %>[]> {
    return this.http.get<<%= pascalCase(singularDomainName) %>[]>(this.endpoint);
  }

  fetchOne(id: number): Observable<<%= pascalCase(singularDomainName) %>> {
    return this.http.get<<%= pascalCase(singularDomainName) %>>(`${this.endpoint}/${id.toString()}`);
  }

  init(): Observable<void> {
    return fromPromise(new Promise((resolve, reject) => {
      try {
        this.oneSignal.startInit(environment.oneSignalAppId, environment.googleProjectNumber);

        if (!environment.production) {
          this.oneSignal.setLogLevel({
            logLevel: 6, // Verbose
            visualLevel: 3, // Warnings
          });
        }

        this.oneSignal.inFocusDisplaying(this.oneSignal.OSInFocusDisplayOption.Notification);

        this.oneSignal.handleNotificationReceived().subscribe((notification: OSNotification) => {
          // do something when notification is received
          console.log('OSNotification', notification);
          if (notification) {
            this.savePushNotification(notification);
          }
        });

        this.oneSignal.handleNotificationOpened().subscribe((result: OSNotificationOpenedResult) => {
          // do something when a notification is opened
          const { notification } = result;
          console.log('Notification Opened', notification);
          if (notification) {
            this.savePushNotification(notification);
          }
        });

        this.oneSignal.endInit();
        resolve();
      } catch (e) {
        reject(e);
      }
    }));
  }

  sendUserTags(tags: PushNotificationTag[]): Observable<void> {
    return fromPromise(new Promise((resolve, reject) => {
      try {
        this.oneSignal.getTags().then((currentTags: any) => {
          tags.forEach((tag: PushNotificationTag) => {
            this.sendSingleTag(currentTags, tag.key, tag.value);
          });
          // this.sendSingleTag(currentTags, 'agent_id', strAgentId);
          // this.sendSingleTag(currentTags, 'push_environment', pushEnvironment);
          resolve();
        }).catch((err: any) => reject(err));
      } catch (e) {
        reject(e);
      }
    }));
  }

  subscribe(): Observable<void> {
    try {
      return fromPromise(new Promise((resolve) => {
          setTimeout(() => {
            this.oneSignal.getPermissionSubscriptionState().then((state: OSPermissionSubscriptionState) => {
              if (isPropertyDefined(state, 'subscriptionStatus')) {
                const { subscribed } = state.subscriptionStatus;
                if (!subscribed) {
                  this.oneSignal.setSubscription(true);
                }
                resolve();
              } else {
                this.oneSignal.setSubscription(true);
                resolve();
              }
            });
          }, 0);
        }));
    } catch (e) {
      return fromPromise(Promise.reject(e));
    }
  }

  unsubscribe(): Observable<void> {
    try {
      return fromPromise(new Promise((resolve) => {
        setTimeout(() => {
          this.oneSignal.setSubscription(false);
          resolve();
        }, 0);
      }));
    } catch (e) {
      return fromPromise(Promise.reject(e));
    }
  }

  private savePushNotification(notification: OSNotification): void {
      const { payload } = notification;
    if (payload) {
      const {
        additionalData: {
          push_environment,
          push_type
        },
        body,
        fromProjectNumber,
        launchURL,
        lockScreenVisibility,
        notificationID,
        priority,
        title,
      } = payload;
      this.store.dispatch(new PushNotificationsActions.AddOne({
        body,
        fromProjectNumber,
        launchURL,
        lockScreenVisibility,
        priority,
        title,
        id: notificationID,
        pushNotificationEnvironment: push_environment,
        pushNotificationType: push_type,
        sent: false,
        timestamp: getISOTimestamp(),
      }));
    }
  }

  private sendSingleTag(currentTags: any, key: string, value: string): void {
      if (!!value && (!!currentTags || (!!currentTags[key] && currentTags[key] !== value))) {
      this.oneSignal.sendTag(key, value);
    }
  }
}
