import log from "loglevel";
import { ChatMessageDTO } from "../../common/dto/ChatMessageDTO";
import { NotificationService } from "../../common/service/NotificationService";
import { Subject } from "../observe/Observable";
import { Observer } from "../observe/Observer";
import { JsonAPI } from "../singleton/JsonAPI";
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
import { fetchErrorHandler } from "./FetchErrorHandler";
import { EncryptionService } from "../../common/service/EncryptionService";
import { createApiHeaders } from "../../common/ajax/util";
import { getActiveUsers } from "../../common/ajax/Users";

export interface Props {
  encryptionService: EncryptionService;
  notificationService: NotificationService;
  authToken: string;
}
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 readonly _activeUsersList: ActiveUserViewModel[] = Array();
  private readonly _props: Props;

  constructor(props: Props) {
    this._activeUsersList = [];
    this._props = props;

    getActiveUsers(props.authToken).then((data) => {
      log.debug(data);
      this._activeUsersList.push(...data);
      this.notify();
    });
  }

  /**
   * 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: "" });
    }
  }

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

  public decryptForUser(dto: ChatMessageDTO, userName: string): string {
    const passphrase =
      this._activeUsersList.find((u) => u.userName === userName)?.passphrase ||
      "";
    return this._props.encryptionService.decrypt(passphrase, dto.messageCipher);
  }
}
