/**
 * @mergeTarget
 * @module Src/Controllers
 */

import { LocalStorageController } from "./storages/local-storage-controller";
import { ExtensionStorageController } from "./storages/extension-storage-controller";
import { StatisticsController } from "./statistics-controller";
import { CookieController } from "./storages/cookie-controller";
import { CompressorController } from "./compressor-controller";
import { MessageManager } from "../managers/message-manager";
import { CustomChoice } from "../render/components/inputs/choice/custom-choice";
import { CustomTextInput } from "../render/components/inputs/text/custom-text-input";
import {
  LisioUser,
  StorageController,
  LisioUserParsed,
  LisioParameterNames,
  LisioParameter,
  LisioParameterFactory,
  LisioProfileFactory,
  LisioBooleanParameterNames,
  LisioStringParameterNames,
  LisioNumericParameterNames,
  LisioProfileNames,
} from "@lisio/lisio-profils";
import { HomeScreen } from "../render/screens/home/home-screen";
import { CoreErrorCodes, LisioComponent } from "@lisio/lisio-engine";
import { UsersScreen } from "../render/screens/users/users-screen";
import {
  ScreenNames,
  VisualCategoryNames,
} from "../render/screens/screen-types";
import { InputManager } from "../managers/input-manager";
import { CustomButton } from "../render/components/custom-button/custom-button";
import { ScreenManager } from "../managers/screen-manager";
import { ManagementScreen } from "../render/screens/management/management-screen";

const isFirefoxOrSafari =
  /safari|firefox/.test(navigator.userAgent.toLowerCase()) &&
  !navigator.userAgent.toLowerCase().includes("chrome");

/**
 * Class representing an user controller.\
 * It aims to centralize the logic and operation on user and users.\
 * If something need to do anything related with user or users it has to use this class.\
 * To execute his responsability this class does several things :
 *  * Compress and encodes stored datas revelant to users
 *  * Decompress and encodes stored datas revelant to users
 */
class UserController {
  /**
   * Private attribute to store next user number
   * @source
   */
  private _nextUserNumber: number = 1;

  /**
   * Private attribute to store current user selected from storage
   * @source
   */
  private _currentUser?: LisioUser;

  /**
   * Private attribute to store all users from storage
   * @source
   */
  private _users: Map<string, LisioUser> = new Map<string, LisioUser>();

  /**
   * Private attribute to store all usernames from storage
   * @source
   */
  private _usernames: string[] = [];

  /**
   * Private attribute to store HTML element containing enabled switch and reset category
   * @source
   */
  private _activationGroup?: LisioComponent;

  /**
   * Private attribute to store HTML element containing users management category
   * @source
   */
  private _userGroup?: LisioComponent;

  /**
   * Private attribute to store HTML element containing choice list of all users
   * @source
   */
  private _usersList?: CustomChoice;

  /**
   * Private attribute to store HTML input element to renaming user
   * @source
   */
  private _userRenameInput?: CustomTextInput;

  /**
   * Private attribute to store delete user button
   * @source
   */
  private _deleteButton?: CustomButton;

  /**
   * Private attribute to store management screen header button
   * @source
   */
  private _managementButton?: CustomButton;

  /**
   * Private attribute to store all storage controller
   * @source
   */
  private _storageControllers: StorageController[] = [];

  /**
   * Getter for attribute {@link _currentUser | _currentUser}
   * @returns Returns _currentUser attribute
   * @source
   */
  public get currentUser(): LisioUser | undefined {
    return this._currentUser;
  }

  /**
   * Getter for attribute {@link _users | _users}
   * @returns Returns _users attribute
   * @source
   */
  public get users(): Map<string, LisioUser> {
    return this._users;
  }

  /**
   * Getter for attribute {@link _usernames | _usernames}
   * @returns Returns _usernames attribute
   * @source
   */
  public get usernames(): string[] {
    return this._usernames;
  }

