/**
 * @mergeTarget
 * @module Src/Managers
 */

import {
  defautValueOfNumericParameters,
  LisioBooleanParameterNames,
  LisioCategoryNames,
  LisioNumericParameterNames,
  LisioParameter,
  LisioParameterNames,
  LisioProfile,
  LisioProfileFactory,
  LisioProfileNames,
  LisioStringParameter,
  LisioStringParameterNames,
} from "@lisio/lisio-profils";
import { CheckboxInput } from "../render/components/inputs/switch/input/checkbox-input";
import { TextInput } from "../render/components/inputs/text/input/text-input";
import { RadioInput } from "../render/components/inputs/choice/input/radio-input";
import { RangeInput } from "../render/components/inputs/range/input/range-input";
import { ScreenManager } from "./screen-manager";
import { NumberInput } from "../render/components/inputs/slider/input/number-input";
import { HomeScreen } from "../render/screens/home/home-screen";
import { CoreErrorCodes } from "@lisio/lisio-engine";
import { UserController } from "../controllers/user-controller";

/**
 * Class representing a input manager.\
 * It aims to centralize the logic of inputs management.\
 * If something need to manage or use mutliple inputs it has to use this class.\
 * To execute his responsability this class does :
 *  * Adds inputs in their respective cache
 *  * Keeps in memory enabled inputs
 *  * Refreshes display of parameters when a profile is enabled
 *  * Disables profiles if a linked parameter is modified
 *  * Disables all
 *  * Disables all book page related parameters and profiles
 */
class InputManager {
  /**
   * Private attribute to store numeric inputs
   * @source
   */
  private _numberInputMap: Map<LisioNumericParameterNames, NumberInput> =
    new Map<LisioNumericParameterNames, NumberInput>();

  /**
   * Private attribute to store numeric inputs
   * @source
   */
  private _rangeInputMap: Map<LisioNumericParameterNames, NumberInput> =
    new Map<LisioNumericParameterNames, NumberInput>();

  /**
   * Private attribute to store parameter related checkbox inputs
   * @source
   */
  private _checkboxParameterInputMap: Map<
    LisioBooleanParameterNames,
    CheckboxInput
  > = new Map<LisioBooleanParameterNames, CheckboxInput>();

  /**
   * Private attribute to store profile related checkbox inputs
   * @source
   */
  private _checkboxProfileInputMap: Map<LisioProfileNames, CheckboxInput> =
    new Map<LisioProfileNames, CheckboxInput>();

  /**
   * Private attribute to store radio inputs
   * @source
   */
  private _radioInputMap: Map<
    Omit<
      LisioStringParameterNames,
      | LisioStringParameterNames.UNDERLINE_RED
      | LisioStringParameterNames.UNDERLINE_GREEN
      | LisioStringParameterNames.UNDERLINE_BLUE
    >,
    RadioInput[]
  > = new Map<
    Omit<
      LisioStringParameterNames,
      | LisioStringParameterNames.UNDERLINE_RED
      | LisioStringParameterNames.UNDERLINE_GREEN
      | LisioStringParameterNames.UNDERLINE_BLUE
    >,
    RadioInput[]
  >();

  /**
   * Private attribute to store text inputs
   * @source
   */
  private _textInputMap: Map<
    | LisioStringParameterNames.UNDERLINE_RED
    | LisioStringParameterNames.UNDERLINE_GREEN
    | LisioStringParameterNames.UNDERLINE_BLUE
    | "rename-user"
    | "users-choice",
    TextInput
  > = new Map<
    | LisioStringParameterNames.UNDERLINE_RED
    | LisioStringParameterNames.UNDERLINE_GREEN
    | LisioStringParameterNames.UNDERLINE_BLUE
    | "rename-user"
    | "users-choice",
    TextInput
  >();

  /**
   * Private attribute to store numeric inputs
   * @source
   */
  private _mapParameterInProfiles: Map<
    LisioParameterNames,
    LisioProfileNames[]
  > = new Map<LisioParameterNames, LisioProfileNames[]>();

