/**
 * @mergeTarget
 * @module Src/Components/CustomInput
 */

import {
  LisioBooleanParameterNames,
  LisioParameter,
  LisioParameterNames,
  LisioProfile,
  LisioProfileFactory,
  LisioProfileNames,
  LisioStringParameter,
  LisioStringParameterNames,
} from "@lisio/lisio-profils";
import { InputManager } from "../../../../../managers/input-manager";
import { CustomInput } from "../../custom-input";
import { MessageManager } from "../../../../../managers/message-manager";
import { UserController } from "../../../../../controllers/user-controller";
// import { CustomText } from "../../../custom-text/custom-text";
import {
  TranslationController,
  TranslationLanguages,
} from "../../../../../controllers/translation/translation-controller";
import { MergedCategoriesNames } from "../../../../screens/screen-types";
import { ScreenManager } from "../../../../../managers/screen-manager";
import { ElementsContainer } from "../../../containers/elements-container/elements-container";
import { CheckboxButton } from "../../../checkbox-button/checkbox-button";
import { translateEvent } from "../../../../../../misc/events";

/**
 * Class representing a checkbox input component extending CustomInput.\
 * It aims to represent a checkbox input component.\
 * A checkbox input component is basically a component to display a checkbox input.\
 */
class CheckboxInput extends CustomInput {
  /**
   * Private attribute to store name of input
   * @source
   */
  private _name: LisioBooleanParameterNames | LisioProfileNames;

  /**
   * Private attribute to store state text
   * @source
   */
  // private _stateText: CustomText;

  /**
   * Private attribute to store parent button
   * @source
   */
  private _checkboxButton: CheckboxButton;

  /**
   * Getter for attribute {@link _isChecked | _isChecked}
   * @returns Returns _isChecked attribute
   * @source
   */
  public get isChecked(): boolean {
    return this._attributes.has("checked");
  }

  /**
   * @async
   * Public method implementing abstract method render of LisioComponent
   * @returns Returns a promise containing the representation of a checkbox input in HTML string
   * @source
   */
  public async render(): Promise<string> {
    return `
        <input name="${this._name.replace("_", "-")}" ${
          this._id != undefined ? `id=${this._id}` : ""
        } type="checkbox" class="lisio-custom-input ${this.renderClasses()}" ${this.renderAttributes()}
        />
      `;
  }

  /**
   * @async
   * Public method to toggle input implementing parent abstract method
   * @typeParam T - Indicates type value expected a boolean value
   * @param {T} value - Value of input
   * @param {boolean} hasToHandleOnChange - Indicates if input has to handle on change
   * @param {boolean} hasToUpdateUser - Indicates if input has to update user
   * @param {boolean} hasToEnableActiveInput - Indicates if has to enable active input
   * @returns Returns a promise containing nothing
   * @source
   */
  public async toggle<T extends boolean | number | string>(
    value: T,
    hasToHandleOnChange: boolean,
    hasToUpdateUser: boolean,
    hasToEnableActiveInput: boolean,
  ): Promise<void> {
    if (
      typeof value === "boolean" &&
      this._attributes.has("checked") !== value
    ) {
      if (value) {
        this.addAttributes("checked", String(value));
      } else {
        this.removeAttributes("checked");
      }
      this._checkboxButton.addAttributes("aria-checked", String(value));
      if (this._htmlElement != undefined) {
        (this._htmlElement as HTMLInputElement).checked = value;
      }
      if (hasToUpdateUser) {
        await UserController.current.updateUserBoolean(this._name, value);
      }
      // this._stateText.changeText(
      //   value
      //     ? "switch-active"
      //     : "switch-inactive"
      // );
      // if (value) {
      //   this._stateText.htmlElement?.classList.add("bold");
      // } else {
      //   this._stateText.htmlElement?.classList.remove("bold");
      // }
      this.generalToggleBehavior(this._name, value, hasToEnableActiveInput);
      if (hasToHandleOnChange) {
        await this.handleOnChange();
      }
      if (this._htmlElement != undefined) {
        (this._htmlElement as HTMLInputElement).checked = value;
        // this._htmlElement.setAttribute("aria-checked", String(value));
      }
      if (this._name === LisioBooleanParameterNames.IS_ACTIVE) {
        if (!value) {
          const lngDefault = TranslationLanguages.DEFAULT;
          await TranslationController.current.loadTranslationFile(lngDefault);
          window.dispatchEvent(
            new CustomEvent(translateEvent.type, {
              detail: {
                // lang: lngDefault,
                flagIso: lngDefault,
              },
            }),
          );
        }
      }
    }
  }