  /**
   * Getter for attribute {@link _storageControllers | _storageControllers}
   * @returns Returns _storageControllers attribute
   * @source
   */
  public get storageControllers(): StorageController[] {
    return this._storageControllers;
  }

  /**
   * Getter for attribute {@link _userGroup | _userGroup}
   * @returns Returns _userGroup attribute
   * @source
   */
  public get userGroup(): LisioComponent | undefined {
    return this._userGroup;
  }

  /**
   * Setter for attribute {@link _activationGroup | _activationGroup}
   * @param {LisioComponent} value - HTML element containing enabled switch and reset category
   * @returns Returns nothing
   * @source
   */
  public set activationGroup(value: LisioComponent) {
    this._activationGroup = value;
  }

  /**
   * Setter for attribute {@link _userGroup | _userGroup}
   * @param {LisioComponent} value - HTML element containing users management category
   * @returns Returns nothing
   * @source
   */
  public set userGroup(value: LisioComponent) {
    this._userGroup = value;
  }

  /**
   * Setter for attribute {@link _usersList | _usersList}
   * @param {LisioComponent} value - HTML element containing choice list of all users
   * @returns Returns nothing
   * @source
   */
  public set usersList(value: CustomChoice) {
    this._usersList = value;
  }

  /**
   * Setter for attribute {@link _userRenameInput | _userRenameInput}
   * @param {LisioComponent} value - HTML input element to renaming user
   * @returns Returns nothing
   * @source
   */
  public set userRenameInput(value: CustomTextInput) {
    this._userRenameInput = value;
  }

  /**
   * Setter for attribute {@link _deleteButton | _deleteButton}
   * @param {CustomButton} value - Button for user deletion
   * @returns Returns nothing
   * @source
   */
  public set deleteButton(value: CustomButton) {
    this._deleteButton = value;
  }

  /**
   * Setter for attribute {@link _managementButton | _managementButton}
   * @param {CustomButton} value - Button that opens the lanagement screen
   * @returns Returns nothing
   * @source
   */
  public set managementButton(value: CustomButton) {
    this._managementButton = value;
  }

  /**
   * Private attribute to store instance of {@link UserController | UserController}
   * @source
   */
  private static _current: UserController;

  /**
   * @static
   * Getter for attribute {@link _current | _current}
   * @returns Returns _current attribute
   * @source
   */
  public static get current(): UserController {
    return UserController._current;
  }

  /**
   * Public method to unparse parsed user. This method converts parameter array as a map
   * @param {LisioUserParsed} parsedUser - Parsed user from storage
   * @returns Retuns an unparsed user
   * @source
   */
  public unparseUser(parsedUser: LisioUserParsed): LisioUser {
    const parameterMap: Map<LisioParameterNames, LisioParameter> = new Map<
      LisioParameterNames,
      LisioParameter
    >(
      parsedUser.customParameters.map((customParameter) => [
        customParameter.name,
        LisioParameterFactory.current.buildLisioParameter(
          customParameter.name,
          customParameter.value as string | number | boolean,
        ),
      ]),
    );

    return new LisioUser(
      parsedUser.name,
      parsedUser.isSelected,
      parameterMap,
      parsedUser.profiles,
    );
  }

  /**
   * Public method to switch the selected user to a new one designated by his username.
   * @param {string} username - The username of new selected user
   * @returns Retuns a promise containing nothing
   * @source
   */
  public async switchSelectedUser(username: string): Promise<void> {
    InputManager.current.disableAll(false);
    if (this._users.get(username) == undefined) {
      return;
    }
    if (
      this._currentUser != undefined &&
      this._users.has(this._currentUser.name)
    ) {
      this._users.get(this._currentUser.name)!.isSelected = false;
    }
    const isSameUsername = this._currentUser?.name == username;
    let lastUser: LisioUser | undefined = this._currentUser;
    for (const storageController of this._storageControllers) {
      if (this._currentUser == undefined || !isSameUsername) {
          lastUser = await storageController.switchSelectedUser(username);
      }
    }
    this.setCurrentUser(lastUser);
    if (this._currentUser == undefined) {
      return;
    }
    this._users.get(username)!.isSelected = true;
    this._userRenameInput?.setValue(username);
    this._currentUser.customParameters.set(
      LisioBooleanParameterNames.IS_ACTIVE,
      LisioParameterFactory.current.buildLisioParameter(
        LisioBooleanParameterNames.IS_ACTIVE,
        true,
      ),
    );
    InputManager.current.refreshInputs(
      this._currentUser.profiles,
      Array.from(this._currentUser.customParameters.values()),
    );
  }