  /**
   * Private attribute to store all current active parameters
   * @source
   */
  private _activeParameters: LisioParameterNames[] = [];

  /**
   * Private attribute to store all current hidden parameters
   * @source
   */
  private _hiddenParameters: Set<LisioParameterNames> =
    new Set<LisioParameterNames>();

  /**
   * Private attribute to store all current active profiles
   * @source
   */
  private _activeProfiles: LisioProfileNames[] = [];

  /**
   * Private attribute to store all current hidden profiles
   * @source
   */
  private _hiddenProfiles: Set<LisioProfileNames> =
    new Set<LisioProfileNames>();

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

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

  /**
   * Getter for attribute {@link _hiddenParameters | _hiddenParameters}
   * @returns Returns _hiddenParameters attribute
   * @source
   */
  public get hiddenParameters(): Set<LisioParameterNames> {
    return this._hiddenParameters;
  }
  /**
   * Public method to disable readink mask when escape is pressed
   * @returns Returns nothing
   * @source
   */
  public disableReadingMask() {
    if (
      UserController.current.currentUser?.customParameters.has(
        LisioBooleanParameterNames.READING_MASK,
      )
    ) {
      this._checkboxParameterInputMap
        .get(LisioBooleanParameterNames.READING_MASK)
        ?.toggle(false, true, true, false);
    } else if (
      UserController.current.currentUser?.profiles.includes(
        LisioProfileNames.FOCUS,
      )
    ) {
      this._checkboxProfileInputMap
        .get(LisioProfileNames.FOCUS)
        ?.toggle(false, true, true, false);
    }
  }

  /**
   * Public method to disable readink mask when escape is pressed
   * @returns Returns nothing
   * @source
   */
  public disableParameter(parameter: LisioParameterNames) {
    const upperName = parameter.toUpperCase();
    if (upperName in LisioBooleanParameterNames) {
      this._checkboxParameterInputMap
        .get(
          LisioBooleanParameterNames[
            upperName as keyof typeof LisioBooleanParameterNames
          ],
        )
        ?.toggle<boolean>(false, true, true, false);
    } else if (upperName in LisioNumericParameterNames) {
      const convertedName =
        LisioNumericParameterNames[
          upperName as keyof typeof LisioNumericParameterNames
        ];
      const defaultValue =
        defautValueOfNumericParameters.get(convertedName) || 0;
      this._numberInputMap
        .get(convertedName)
        ?.toggle<number>(defaultValue, true, true, false);
    } else if (upperName in LisioStringParameterNames) {
      const convertedName =
        LisioStringParameterNames[
          upperName as keyof typeof LisioStringParameterNames
        ];
      const radios = this._radioInputMap.get(convertedName);
      const defaultInput = radios?.find(
        (radioInput) => radioInput.value === "default",
      );
      defaultInput?.toggle<boolean>(true, true, true, false);
    }
    this.disableProfileLinkToParameter(parameter);
  }

  /**
   * Public method to keep in track all hidden inputs
   * @param {LisioParameterNames | LisioProfileNames} name - Name of parameter or profile
   * @returns Returns nothing
   * @source
   */
  public addHiddenProfileOrParameter(
    name: LisioParameterNames | LisioProfileNames,
  ) {
    if (name.toUpperCase() in LisioProfileNames) {
      this._hiddenProfiles.add(name as LisioProfileNames);
    } else {
      this._hiddenParameters.add(name as LisioParameterNames);
    }
  }