  /**
   * @async
   * Protected method to handle on change event implementing parent abstract method
   * @returns Returns a promise containing nothing
   * @source
   */
  public async handleOnChange(): Promise<void> {
    const isChecked: boolean = this._attributes.has("checked");
    if (this._name.toUpperCase() in LisioBooleanParameterNames) {
      MessageManager.current?.booleanParameterAdaptMessage(
        this._name as LisioBooleanParameterNames,
        isChecked,
      );
      if (
        this._name === LisioBooleanParameterNames.IS_ACTIVE &&
        UserController.current.currentUser != undefined
      ) {
        if (isChecked) {
          InputManager.current.refreshInputs(
            UserController.current.currentUser.profiles,
            Array.from(
              UserController.current.currentUser.customParameters.values(),
            ).filter(
              (parameter) =>
                parameter.name !== LisioBooleanParameterNames.IS_ACTIVE,
            ),
          );
        }
        ScreenManager.current.toggleNavAndHeadersButtonAndUserManagementButtonAndChangeManagementScreenTitle(
          isChecked,
        );
      }
    } else {
      if (this._name === LisioProfileNames.UNDERLINE) {
        if (isChecked) {
          if (
            UserController.current.currentUser?.customParameters.has(
              LisioStringParameterNames.UNDERLINE_RED,
            )
          ) {
            const underlineRed: LisioStringParameter =
              UserController.current.currentUser?.customParameters.get(
                LisioStringParameterNames.UNDERLINE_RED,
              )! as LisioStringParameter;
            MessageManager.current.stringParameterAdaptMessage(
              LisioStringParameterNames.UNDERLINE_RED,
              underlineRed.value,
              underlineRed.defaultValue,
            );
          }
          if (
            UserController.current.currentUser?.customParameters.has(
              LisioStringParameterNames.UNDERLINE_GREEN,
            )
          ) {
            const underlineGreen: LisioStringParameter =
              UserController.current.currentUser?.customParameters.get(
                LisioStringParameterNames.UNDERLINE_GREEN,
              )! as LisioStringParameter;
            MessageManager.current.stringParameterAdaptMessage(
              LisioStringParameterNames.UNDERLINE_GREEN,
              underlineGreen.value,
              underlineGreen.defaultValue,
            );
          }
          if (
            UserController.current.currentUser?.customParameters.has(
              LisioStringParameterNames.UNDERLINE_BLUE,
            )
          ) {
            const underlineBlue: LisioStringParameter =
              UserController.current.currentUser?.customParameters.get(
                LisioStringParameterNames.UNDERLINE_BLUE,
              )! as LisioStringParameter;
            MessageManager.current.stringParameterAdaptMessage(
              LisioStringParameterNames.UNDERLINE_BLUE,
              underlineBlue.value,
              underlineBlue.defaultValue,
            );
          }
        } else {
          InputManager.current.clearAllUnderlineTextInputs();
        }
      }
      const profile: LisioProfile =
        LisioProfileFactory.current.buildLisioProfile(
          this._name as LisioProfileNames,
        );
      const parameters: LisioParameter[] = Array.from(
        profile.parameters.values(),
      );
      const bookPageOrReadingParameterName = parameters.find((parameter) =>
        (
          [
            LisioBooleanParameterNames.BOOK_PAGE,
            LisioBooleanParameterNames.READING_MODE,
          ] as LisioParameterNames[]
        ).includes(parameter.name),
      )?.name as
        | LisioBooleanParameterNames.BOOK_PAGE
        | LisioBooleanParameterNames.READING_MODE
        | undefined;
      // if(__BUILD_TARGET__ === "extension"){
      //   if(bookPageOrReadingParameterName === LisioBooleanParameterNames.READING_MODE){
      //     MessageManager.current.sendTransBannerPopupMessage(
      //       this._name.replace(/_/g, "-"),
      //       bookPageOrReadingParameter.
      //     );
      //   }
      // }
      if (
        bookPageOrReadingParameterName != undefined &&
        this.isChecked &&
        !MessageManager.current.originOfMessages?.includes("mobiledition")
      ) {
        if (__BUILD_TARGET__ === "extension") {
          if (
            parameters.some((parameter) =>
              (
                [
                  LisioBooleanParameterNames.BOOK_PAGE,
                  LisioBooleanParameterNames.READING_MODE,
                ] as LisioParameterNames[]
              ).includes(parameter.name),
            )
          ) {
            MessageManager.current.sendTransBannerPopupMessage(
              this._name.replace(/_/g, "-"),
              bookPageOrReadingParameterName,
              this._id || "",
            );
          }
        } else {
          if(MessageManager.current.originOfMessages?.includes("mobiledition")){
            await InputManager.current.adaptParameters(
              profile.name,
              parameters,
              isChecked,
              false,
            );
          }else{
            MessageManager.current.sendTransBannerPopupMessage(
              this._name.replace(/_/g, "-"),
              bookPageOrReadingParameterName,
              this._id || "",
            );
          }
        }
      }else{
        await InputManager.current.adaptParameters(
          profile.name,
          parameters,
          isChecked,
          false,
        );
      }

      if (__BUILD_TARGET__ === "extension") {
        // if(bookPageOrReadingParameterName === LisioBooleanParameterNames.READING_MODE){
        MessageManager.current.profileAdaptMessage(
          this._name as LisioProfileNames,
          isChecked,
        );
        // }
      } else {
        MessageManager.current.profileAdaptMessage(
          this._name as LisioProfileNames,
          isChecked,
        );
      }
    }
  }

