import { Observer } from "../observe/Observer";
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
import { ChatModel } from "../model/ChatModel";
import log = require("loglevel");
import * as DOMPurify from "dompurify";
import { SearchService } from "../../common/service/SearchService";
import { UserModel } from "../model/UserModel";
import { UserViewDeps } from "./UserViewDeps";
import { ObserverData } from "../observe/ObserverData";
import { JsonAPI } from "../singleton/JsonAPI";
import { NotificationService } from "../../common/service/NotificationService";
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";

export class UserView implements Observer<ActiveUserViewModel> {
  private readonly _model: UserModel;
  private readonly _chatModel: ChatModel;
  private readonly _usersListElement: HTMLElement;
  private readonly _userSearchInputElement: HTMLInputElement;
  private readonly _userSearchButton: HTMLElement;
  private readonly _userSearchCancelButton: HTMLElement;
  private readonly _searchService: SearchService<ActiveUserViewModel>;
  private readonly _userContactOnlineTemplate: Handlebars.TemplateDelegate<
    ActiveUserViewModel
  >;
  private readonly _userContactOfflineTemplate: Handlebars.TemplateDelegate<
    ActiveUserViewModel
  >;
  private readonly _notificationService: NotificationService;
  private _newMessagesLoop: any;

  constructor(deps: UserViewDeps) {
    this._model = deps.model;
    this._chatModel = deps.chatModel;
    this._usersListElement = deps.usersListElement;
    this._userSearchInputElement = deps.userSearchInputElement;
    this._userSearchButton = deps.userSearchButton;
    this._userSearchCancelButton = deps.userSearchCancelButton;
    this._searchService = deps.searchService;
    this._userContactOnlineTemplate = deps.userContactOnlineTemplate;
    this._userContactOfflineTemplate = deps.userContactOfflineTemplate;
    this._notificationService = deps.notificationService;

    this._addSearchEventListeners();
  }

  update(d: ObserverData<ActiveUserViewModel>): void {
    let html: string = "";
    d.data.forEach((element: ActiveUserViewModel) => {
      element.online
        ? (html += this._userContactOnlineTemplate(element))
        : (html += this._userContactOfflineTemplate(element));
    });
    $(this._usersListElement).html(DOMPurify.sanitize(html));
    this._addUserCallBacks();
  }

  private _addSearchEventListeners(): void {
    this._addSearchButtonEL();
    this._addSearchCancelEL();
    this._addSearchInputEL();
  }

  private _addUserCallBacks(): void {
    let userBoxes = document.getElementsByClassName("user-box");

    Array.from(userBoxes).forEach((ub: Element) =>
      ub.addEventListener("click", this._userCallBack.bind(this, ub))
    );
  }

  private _userCallBack(el: Element): void {
    this._chatModel.clear();
    clearInterval(this._newMessagesLoop);
    let current = document.getElementsByClassName("user-box active");

    if (current.length > 0) {
      current[0].className = current[0].className.replace(" active", "");
    }
    // Add the active class to the current/clicked button
    else if (current.length == 0) {
      // @ts-ignore: Object is possibly 'null'.
      document.getElementById("no-user-selected").hidden = true;
      // @ts-ignore: Object is possibly 'null'.
      document.getElementById("chat-card").hidden = false;
    }
    // console.log(this.getElementsByClassName('to-user-span'));
    let elem = el.getElementsByClassName("to-user-span")[0] as HTMLElement;
    let userName = elem.innerText;
    JsonAPI.contactName = userName;
    // @ts-ignore: Object is possibly 'null'.
    document.getElementById("user-name-span").innerText = userName;
    let currentUser = this._model.activeUsersList.find((vm) => vm.userName === userName) || new ActiveUserViewModel();
    currentUser.userName = userName;

    if (!currentUser?.passphrase) {
      this._notificationService.passphrasePrompt(
        async (result) => {
          if (result) {

            const valid = await this._chatModel.isPassphraseValid(result, currentUser.userName!);
            if (!valid) {
              bootbox.alert("Some error occured. Please check your password");
              log.error("invalid password");
              return;
            }
            currentUser.unlocked = true;
            currentUser.passphrase = result;
            const chatMessages: ChatMessageViewModel[] = await this._chatModel.getMessages(currentUser, "new");

            this._model.activeUsersList
              .filter((v) => v.userName == currentUser!.userName)
              .forEach((v) => {
                v.passphrase = result;
                v.unlocked = true;
                if (chatMessages.length > 0) {
                  v.lastMessageTime = new Date(
                    chatMessages[chatMessages.length - 1].messageTime
                  );
                  const lastMessageText = (v.lastMessageText =
                    chatMessages[chatMessages.length - 1].message);
                  if (lastMessageText.length > 15) {
                    v.lastMessageText =
                      chatMessages[chatMessages.length - 1].message.slice(
                        0,
                        15
                      ) + "...";
                  }
                }
              });
            this._promptHandler(currentUser);

          }
        }
      );
    }
    else {
      this._chatModel.getMessages(currentUser, "new");
    }

    el.className += " active";
    if (currentUser.unlocked && currentUser.lastMessageTime) {
      this._newMessagesLoop = setInterval(
        this._chatModel.getMessages.bind(this._chatModel, currentUser, "update"),
        10_000
      );
      this._model.notify();
    }
  }

  private _promptHandler(vm: ActiveUserViewModel) {
    // vms.filter(v => v.userName == vm.userName).map(v => v.userName = vm.userName)
    // log.debug(vms);

    if (vm.lastMessageTime) {
      this._newMessagesLoop = setInterval(
        this._chatModel.getMessages.bind(this._chatModel, vm, "update"),
        10_000
      );
      this._model.notify();
    }
  }

  private _addSearchButtonEL() {
    this._userSearchButton.addEventListener("submit", (e) => {
      e.preventDefault();
      // log.trace(temp);
      const searchTerm = this._userSearchInputElement.value;
      if (searchTerm.length > 0) {
        log.debug("search term value = " + searchTerm);
        const list = this._model.activeUsersList;
        log.debug("active users");
        log.debug(list);
        if (!list) {
          log.error("Users list is null");
          return;
        }
        let searchResult = this._searchService.search(list, searchTerm);
        this.update({ data: searchResult, op: "" });
        log.debug(searchResult);
      }
      else {
        this._notificationService.error("Please enter a name")
      }
    });
  }

  private _addSearchInputEL() {
    this._userSearchInputElement.addEventListener("input", (e) => {
      e.preventDefault();
      if (this._userSearchInputElement.value.length < 2) {
        this._userSearchCancelButton.hidden = false;
      }
    });
  }

  private _addSearchCancelEL() {
    this._userSearchCancelButton.addEventListener("click", (e) => {
      e.preventDefault();
      this._userSearchInputElement.value = "";
      this._userSearchCancelButton.hidden = true;
      let list = this._model.activeUsersList;
      this.update({ data: list, op: "" });
    });
  }
}