  /**
   * Public method to keep in track enabled inputs
   * @param {LisioParameterNames | LisioProfileNames} name - Name of parameter or profile
   * @param {boolean} hasToAdd - Indicates if parameter or profile has to be add or remove
   * @returns Returns nothing
   * @source
   */
  public addOrRemoveEnabledInput(
    name: LisioParameterNames | LisioProfileNames,
    hasToAdd: boolean,
  ): void {
    const lightEco = this._checkboxProfileInputMap.get(
      LisioProfileNames.LIGHT_ECOLO,
    );
    if (name === LisioProfileNames.ECOLO && hasToAdd != lightEco?.isChecked) {
      lightEco?.toggle(hasToAdd, true, true, true);
    }
    if (name.toUpperCase() in LisioProfileNames) {
      if (
        hasToAdd &&
        !this._activeProfiles.includes(name as LisioProfileNames)
      ) {
        this._activeProfiles.push(name as LisioProfileNames);
      } else if (
        !hasToAdd &&
        this._activeProfiles.includes(name as LisioProfileNames)
      ) {
        this._activeProfiles.splice(
          this._activeProfiles.indexOf(name as LisioProfileNames),
          1,
        );
      }
    } else {
      if (
        hasToAdd &&
        !this._activeParameters.includes(name as LisioParameterNames)
      ) {
        this._activeParameters.push(name as LisioParameterNames);
      } else if (
        !hasToAdd &&
        this._activeParameters.includes(name as LisioParameterNames)
      ) {
        this._activeParameters.splice(
          this._activeParameters.indexOf(name as LisioParameterNames),
          1,
        );
      }
    }
  }

  /**
   * Public method to add input in cache
   * @typeParam T - The type of input passed in parameter. It's can be : {@link Src/Components/CustomInput.NumberInput | NumberInput}, {@link Src/Components/CustomInput.CheckboxInput | CheckboxInput}, {@link Src/Components/CustomInput.TextInput | TextInput} or {@link Src/Components/CustomInput.RadioInput | RadioInput}
   * @param {LisioParameterNames | LisioProfileNames | "users-choice" | "rename-user"} name
   * @param {T} input
   * @returns Returns nothing
   * @source
   */
  public addInputInMap<
    T extends NumberInput | CheckboxInput | TextInput | RadioInput | RangeInput,
  >(
    name:
      | LisioParameterNames
      | LisioProfileNames
      | "users-choice"
      | "rename-user",
    input: T,
  ): void {
    const upperName = name.toUpperCase();
    if (upperName in LisioNumericParameterNames) {
      if(["daltonism_r","daltonism_g","daltonism_b","daltonism_hue","daltonism_saturation","daltonism_brightness"].includes(name)){
        this._rangeInputMap.set(
          name as LisioNumericParameterNames,
          input as NumberInput,
        );
      } else {
        this._numberInputMap.set(
          name as LisioNumericParameterNames,
          input as NumberInput,
        );
      }
    } else if (
      upperName in LisioBooleanParameterNames ||
      upperName in LisioProfileNames
    ) {
      if (upperName in LisioBooleanParameterNames) {

        this._checkboxParameterInputMap.set(
          name as LisioBooleanParameterNames,
          input as CheckboxInput,
        );
      } else {
        this._checkboxProfileInputMap.set(
          name as LisioProfileNames,
          input as CheckboxInput,
        );
      }
    } else if (
      name === "rename-user" ||
      name === "users-choice" ||
      name === LisioStringParameterNames.UNDERLINE_RED ||
      name === LisioStringParameterNames.UNDERLINE_GREEN ||
      name === LisioStringParameterNames.UNDERLINE_BLUE
    ) {
      this._textInputMap.set(name, input as TextInput);
    } else if (upperName in LisioStringParameterNames) {
      const inputs: RadioInput[] | undefined = this._radioInputMap.get(name);
      if (inputs == undefined) {
        this._radioInputMap.set(name as LisioStringParameterNames, [
          input as RadioInput,
        ]);
      } else {
        inputs.push(input as RadioInput);
      }
    }
  }

