import * as log from "loglevel";
import { Subject } from "../observe/Observable";
import { Observer } from "../observe/Observer";
import { JsonAPI } from "../singleton/JsonAPI";
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
import { fetchErrorHandler } from "./FetchErrorHandler";
import { NotificationService } from "../../common/service/NotificationService";

export class UserModel implements Subject<ActiveUserViewModel> {
  /**
   * @type {Observer[]} List of subscribers. In real life, the list of
   * subscribers can be stored more comprehensively (categorized by event
   * type, etc.).
   */
  private readonly observers: Observer<ActiveUserViewModel>[] = [];

  private _activeUsersList: ActiveUserViewModel[] = Array();
  private readonly _notificationService: NotificationService;

  constructor(notificationService: NotificationService) {
    this._activeUsersList = [];
    this._notificationService = notificationService;
  }

  /**
   * Getter activeUsersList
   * @return {ActiveUserViewModel[] }
   */
  public get activeUsersList(): ActiveUserViewModel[] {
    return this._activeUsersList;
  }

  /**
   * The subscription management methods.
   */
  public attach(observer: Observer<ActiveUserViewModel>): void {
    log.info("Subject: Attached an observer.");
    this.observers.push(observer);
  }

  public detach(observer: Observer<ActiveUserViewModel>): void {
    const observerIndex = this.observers.indexOf(observer);
    this.observers.splice(observerIndex, 1);
    log.info("Subject: Detached an observer.");
  }

  /**
   * Trigger an update in each subscriber.
   */
  public notify(): void {
    log.info("Subject: Notifying observers...");
    for (const observer of this.observers) {
      observer.update({ data: this._activeUsersList!, op: "" });
    }
  }

  public someBusinessMethod(activeuserList: ActiveUserViewModel[]): void {
    this._activeUsersList = activeuserList;
    this.helperMethod();
    log.info(`Subject: My state has just changed`);
    log.trace(activeuserList);
    this.notify();
  }

  updateLastActive(username: String, lastActive: Date): void {
    this._activeUsersList
      .filter(u => u.userName == username)
      .forEach(u => u.lastActive = lastActive)
  }

  /**
   * getActiveUsers
   */
  public getActiveUsers(): void {
    if (JsonAPI.authToken != null) {
      this._getActiveUsersAjax(JsonAPI.authToken).then((data) => {
        // // activeUsers = data;
        // sessionStorage.setItem('activeUsers', JSON.stringify(data));
        // log.trace(sessionStorage.getItem('activeUsers'));
        log.info(`Subject: received ajax active users`);
        data.map((d: any) => {
          if (d.lastActive == null) return null;

          d.lastActive = new Date(d.lastActive);
          return d;
        });
        this._activeUsersList = data;
        this.notify();
      });
    } else {
      log.error("Auth token is null");
    }
  }

  private async _getActiveUsersAjax(authToken: string): Promise<any> {
    let headers = new Headers();
    headers.append("X-AUTH-TOKEN", authToken);
    let response = await fetch(JsonAPI.ACTIVE_USERS_GET, {
      method: "GET",
      headers: headers,
    });
    log.debug(response.clone());
    if (fetchErrorHandler(response.clone(), this._notificationService)) {
      return null;
    }
    let data = await response.json();
    // return data;
    return new Promise((resolve, reject) => {
      if (data != null) {
        resolve(data);
      } else reject("Response data null");
    });
  }

  private helperMethod() { }
}