  /**
   * Public method to remove all parameters or profiles related to book page and notify client script to deactive all adaptions related to these profiles.
   * @returns Retuns nothing
   * @source
   */
  public disableAllBookPageOrReading(): void {
    if (this._currentUser != undefined) {
      for (const profilName of this._currentUser?.profiles) {
        const profile =
          LisioProfileFactory.current.buildLisioProfile(profilName);
        if (
          profile.parameters.has(LisioBooleanParameterNames.BOOK_PAGE) ||
          this._currentUser.customParameters.has(
            LisioBooleanParameterNames.READING_MODE,
          )
        ) {
          this.updateUserBoolean(profile.name, false);
          MessageManager.current.profileAdaptMessage(profilName, false);
        }
      }

      if (
        this._currentUser.customParameters.has(
          LisioStringParameterNames.UNDERLINE_RED,
        )
      ) {
        this.updateUserString(
          LisioStringParameterNames.UNDERLINE_RED,
          "",
          true,
        );
      }
      if (
        this._currentUser.customParameters.has(
          LisioStringParameterNames.UNDERLINE_GREEN,
        )
      ) {
        this.updateUserString(
          LisioStringParameterNames.UNDERLINE_GREEN,
          "",
          true,
        );
      }
      if (
        this._currentUser.customParameters.has(
          LisioStringParameterNames.UNDERLINE_BLUE,
        )
      ) {
        this.updateUserString(
          LisioStringParameterNames.UNDERLINE_BLUE,
          "",
          true,
        );
      }
      if (
        this._currentUser.customParameters.has(
          LisioBooleanParameterNames.BOOK_PAGE,
        ) ||
        this._currentUser.customParameters.has(
          LisioBooleanParameterNames.READING_MODE,
        )
      ) {
        this.updateUserBoolean(LisioBooleanParameterNames.BOOK_PAGE, false);
        this.updateUserBoolean(LisioBooleanParameterNames.READING_MODE, false);
      }
    }
  }

  /**
   * @async
   * Public method to retrieve all users
   * @returns Retuns a promise containing nothing
   * @source
   */
  public async getAllUsers(): Promise<void> {
    let savedUsers: LisioUserParsed[] | undefined = undefined;
    for (const storageController of this._storageControllers) {
      if (savedUsers == undefined || savedUsers.length == 0) {
        savedUsers = await storageController.getAllUsers();
      }
    }
    if (savedUsers != undefined) {
      savedUsers.sort((a, b) => a.name.localeCompare(b.name));
      for (const savedUser of savedUsers) {
        this._usernames.push(savedUser.name);
        this._users.set(savedUser.name, this.unparseUser(savedUser));
      }
    }
  }

  /**
   * @async
   * Public method to calculate the next user number based on existing user numbers
   * @returns Returns a promise containing nothing
   * @source
   */
  public async getNextUserNumber(): Promise<void> {
    if (this._users.size != 0) {
      let lastUserNumber: number = -1;
      for (const username of this._users.keys()) {
        const userNumber: number = Number.parseInt(
          username.charAt(username.length - 1),
        );
        if (userNumber > lastUserNumber) {
          lastUserNumber = userNumber;
        }
      }
      this._nextUserNumber = lastUserNumber + 1;
    }
  }