  /**
   * Public method to refresh display of settings when a profile is enabled
   * @param {LisioProfileNames} profileName - Profile name
   * @param {LisioParameter[]} parameters - Parameters used by profile
   * @param {boolean} isEnabled - Indicates profile state
   * @param {boolean} hasToHandleOnChange - Indicates if parameter input has to handle on change event
   * @returns Returns an empty promise nothing
   * @source
   */
  public async adaptParameters(
    profileName: LisioProfileNames,
    parameters: LisioParameter[],
    isEnabled: boolean,
    hasToHandleOnChange: boolean,
  ): Promise<void> {
    for (const parameter of parameters) {
      if (parameter.name.toUpperCase() in LisioBooleanParameterNames) {
        if (
          parameter.name != LisioBooleanParameterNames.BOOK_PAGE &&
          parameter.name != LisioBooleanParameterNames.READING_MODE &&
          parameter.name != LisioBooleanParameterNames.VOCA &&
          parameter.name != LisioBooleanParameterNames.ACTIVE_UNDERLINE &&
          parameter.name != LisioBooleanParameterNames.SPEECH_SYNTHESIS_STATE &&
          parameter.name != LisioBooleanParameterNames.IS_ACTIVE
        ) {
          this._checkboxParameterInputMap
            .get(parameter.name as LisioBooleanParameterNames)
            ?.toggle<boolean>(!isEnabled as boolean, false, false, false);
          this._checkboxParameterInputMap
            .get(parameter.name as LisioBooleanParameterNames)
            ?.toggle<boolean>(
              isEnabled as boolean,
              hasToHandleOnChange,
              hasToHandleOnChange,
              false,
            );
        } else if (
          parameter.name == LisioBooleanParameterNames.BOOK_PAGE &&
          UserController.current.currentUser != undefined
        ) {
          const otherProfilesHaveBookPage: boolean =
            UserController.current.currentUser.profiles.some(
              (profile) =>
                profile != profileName &&
                LisioProfileFactory.current
                  .buildLisioProfile(profile)
                  ?.checkIfParametersAreInProfile([
                    LisioBooleanParameterNames.BOOK_PAGE,
                  ]),
            );
          if (!otherProfilesHaveBookPage) {
            await UserController.current.updateUserBoolean(
              LisioBooleanParameterNames.BOOK_PAGE,
              isEnabled,
            );
          }
        }
      } else if (parameter.name.toUpperCase() in LisioStringParameterNames) {
        const inputs: RadioInput[] | undefined = this._radioInputMap.get(
          parameter.name as LisioStringParameterNames,
        );
        if (inputs != undefined) {
          inputs
            .find(
              (input) =>
                input.value ===
                (parameter as LisioStringParameter).defaultValue,
            )
            ?.toggle<boolean>(
              true,
              hasToHandleOnChange,
              hasToHandleOnChange,
              false,
            );
          inputs
            .find((input) => input.value === (parameter.value as string))
            ?.toggle<boolean>(
              isEnabled,
              hasToHandleOnChange,
              hasToHandleOnChange,
              false,
            );
        }
      } else if (parameter.name.toUpperCase() in LisioNumericParameterNames) {
        if(["daltonism_r","daltonism_g","daltonism_b","daltonism_hue","daltonism_saturation","daltonism_brightness"].includes(parameter.name)){
          this._rangeInputMap
          .get(parameter.name as LisioNumericParameterNames)
            ?.toggle<number>(
              isEnabled
              ? (parameter.value as number)
              : (parameter.defaultValue as number),
              hasToHandleOnChange,
              hasToHandleOnChange,
              false,
            );
        } else {
          this._numberInputMap
            .get(parameter.name as LisioNumericParameterNames)
            ?.toggle<number>(
              parameter.defaultValue as number,
              hasToHandleOnChange,
              hasToHandleOnChange,
              false,
            );
          this._numberInputMap
            .get(parameter.name as LisioNumericParameterNames)
            ?.toggle<number>(
              isEnabled
                ? (parameter.value as number)
                : (parameter.defaultValue as number),
              hasToHandleOnChange,
              hasToHandleOnChange,
              false,
            );
        }
      }
      if (
        parameter.name !== LisioBooleanParameterNames.BOOK_PAGE &&
        parameter.name !== LisioBooleanParameterNames.READING_MODE &&
        parameter.name !== LisioBooleanParameterNames.VOCA &&
        parameter.name !== LisioStringParameterNames.UNDERLINE_RED &&
        parameter.name !== LisioStringParameterNames.UNDERLINE_GREEN &&
        parameter.name !== LisioStringParameterNames.UNDERLINE_BLUE
      ) {
        ScreenManager.current.breadcrumb(
          parameter.name,
          "SettingsScreen",
          LisioCategoryNames.SETTINGS,
          HomeScreen.name,
          isEnabled,
        );
      }
    }
  }

