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

import {
  LisioBooleanParameterNames,
  LisioStringParameterNames,
} from "@lisio/lisio-profils";
import { ElementsContainer } from "../../../containers/elements-container/elements-container";
import { CustomIcon } from "../../../custom-icon/custom-icon";
import { CustomText } from "../../../custom-text/custom-text";
import { InputManager } from "../../../../../managers/input-manager";
import { RadioInput } from "../input/radio-input";
import { customChoiceItemStyles } from "./custom-choice-item.css";
import { LisioComponent, LisioComponentStyles } from "@lisio/lisio-engine";
import {
  MergedCategoriesNames,
} from "../../../../screens/screen-types";
import { TextsContainer } from "../../../containers/texts-container/texts-container";
import { TranslationLanguages } from "../../../../../controllers/translation/translation-languages-enum-and-types";
import { ScreenManager } from "../../../../../managers/screen-manager";
import { TranslationController } from "../../../../../controllers/translation/translation-controller";
import { translateEvent } from "../../../../../../misc/events";

/**
 * Class representing a choice item component extending LisioComponent.\
 * It aims to represent a choice item component.\
 * A choice item component is basically a component to display a radio input as a choice list item.\
 */
class CustomChoiceItem extends LisioComponent {
  /**
   * Private attribute to store CSS classes label
   * @source
   */
  private _cssClassesLabel: string[] = [];
  /**
   * Private attribute to for attribute
   * @source
   */
  private _labelFor: string = "";
  /**
   * Private attribute to radio input
   * @source
   */
  private _input: RadioInput;

  private _langVoiceAvailable: boolean;

  /**
   * Private attribute to infobox text
   * @source
   */
  private _textInfobox: string;

  /**
   * Private attribute to synth button text
   * @source
   */
  private _synthButtonText: string;

  /**
   * Private attribute to arrow icon
   * @source
   */
  private _arrowIcon: CustomIcon;

  /**
   * Getter for attribute {@link _input | _input}
   * @returns Returns _input attribute
   * @source
   */
  public get input(): RadioInput {
    return this._input;
  }

  /**
   * Setter for attribute {@link _langVoiceAvailable | _langVoiceAvailable}
   * @param {boolean} value - New value of input
   * @source
   */
  public set langVoiceAvailable(value: boolean) {
    this._langVoiceAvailable = value;
  }

  /**
   * @async
   * Public method implementing abstract method render of LisioComponent
   * @returns Returns a promise containing the representation of a choice item in HTML string
   * @source
   */
  public async render(): Promise<string> {
    const arrowIconHTML = await this._arrowIcon.render(true);
    return `
      <li class="lisio-custom-choice-item ${this.renderClasses()}">
        <label class="${this._cssClassesLabel.join(" ")}" for="${
          this._labelFor
        }">
        <children></children>
        </label>
        ${
          this._langVoiceAvailable &&
          !InputManager.current.hiddenParameters.has(
            LisioBooleanParameterNames.SPEECH_SYNTHESIS_STATE,
          )
            ? `
          <div class="infobox-radio">
            <p class="lisio-custom-text info-text" aria-hidden="true">
              ${this._textInfobox}
            </p>
            <button class='lisio-custom-button btn-pill btn-outline-grey infobox-synth-button' tabindex="0">
              <p class='lisio-custom-text regular' aria-hidden="true">
                ${this._synthButtonText}
              </p>
              ${arrowIconHTML}
            </button>
          </div>
      `
            : ""
        }
      </li>
    `;
  }

  postRender(): void {
    this._textInfobox = TranslationController.current.getTranslation(
      "translation-radio-item-infobox",
    );
    this._synthButtonText =
      TranslationController.current.getTranslation("synth-title");
    if (
      this._htmlElement &&
      this._htmlElement !== null &&
      this._langVoiceAvailable &&
      this._htmlElement.querySelector(".info-text") &&
      this._htmlElement.querySelector(".infobox-synth-button p")
    ) {
      this._htmlElement.querySelector(".info-text")!.textContent =
        this._textInfobox;
      this._htmlElement.querySelector(".infobox-synth-button p")!.textContent =
        this._synthButtonText;
    }

    this._htmlElement
      ?.querySelector(".infobox-synth-button")
      ?.addEventListener("click", () => {
        ScreenManager.current.changeScreen(
          "synth-screen",
          undefined,
          true,
        );
      });
    window.addEventListener(translateEvent.type, () => {
      this._textInfobox = TranslationController.current.getTranslation(
        "translation-radio-item-infobox",
      );
      this._synthButtonText =
        TranslationController.current.getTranslation("synth-title");
      if (
        this._htmlElement &&
        this._htmlElement !== null &&
        this._langVoiceAvailable &&
        this._htmlElement.querySelector(".info-text") &&
        this._htmlElement.querySelector(".infobox-synth-button p")
      ) {
        this._htmlElement.querySelector(".info-text")!.textContent =
          this._textInfobox;
        this._htmlElement.querySelector(
          ".infobox-synth-button p",
        )!.textContent = this._synthButtonText;
      }
    });
  }

