import { Injectable } from '@angular/core';
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
import { environment } from '@msfa-environment';
import { BehaviorSubject, fromEvent, merge, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { AuthenticationService } from './api/authentication.service';

@Injectable({
  providedIn: 'root',
})
export class IdleService extends UnsubscribeDirective {
  private _eventsArray$: Observable<Event>[] = [
    fromEvent(document, 'click'),
    fromEvent(document, 'wheel'),
    fromEvent(document, 'mousemove'),
    fromEvent(document, 'touchstart'),
    fromEvent(document, 'keyup'),
    fromEvent(window, 'resize'),
    fromEvent(window, 'scroll'),
  ];
  private _allEvents$ = merge(...this._eventsArray$);
  private _isIdle$ = new BehaviorSubject<boolean>(false);
  public isIdle$: Observable<boolean> = this._isIdle$.asObservable();
  private _isActive$ = new BehaviorSubject<boolean>(true);
  private _idleAfterMS = environment.idle.idleAfterMS;
  private _autoLogoutAfterMS = environment.idle.logoutAfterMS;
  private _timeLeftBeforeLogoutInMS$ = new BehaviorSubject<number>(this._autoLogoutAfterMS);

  private _idleTimeout;
  private _autoLogoutTimeout;
  private _autoLogoutInterval;

  constructor(private authenticationService: AuthenticationService) {
    super();
    super.unsubscribeOnDestroy(
      this._allEvents$.subscribe(() => {
        this._setNewTimeoutIfActive();
      })
    );
    this._setNewTimeoutIfActive();
  }

  private _setNewTimeoutIfActive(): void {
    if (this._isActive$.getValue() && this.authenticationService.isLoggedInWithValidToken) {
      this._clearTimeouts();
      this._setIdleTimeout();
    }
  }

  private _setIdleTimeout(): void {
    this._idleTimeout = setTimeout(() => {
      this._isActive$.next(false);
      this._isIdle$.next(true);
      this._setAutoLogoutTimeout();
    }, this._idleAfterMS);
  }

  private _setAutoLogoutTimeout(): void {
    this._autoLogoutTimeout = setTimeout(() => {
      this.authenticationService.logout();
    }, this._autoLogoutAfterMS);

    this._autoLogoutInterval = setInterval(() => {
      const currentTimeLeft = this._timeLeftBeforeLogoutInMS$.getValue();
      this._timeLeftBeforeLogoutInMS$.next(currentTimeLeft - 1000);
    }, 1000);
  }

  private _clearTimeouts(): void {
    clearTimeout(this._autoLogoutTimeout);
    clearTimeout(this._idleTimeout);
    clearInterval(this._autoLogoutInterval);
    this._timeLeftBeforeLogoutInMS$.next(this._autoLogoutAfterMS);
  }

  public setActive(): void {
    this._isIdle$.next(false);
    this._isActive$.next(true);
    this._clearTimeouts();
    this._setIdleTimeout();
  }

  public get timeLeftBeforeLogout$(): Observable<string> {
    return this._timeLeftBeforeLogoutInMS$.pipe(
      map(timeLeftInMS => {
        const timeLeftInSeconds = timeLeftInMS / 1000;
        const minutes = Math.floor(timeLeftInSeconds / 60);
        const seconds = timeLeftInSeconds - minutes * 60;

        return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
      })
    );
  }
}