  /**
   * Public method to disable all profiles which include modified parameter without disabled others parameters used by disabled profiles
   * @param {LisioParameterNames} name - Parameter name modified
   * @returns Returns a promise containing nothing
   * @source
   */
  public async disableProfileLinkToParameter(
    name: LisioParameterNames,
  ): Promise<void> {
    const profilesUseThisParameter = this._mapParameterInProfiles.get(name);
    if (profilesUseThisParameter != undefined) {
      for (const profilUseThisParameter of profilesUseThisParameter) {
        if (this._activeProfiles.includes(profilUseThisParameter)) {
          const profile: LisioProfile =
            LisioProfileFactory.current.buildLisioProfile(
              profilUseThisParameter,
            );
          this._checkboxProfileInputMap
            .get(profilUseThisParameter)
            ?.toggle<boolean>(false, false, true, false);

          await this.adaptParameters(
            profile.name,
            Array.from(profile.parameters.values()).filter(
              (parameter) => parameter.name != name,
            ),
            true,
            true,
          );
        }
      }
    }
  }

  /**
   * Public method to disable all parameters and profiles
   * @param {boolean} hasToUpdateUser - Indicates if has to update user
   * @returns Returns nothing
   * @source
   */
  public disableAll(hasToUpdateUser: boolean): void {
    const activeParametersCopy = [...this._activeParameters];
    for (const activeParameter of activeParametersCopy) {
      const upperName = activeParameter.toUpperCase();
      if (upperName in LisioNumericParameterNames) {
        if(["daltonism_r","daltonism_g","daltonism_b","daltonism_hue","daltonism_saturation","daltonism_brightness"].includes(activeParameter)){
          this._rangeInputMap
            .get(activeParameter as LisioNumericParameterNames)
            ?.toggle<number>(Number.NEGATIVE_INFINITY, true, hasToUpdateUser, false);
        } else {
          const defaultValue = defautValueOfNumericParameters.get(activeParameter as LisioNumericParameterNames) || 0;
          this._numberInputMap
            .get(activeParameter as LisioNumericParameterNames)
            ?.toggle<number>(defaultValue, false, hasToUpdateUser, false);
        }
      } else if (upperName in LisioBooleanParameterNames) {
        this._checkboxParameterInputMap
          .get(activeParameter as LisioBooleanParameterNames)
          ?.toggle<boolean>(false, true, hasToUpdateUser, false);
      } else if (
        activeParameter === LisioStringParameterNames.UNDERLINE_RED ||
        activeParameter === LisioStringParameterNames.UNDERLINE_GREEN ||
        activeParameter === LisioStringParameterNames.UNDERLINE_BLUE
      ) {
        this._textInputMap
          .get(activeParameter)
          ?.toggle<string>("", true, hasToUpdateUser, false);
      } else if (upperName in LisioStringParameterNames) {
        const inputs: RadioInput[] | undefined = this._radioInputMap.get(
          activeParameter as LisioStringParameterNames,
        );
        if (inputs != undefined) {
          inputs.find((input) => input.value === "default")?.toggle<boolean>(true, true, hasToUpdateUser, false);
        }
      }
    }
    const activeProfilesCopy = [...this._activeProfiles];
    for (const activeProfile of activeProfilesCopy) {
      this._checkboxProfileInputMap
        .get(activeProfile)
        ?.toggle<boolean>(false, true, hasToUpdateUser, false);
    }
  }

  /**
   * Public method to disable all parameters and profiles related to book page or reading mode
   * @returns Returns nothing
   * @source
   */
  public disableAllBookPageOrReading(): void {
    for (const profilName of this._activeProfiles) {
      const profile = LisioProfileFactory.current.buildLisioProfile(profilName);
      if (
        profile.parameters.has(LisioBooleanParameterNames.BOOK_PAGE) ||
        profile.parameters.has(LisioBooleanParameterNames.READING_MODE)
      ) {
        this._checkboxProfileInputMap
          .get(profilName)
          ?.toggle<boolean>(false, false, true, false);
      }
    }
  }