  /**
   * @async
   * Public method to retrieve the selected user from storage and store it in {@link _currentUser | _currentUser} attribute
   * @returns Returns a promise containing nothing
   * @source
   */
  public async getSelectedUser(): Promise<void> {
    for (const storageController of this._storageControllers) {
      const savedUser = await storageController.getSelectedUser().catch(() => {
        if (!isFirefoxOrSafari) {
          storageController.deleteAllUsers();
        }
      });
      if (savedUser != undefined) {
        this.setCurrentUser(savedUser);
        for (const user of this._users.values()) {
          storageController.setUser(user);
        }
      }
    }
  }

  /**
   * @async
   * Public method to check if user has to be deleted.\
   * This method checks :
   *  * If user has only is_active parameter active and no profiles
   *  * If user has no parameters and no profiles
   *  * Update the management screen opening button state
   * @returns Returns nothing
   * @source
   */
  public async checkIfUserNeedToBeDeleted(): Promise<void> {
    try {
      if (this._currentUser != undefined) {
        if (
          ((this._currentUser.customParameters.size === 1 &&
            (this._currentUser.customParameters.has(
              LisioBooleanParameterNames.IS_ACTIVE,
            ) ||
            this._currentUser.customParameters.has(
              LisioBooleanParameterNames.BOOK_PAGE,
            ))) ||
            (this._currentUser.customParameters.size === 0 &&
              !this._currentUser.customParameters.has(
                LisioBooleanParameterNames.IS_ACTIVE,
              ))) &&
          this._currentUser.profiles.length === 0 &&
          this._usernames.length === 1
        ) {
          this._usernames.splice(
            this._usernames.indexOf(this._currentUser.name),
            1,
          );
          for (const storageController of this._storageControllers) {
            await storageController.deleteUser(this._currentUser.name);
          }
          this._usersList?.removeUserFromList(this._currentUser.name);
          this._users.delete(this._currentUser.name);
          this.setCurrentUser(undefined);
          if (this._users.size === 0) {
            this._activationGroup?.addClasses(["hidden"]);
            this._userGroup?.addClasses(["hidden"]);
            if (
              ScreenNames[ManagementScreen.name] ==
              ScreenManager.current.currentScreen?.componentName
            ) {
              ScreenManager.current.changeScreen(
                ScreenManager.current.nav?.navButtons[0],
              );
            }
          }
          InputManager.current.disableAll(false);
        } else {
          this._users.set(this._currentUser.name, this._currentUser);
        }
      }
      this.checkManagementScreenButtonState();
    } catch (_) {}
  }

  /**
   * @async
   * Public method to update numeric parameters of current user.\
   * This method does :
   *  * Creates user if no current user exsits
   *  * If parameter value equals to his default value then remove this parameter
   *  * Else update this parameter
   *  * Applies change also to storage
   * @param {LisioNumericParameterNames} name - Numeric parameter name
   * @param {number} value - Value of the parameter
   * @param {boolean} isDefault - Notifies if value is default value of the parameter
   * @returns Returns nothing
   * @source
   */
  public async updateUserNumber(
    name: LisioNumericParameterNames,
    value: number,
    isDefault: boolean,
  ): Promise<void> {
    if (this._currentUser == undefined) {
      await this.createNewUser();
    }
    if (isDefault) {
      this._currentUser?.customParameters.delete(name);
    } else {
      this._currentUser?.customParameters.set(
        name,
        LisioParameterFactory.current.buildLisioParameter(name, value),
      );
    }
    for (const storageController of this._storageControllers) {
      await storageController.updateUser(
        this._currentUser?.formatForSaving()!,
        isDefault
          ? {
              remove: { parameters: [name] },
            }
          : {
              update: [
                {
                  name,
                  value,
                },
              ],
            },
      );
    }
    this.checkIfUserNeedToBeDeleted();
  }