  /**
   * Protected method to handle initialization implementing parent abstract method
   * @param {boolean} hasToEnableActiveInput - Indicates if has to enable active input
   * @returns Returns nothing
   * @source
   */
  public handleOnInit(hasToEnableActiveInput: boolean): void {
    if (
      UserController.current.currentUser != undefined &&
      this._attributes.has("checked")
    ) {
      this.removeAttributes("checked");
      this.toggle<boolean>(
        true,
        this._name !== LisioBooleanParameterNames.IS_ACTIVE,
        false,
        hasToEnableActiveInput,
      );
    }
  }

  /**
   * Constructor of class {@link RadioInput | RadioInput}
   * @param {boolean} isChecked - State of input
   * @param {CustomText} stateText - State text of input
   * @param {LisioBooleanParameterNames | LisioProfileNames} name - Name of functionality
   * @param {(event: Event) => void} handler - Extra behvior for on change event
   * @param {string} id - Id of component
   * @param {string} screenName - Screen name including this input
   * @param {CheckboxButton} checkboxButton - Checkbox button
   * @param {MergedCategoriesNames | undefined} categoryName - Category name containing parameter or profile related to this input
   * @param {string | undefined} parentScreenName - Parent screen name in screen tree
   * @param {ElementsContainer | undefined} infobox - Infobox linked to this component
   * @param {string[] | undefined} cssClasses - CSS classes of component
   * @param {object | undefined} aria - Aria attributes
   * @property {object | undefined} aria.label - Aria label datas
   * @property {boolean | undefined} aria.label.noTranslate - Indicates if label need to be translated
   * @property {string} aria.label.id - Id of the text for aria label
   * @property {boolean | undefined} aria.hidden - Aria hidden
   */
  constructor(
    isChecked: boolean,
    // stateText: CustomText,
    name: LisioBooleanParameterNames | LisioProfileNames,
    handler: (event: Event) => void,
    id: string,
    screenName: string,
    checkboxButton: CheckboxButton,
    categoryName?: MergedCategoriesNames,
    parentScreenName?: string,
    infobox?: ElementsContainer,
    cssClasses?: string[],
    aria?: {
      label?: {
        noTranslate?: boolean;
        id: string;
      };
      hidden?: boolean;
    },
  ) {
    const attributes: Map<string, string> = new Map<string, string>();
    if (aria) {
      if (aria.label) {
        attributes.set(
          "aria-label",
          aria.label.noTranslate
            ? aria.label.id
            : TranslationController.current.getTranslation(aria.label.id),
        );
      }
      if (aria.hidden != undefined) {
        attributes.set("aria-hidden", String(aria.hidden));
      }
    }
    if (isChecked) {
      attributes.set("checked", "true");
    }
    attributes.set("tabindex", "-1");
    super(
      id,
      screenName,
      categoryName,
      parentScreenName,
      infobox,
      cssClasses,
      attributes,
    );
    InputManager.current.addInputInMap(name, this);
    this._name = name;
    // this._stateText = stateText;
    this._checkboxButton = checkboxButton;
    this._eventListeners.push({
      type: "change",
      handler: (event: unknown) => {
        if (event instanceof Event) {
          handler(event);
          this.toggle<boolean>(
            (event.target as HTMLInputElement).checked,
            true,
            true,
            true,
          );
        }
      },
    });
  }
}

export { CheckboxInput };