  /**
   * Public method to initialize active inputs
   * @returns Returns nothing
   * @source
   */
  public initInputs() {
    const hasToEnableActiveInput: boolean =
      UserController.current.currentUser != undefined &&
      UserController.current.currentUser.customParameters.has(
        LisioBooleanParameterNames.IS_ACTIVE,
      ) &&
      this._activeParameters.length > 1 &&
      this._activeProfiles.length > 0;
    for (const activeParameter of [...this._activeParameters]) {
      if (activeParameter.toUpperCase() in LisioBooleanParameterNames) {
        this._checkboxParameterInputMap
          .get(activeParameter as LisioBooleanParameterNames)
          ?.handleOnInit(hasToEnableActiveInput);
      } else if (activeParameter.toUpperCase() in LisioNumericParameterNames) {
        if(["daltonism_r","daltonism_g","daltonism_b","daltonism_hue","daltonism_saturation","daltonism_brightness"].includes(activeParameter)){
          this._rangeInputMap
            .get(activeParameter as LisioNumericParameterNames)
            ?.handleOnInit(hasToEnableActiveInput);
        } else {
          this._numberInputMap
            .get(activeParameter as LisioNumericParameterNames)
            ?.handleOnInit(hasToEnableActiveInput);
        }
      } else if (
        activeParameter === LisioStringParameterNames.UNDERLINE_RED ||
        activeParameter === LisioStringParameterNames.UNDERLINE_GREEN ||
        activeParameter === LisioStringParameterNames.UNDERLINE_BLUE
      ) {
        this._textInputMap
          .get(activeParameter)
          ?.handleOnInit(hasToEnableActiveInput);
      } else if (activeParameter.toUpperCase() in LisioStringParameterNames) {
        this._radioInputMap
          .get(activeParameter)
          ?.find((radio) => radio.isChecked)
          ?.handleOnInit(hasToEnableActiveInput);
      }
    }
    for (const activeProfile of [...this._activeProfiles]) {
      this._checkboxProfileInputMap
        .get(activeProfile)
        ?.handleOnInit(hasToEnableActiveInput);
    }
  }

  /**
   * Public method to refresh inputs when user switched
   * @returns Returns nothing
   * @source
   */
  public refreshInputs(
    profileNames: LisioProfileNames[],
    parameters: LisioParameter[],
  ) {
    for (const profileName of profileNames) {
      this._checkboxProfileInputMap
        .get(profileName)
        ?.toggle<boolean>(false, false, false, false);
      this._checkboxProfileInputMap
        .get(profileName)
        ?.toggle<boolean>(true, true, false, false);
    }

    for (const parameter of parameters) {
      if (parameter.name.toUpperCase() in LisioBooleanParameterNames) {
        this._checkboxParameterInputMap
          .get(parameter.name as LisioBooleanParameterNames)
          ?.toggle<boolean>(false, false, false, false);
        this._checkboxParameterInputMap
          .get(parameter.name as LisioBooleanParameterNames)
          ?.toggle<boolean>(true, true, false, false);
      } else if (parameter.name.toUpperCase() in LisioNumericParameterNames) {
        const map = this._numberInputMap.has(parameter.name as LisioNumericParameterNames) ? this._numberInputMap : this._rangeInputMap;
        // map.get(parameter.name as LisioNumericParameterNames)
        //     ?.toggle<number>(
        //       parameter.defaultValue as number,
        //       false,
        //       false,
        //       false,
        //     );
          map
            .get(parameter.name as LisioNumericParameterNames)
            ?.toggle<number>(parameter.value as number, true, false, false);
      } else if (
        parameter.name === LisioStringParameterNames.UNDERLINE_RED ||
        parameter.name === LisioStringParameterNames.UNDERLINE_GREEN ||
        parameter.name === LisioStringParameterNames.UNDERLINE_BLUE
      ) {
        this._textInputMap
          .get(parameter.name)
          ?.toggle<string>(
            parameter.defaultValue as string,
            false,
            false,
            false,
          );
        this._textInputMap
          .get(parameter.name)
          ?.toggle<string>(parameter.value as string, true, false, false);
      } else if (parameter.name.toUpperCase() in LisioStringParameterNames) {
        this._radioInputMap
          .get(parameter.name)
          ?.find((radio) => radio.value === parameter.defaultValue)
          ?.toggle<boolean>(true, false, false, false);
        this._radioInputMap
          .get(parameter.name)
          ?.find((radio) => radio.value === parameter.value)
          ?.toggle<boolean>(true, true, false, false);
      }
    }
  }