  /**
   * @async
   * Public method to update string parameters of current user.\
   * This method does :
   *  * Creates user if no current user exsits
   *  * If parameter value equals to his default value then remove this parameter
   *  * Else update this parameter
   *  * Applies change also to storage
   * @param {LisioStringParameterNames} name - String parameter name
   * @param {string} value - Value of the parameter
   * @param {boolean} isDefault - Notifies if value is default value of the parameter
   * @returns Returns nothing
   * @source
   */
  public async updateUserString(
    name: LisioStringParameterNames,
    value: string,
    isDefault: boolean,
  ): Promise<void> {
    if (this._currentUser == undefined) {
      await this.createNewUser();
    }
    if (isDefault) {
      this._currentUser?.customParameters.delete(name);
    } else {
      this._currentUser?.customParameters.set(
        name,
        LisioParameterFactory.current.buildLisioParameter(name, value),
      );
    }
    for (const storageController of this._storageControllers) {
      await storageController.updateUser(
        this._currentUser?.formatForSaving()!,
        isDefault
          ? {
              remove: { parameters: [name] },
            }
          : {
              update: [
                {
                  name,
                  value,
                },
              ],
            },
      );
    }
    this.checkIfUserNeedToBeDeleted();
  }

  /**
   * @async
   * Public method to update boolean parameters of current user.\
   * This method does :
   *  * Creates user if no current user exsits
   *  * If parameter value equals to his default value then remove this parameter
   *  * Else update this parameter
   *  * Applies change also to storage
   * @param {LisioBooleanParameterNames} name - Boolean parameter name
   * @param {boolean} value - Value of the parameter
   * @returns Returns nothing
   * @source
   */
  public async updateUserBoolean(
    name: LisioBooleanParameterNames | LisioProfileNames,
    value: boolean,
  ): Promise<void> {
    if (name.toUpperCase() in LisioBooleanParameterNames) {
      if (this._currentUser == undefined) {
        await this.createNewUser();
      }
      if (value) {
        this._currentUser?.customParameters.set(
          name as LisioBooleanParameterNames,
          LisioParameterFactory.current.buildLisioParameter(
            name as LisioBooleanParameterNames,
            value,
          ),
        );
      } else {
        this._currentUser?.customParameters.delete(
          name as LisioBooleanParameterNames,
        );
      }
      for (const storageController of this._storageControllers) {
        await storageController.updateUser(
          this._currentUser?.formatForSaving()!,
          value
            ? {
                add: {
                  parameters: [
                    { name: name as LisioBooleanParameterNames, value },
                  ],
                },
              }
            : {
                remove: {
                  parameters: [name as LisioBooleanParameterNames],
                },
              },
        );
      }
    } else {
      if (this._currentUser == undefined) {
        await this.createNewUser();
      }
      if (value) {
        this._currentUser?.profiles.push(name as LisioProfileNames);
      } else {
        this._currentUser?.profiles.splice(
          this._currentUser?.profiles.indexOf(name as LisioProfileNames),
          1,
        );
      }
      for (const storageController of this._storageControllers) {
        await storageController.updateUser(
          this._currentUser?.formatForSaving()!,
          value
            ? { add: { profiles: [{ name: name as LisioProfileNames }] } }
            : {
                remove: { profiles: [name as LisioProfileNames] },
              },
        );
      }
    }
    this.checkIfUserNeedToBeDeleted();
  }