  /**
   * Constructor of class {@link CustomChoiceItem | CustomChoiceItem}
   * @param {LisioStringParameterNames | "users-choice"} parameterName - Name of functionality
   * @param {string} text - Label text
   * @param {string} value - Value of input
   * @param {boolean} checked - Indicates if input is checked
   * @param {string} screenName - Screen name including this input
   * @param {(input: RadioInput) => void} lastCheckecHandler - Handler for deactive last checked radio input
   * @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 {object | undefined} icon - Icon object
   * @property {string} icon.fileName - Icon file name
   * @property {string} icon.iconName - Icon name
   * @param {string[] | undefined} iconClasses - CSS class of icon
   * @param {boolean | undefined} noTranslate - Indicates if text has to be translated
   * @param {string[] | undefined} cssClasses - CSS classes of component
   * @param {string[] | undefined} cssClassesLabel - CSS classes of label
   * @param {boolean | undefined} noText - Indicates if input has text
   * @source
   */
  constructor(
    parameterName: LisioStringParameterNames | "users-choice",
    text: string,
    value: string,
    checked: boolean,
    screenName: string,
    lastCheckecHandler: (input: RadioInput) => void,
    categoryName?: MergedCategoriesNames,
    parentScreenName?: string,
    infobox?: ElementsContainer,
    icon?: {
      fileName: string;
      iconName: string;
    },
    iconClasses?: string[],
    noTranslate?: boolean,
    cssClasses?: string[],
    cssClassesLabel?: string[],
    noText?: boolean,
    specificLabel?: {
      textId: string;
      noTranslate?: boolean;
    },
  ) {
    super(CustomChoiceItem.name, undefined, cssClasses);
    this._textInfobox = TranslationController.current.getTranslation(
      "translation-radio-item-infobox",
    );
    this._synthButtonText =
      TranslationController.current.getTranslation("synth-title");
    this._labelFor = `${parameterName}-${value}-input`
      .replace(/_/g, "-")
      .toLowerCase();

    this._arrowIcon = new CustomIcon("misc-icons", "Arrow", [
      "arrow-secondary",
      "grey",
      "m-left",
    ]);
    if (cssClassesLabel != undefined) {
      this._cssClassesLabel = cssClassesLabel;
    }
    const handler = async (_: any) => {
      if (parameterName != "users-choice") {
        await InputManager.current.disableProfileLinkToParameter(parameterName);
      }
    };
    this._input = new RadioInput(
      checked,
      value,
      parameterName,
      lastCheckecHandler,
      handler,
      this._labelFor,
      screenName,
      categoryName,
      parentScreenName,
      infobox,
      undefined,
      {
        hidden: false,
        label: {
          noTranslate: true,
          id: noText ? text : "",
        },
      },
    );
    this._langVoiceAvailable = false;
    if (checked) {
      lastCheckecHandler(this._input);
    }
    const elementContainer: LisioComponent = new ElementsContainer(
      [],
      undefined,
      ["transparent"],
    );
    if (!noText || noText == undefined) {
    }
    if (icon != undefined) {
      if (noText != true) {
        elementContainer.children.push(
          new CustomIcon(
            icon.fileName,
            icon.iconName,
            iconClasses == undefined ? ["black"] : iconClasses,
          ),
        );
      } else {
        elementContainer.children.push(
          new CustomIcon(
            icon.fileName,
            icon.iconName,
            iconClasses == undefined ? ["black"] : iconClasses,
          ),
        );
      }
    }
    const labelTextClasses: string[] = ["regular"];
    if (noText) {
      labelTextClasses.push("hidden");
    }
    const attributes: Map<string, string> = new Map<string, string>();
    if (
      (parameterName === LisioStringParameterNames.GOOGLE_TRANSLATION ||
        parameterName === LisioStringParameterNames.DEEPL_TRANSLATION) &&
      value != TranslationLanguages.DEFAULT
    ) {
      attributes.set("lang", value.replace("_", "-").toLowerCase());
    }
    const labelText: CustomText = new CustomText(
      "p",
      text,
      noTranslate,
      labelTextClasses,
      undefined,
      undefined,
      undefined,
      attributes,
    );
    elementContainer.children.push(labelText);
    this._children.push(this._input, elementContainer);

    if (specificLabel) {
      const specificLabelContainer = new TextsContainer([], ["specific-label"]);
      specificLabelContainer.children.push(
        new CustomText("p", specificLabel.textId, specificLabel.noTranslate),
      );
      this._children.push(specificLabelContainer);
    }

    if (parameterName != "users-choice" && value != "default" && checked) {
      InputManager.current.addOrRemoveEnabledInput(parameterName, true);
    }
    if (this.findChildByAttribute("checked")) {
      this.addClasses(["checked"]);
    }
  }
}

new LisioComponentStyles(CustomChoiceItem.name, customChoiceItemStyles);

export { CustomChoiceItem };