  /**
   * Public method to toggle isActive input when another parameter or profile is enabled
   * @param {boolean} state - Indicates state of input
   * @param {boolean} hasToHandleOnChange - Indicates if handle on change
   * @returns Returns nothing
   * @source
   */
  public toggleIsActiveInput(
    state: boolean,
    hasToHandleOnChange: boolean,
  ): void {
    const isActiveInput: CheckboxInput | undefined =
      this._checkboxParameterInputMap.get(LisioBooleanParameterNames.IS_ACTIVE);
    if (isActiveInput != undefined) {
      isActiveInput.toggle<boolean>(state, hasToHandleOnChange, true, state);
    }
  }

  /**
   * Public method to know if is_active is the only input checked
   * @returns Returns if is_active is the only input checked
   * @source
   */
  public isReallyActive(): boolean {
    return (
      (this._activeProfiles.length > 0 ||
        this._activeParameters.length > 1 ||
        (UserController.current.currentUser != undefined &&
          UserController.current.currentUser.customParameters.has(
            LisioBooleanParameterNames.BOOK_PAGE,
          ) &&
          this._activeParameters.length === 1)) &&
      this._activeParameters.includes(LisioBooleanParameterNames.IS_ACTIVE)
    );
  }

  /**
   * Public method to know if is really configured
   * @returns Returns boolean
   * @source
   */
  public isReallyConfigured(): boolean {
    const filteredParameters = UserController.current.currentUser
      ?.customParameters
      ? new Map(
          [...UserController.current.currentUser?.customParameters].filter(
            ([item]) =>
              !this._hiddenParameters.has(item) &&
              item !== LisioBooleanParameterNames.IS_ACTIVE,
          ),
        )
      : new Map();
    const filteredProfils = UserController.current.currentUser?.profiles
      ? UserController.current.currentUser?.profiles.filter(
          (item) => !this._hiddenProfiles.has(item),
        )
      : [];
    return filteredParameters.size >= 1 || filteredProfils?.length >= 1;
  }

  /**
   * Public method to clear all underline text inputs
   * @returns Returns nothing
   * @source
   */
  public clearAllUnderlineTextInputs(): void {
    for (const activeParameter of this._activeParameters) {
      if (
        activeParameter === LisioStringParameterNames.UNDERLINE_RED ||
        activeParameter === LisioStringParameterNames.UNDERLINE_GREEN ||
        activeParameter === LisioStringParameterNames.UNDERLINE_BLUE
      ) {
        this._textInputMap.get(activeParameter)?.toggle("", false, true, false);
      }
    }
  }

  /**
   * Constructor of class {@link InputManager | InputManager}
   * @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 (InputManager._current == undefined) {
      InputManager._current = this;
      const profilNames: LisioProfileNames[] = Object.values(LisioProfileNames);
      for (const profilName of profilNames) {
        const profile =
          LisioProfileFactory.current.buildLisioProfile(profilName);
        for (const parameterName of profile.parameters.keys()) {
          if (this._mapParameterInProfiles.has(parameterName)) {
            this._mapParameterInProfiles.get(parameterName)?.push(profilName);
          } else {
            this._mapParameterInProfiles.set(parameterName, [profilName]);
          }
        }
      }
    } else {
      throw new Error(
        `Code : ${CoreErrorCodes.SINGLETON_NOT_UNIQUE}. Singleton already initialize`,
      );
    }
  }
}

export { InputManager };