  /**
   * @async
   * Public method to create new user.\
   * This method does :
   *  * Creates a new user and save it to storage
   *  * Enables adaptation, displays users groups and add a new item in user list
   *  * Updates some piece of informations
   *  * Update statistics
   *  * Update the user deletion button state
   *  * Update the management screen opening button state
   * @returns Returns nothing
   * @source
   */
  public async createNewUser(): Promise<void> {
    const isActiveParameter: LisioParameter =
      LisioParameterFactory.current.buildLisioParameter(
        LisioBooleanParameterNames.IS_ACTIVE,
        true,
      );
    const newUser: LisioUser = new LisioUser(
      `Utilisateur-${this._nextUserNumber}`,
      true,
      new Map<LisioParameterNames, LisioParameter>(
        this._currentUser == undefined
          ? [[LisioBooleanParameterNames.IS_ACTIVE, isActiveParameter]]
          : new Map(this._currentUser.customParameters),
      ),
      this._currentUser == undefined ? [] : [...this._currentUser.profiles],
    );
    for (const storageController of this._storageControllers) {
      await storageController.setUser(newUser);
    }
    if (this._currentUser != undefined) {
      for (const storageController of this._storageControllers) {
        await storageController.switchSelectedUser(newUser.name);
      }
      if (this._users.get(this._currentUser.name)) {
        this._users.get(this._currentUser.name)!.isSelected = false;
      }
    } else {
      this._activationGroup?.removeClasses(["hidden"]);
      this._userGroup?.removeClasses(["hidden"]);
    }
    this._usersList?.addItemInList(
      "users-choice",
      {
        textId: newUser.name,
        value: newUser.name,
        isChecked: true,
        noTranslate: true,
      },
      UsersScreen.name,
      VisualCategoryNames.USERS,
      HomeScreen.name,
    );
    this._userRenameInput?.setValue(newUser.name);
    this._usernames.push(newUser.name);
    this.setCurrentUser(newUser);
    this._users.set(newUser.name, newUser);
    this._nextUserNumber++;
    StatisticsController.current.incrementAddUserStatistics();
    InputManager.current.refreshInputs([], [isActiveParameter]);
    this.checkDeleteButtonState();
    this.checkManagementScreenButtonState();
    InputManager.current.toggleIsActiveInput(true, false);
  }

  /**
   * @async
   * Public method to delete all users.\
   * This method does :
   *  * Creates a new user
   *  * Enables adaptation, displays users groups and add a new item in user list
   *  * Updates some piece of informations
   *  * Update statistics
   *  * Update the user deletion button state
   *  * Update the management screen opening button state
   * @returns Returns nothing
   * @source
   */
  public async deleteAllUsers(): Promise<void> {
    for (const storageController of this._storageControllers) {
      await storageController.deleteAllUsers();
    }
    this.setCurrentUser(undefined);
    this._usernames = [];
    this._users.clear();
    this._activationGroup?.addClasses(["hidden"]);
    this._userGroup?.addClasses(["hidden"]);
    this._nextUserNumber = 1;
    this._usersList?.clearChildren();
    this.checkDeleteButtonState();
    this.checkManagementScreenButtonState();
  }

  /**
   * @async
   * Public method to check storage version
   * @returns Returns nothing
   * @source
   */
  public async checkStorageVersion(): Promise<void> {
    for (const storageController of this._storageControllers) {
      await storageController.checkStorageVersion();
    }
  }

  /**
   * @async
   * Public method to set popin display state
   * @returns Returns nothing
   * @source
   */
  public async setIsPopinHidden(value: boolean): Promise<void> {
    for (const storageController of this._storageControllers) {
      await storageController.setIsPopinHidden(value);
    }
  }

  /**
   * @async
   * Public method to set process state
   * @returns Returns nothing
   * @source
   */
  public async setIsProcessEnd(value: boolean): Promise<void> {
    for (const storageController of this._storageControllers) {
      await storageController.setIsProcessEnd(value);
    }
  }

  /**
   * @async
   * Public method to synchronize users from url query.\
   * This method does :
   *  * Decodes usernames from query string
   *  * Decodes users using {@link Src/Controllers.CompressorController | CompressorController} from query string
   *  * Update storage
   * @param {string[]} urlQueries - Query string from URL
   * @returns Returns nothing
   * @source
   */
  public async synchronizeFromUrlQuery(urlQueries: string[]): Promise<void> {
    this.setCurrentUser(undefined);
    this._usernames = [];
    this._users.clear();
    for (const storageController of this._storageControllers) {
      await storageController.clearUsers();
    }
    for (const urlQuery of urlQueries) {
      const match = urlQuery.match(/(\w+)=(.+)/);
      if (match != null) {
        if (match[1] === "lisioUsernames") {
          this._usernames = JSON.parse(atob(match[2]));
        } else if (match[1] === "lisioUsers") {
          const parsedUsers: LisioUserParsed[] =
            CompressorController.current.decodeUsers(match[2]);
          for (const parsedUser of parsedUsers) {
            for (const storageController of this._storageControllers) {
              await storageController.setUser(parsedUser);
            }
            this._users.set(parsedUser.name, this.unparseUser(parsedUser));
            if (parsedUser.isSelected) {
              this.setCurrentUser(this.unparseUser(parsedUser));
            }
          }
        }
      }
    }
    if (this._currentUser == undefined) {
      MessageManager.current.sendDisableAllMessage();
    }
  }

