import { Injectable } from '@angular/core';
import { AppStorage } from '../app-storage';
import { AuthService } from '../server-services/auth.service';
import { editPushData } from '../server-services/querys';
import { CordovaService } from './cordova.service';
import { ServerRestApiService, WebSocketStatus } from './server-rest-api.service';

@Injectable({
  providedIn: 'root',
})
export class PushNotificationService {
  public static PUSH_FCM_TOKEN_STORAGE_KEY = 'pushFCMToken';
  public static LAST_PUSH_FCM_TOKEN_UPDATE_TIME_STORAGE_KEY = 'lastPushFCMTokenUpdateTime';
  public static TOKEN_EXPIRE_TIME_DISTANCE = 1000 * 60 * 60 * 24 * 7 * 3; // 3 weeks

  constructor(
    private cordovaService: CordovaService,
    private serverRestApi: ServerRestApiService,
    private authService: AuthService,
    private restApiService: ServerRestApiService
  ) {
    if (this.cordovaService.isOnApp()) {
      if (window['pushNotification']) {
        // Note: in the background ios can suspend the app and the connection
        // so we have to subscribe on the keyring loaded state
        // on android we have minutes before the suspend, so we can
        // check the cordova resume feature

        this.restApiService.subscribeOnWSConnected(() => {
          this.refreshToken();
        });

        // after resume
        document.addEventListener(
          'resume',
          () => {
            if (this.restApiService.isWebsocketConnected()) {
              //console.log('push noti token after resume cordova app');
              this.refreshToken();
            }
          },
          false
        );

        this.authService.onLogout(() => {
          this.resetToken();
        });

        /**
         * Android needs time to save session cookies
         * You can close the app right after login and you will lose these cookies
         * so after every login we should reset the token
         */
        this.authService.onLogin(() => {
          this.resetToken();
          this.refreshToken();
        });
      } else {
        console.error('Push not implementation is not found');
      }
    } else {
      console.warn('push noti is only supported on app');
    }
  }

  public refreshToken() {
    if (!this.authService.isAnonym()) {
      return window['pushNotification'].getToken().then((token) => {
        console.log('refresh token?');
        if (this.needToUpdateToken(token)) {
          console.log('yes, refresh token');
          return this.serverRestApi
            .mutate({
              query: editPushData,
              variables: {
                type: 'fcm',
                token,
              },
            })
            .then((res) => {
              console.log('push noti refresh resp', res);
              AppStorage.setItem(PushNotificationService.PUSH_FCM_TOKEN_STORAGE_KEY, token);
              AppStorage.setItem(
                PushNotificationService.LAST_PUSH_FCM_TOKEN_UPDATE_TIME_STORAGE_KEY,
                new Date().getTime() + ''
              );
              return true;
            })
            .catch((err) => {
              console.error('could not send token to refresh');
            });
        }
      });
    }
  }

  private needToUpdateToken(token): boolean {
    let savedToken = AppStorage.getItem(PushNotificationService.PUSH_FCM_TOKEN_STORAGE_KEY);
    let lastUpdateTimeString = AppStorage.getItem(
      PushNotificationService.LAST_PUSH_FCM_TOKEN_UPDATE_TIME_STORAGE_KEY
    );
    let lastUpdateTime;
    let timeDiff;
    if (lastUpdateTimeString) {
      lastUpdateTime = new Date(parseInt(lastUpdateTimeString));
      timeDiff = new Date().getTime() - lastUpdateTime.getTime();
    }

    return (
      token &&
      (token != savedToken ||
        !lastUpdateTime ||
        timeDiff > PushNotificationService.TOKEN_EXPIRE_TIME_DISTANCE)
    );
  }

  public resetToken() {
    console.log('reset fcm token');
    AppStorage.removeItem(PushNotificationService.PUSH_FCM_TOKEN_STORAGE_KEY);
    AppStorage.removeItem(PushNotificationService.LAST_PUSH_FCM_TOKEN_UPDATE_TIME_STORAGE_KEY);
  }
}