  /**
   * @async
   * Public method to rename user with a new username and changes it in usernames
   * @param {string} newUsername - New username of the user
   * @returns Returns nothing
   * @source
   */
  public async renameUser(newUsername: string): Promise<void> {
    if (this._users.get(newUsername) == undefined) {
      const currentUsername = this.currentUser!.name;
      this._currentUser!.name = newUsername;
      this._users.delete(currentUsername);
      this._usernames[this._usernames.indexOf(currentUsername)] = newUsername;
      for (const storageController of this._storageControllers) {
        await storageController.renameUser(currentUsername, newUsername);
      }
      this._users.set(newUsername, this._currentUser!);
      this._usersList?.changeUsernameInList(currentUsername, newUsername);
    }
  }

  /**
   * @async
   * Public method to delete user designated by his username and removes it from usernames
   * @param {string} username - New username of the user to be deleted
   * @returns Returns nothing
   * @source
   */
  public async deleteUser(username: string): Promise<void> {
    if (this._users.size > 1) {
      this._usersList?.removeUserFromList(username);
      for (const storageController of this._storageControllers) {
        await storageController.deleteUser(username);
      }
      this._usernames.splice(this._usernames.indexOf(username), 1);
      this._users.delete(username);
      this.checkDeleteButtonState();
    }
  }

  /**
   * @async
   * Public method to enable or disable the delete button in the user screen
   * @returns Returns nothing
   * @source
   */
  public async checkDeleteButtonState() {
    if (this._deleteButton?.htmlElement != undefined) {
      if (this._users.size <= 1) {
        (this._deleteButton.htmlElement as HTMLInputElement).disabled = true;
      } else {
        (this._deleteButton.htmlElement as HTMLInputElement).disabled = false;
      }
    }
  }

  /**
   * @async
   * Public method to enable or disable the management screen button in the header
   * @returns Returns nothing
   * @source
   */
  public async checkManagementScreenButtonState() {
    if (this._users.size === 0) {
      (this._managementButton!.htmlElement as HTMLInputElement).disabled = true;
      this._managementButton?.showHideElement(false);
    } else {
      (this._managementButton!.htmlElement as HTMLInputElement).disabled =
        false;
      this._managementButton?.showHideElement(true);
    }
  }

  /**
   * Constructor of class {@link UserController | UserController}
   * @throws If singleton already initialize.\
   * See {@link https://env-preprod-docs.lisio.fr/lisio-engine/enums/Src_Core.CoreErrorCodes.html#SINGLETON_NOT_UNIQUE | CoreErrorCodes.SINGLETON_NOT_UNIQUE}
   * @source
   */
  constructor() {
    if (UserController._current == undefined) {
      if (__BUILD_TARGET__ === "extension") {
        this._storageControllers.push(
          new StorageController(new ExtensionStorageController()),
        );
      } else {
        this._storageControllers.push(
          new StorageController(new LocalStorageController()),
          new StorageController(new CookieController()),
        );
      }
      UserController._current = this;
    } else {
      throw new Error(
        `Code : ${CoreErrorCodes.SINGLETON_NOT_UNIQUE}. Singleton already initialize`,
      );
    }
  }

  private setCurrentUser(value: LisioUser | undefined){
    this._currentUser = value;
  }
}

export { UserController };
