/**
 * @mergeTarget
 * @module Src/Components/CustomButton
 */

import { LisioComponent, LisioComponentStyles } from "@lisio/lisio-engine";
import { LisioAriaLabelComponent } from "../LisioAriaLabelComponent/LisioAriaLabelComponent";
import { customButtonStyles } from "./custom-button.css";

/**
 * Class representing a button component extending LisioAriaLabelComponent.\
 * It aims to represent a button component.\
 * A button component is basically a container for elements which have behaviours on click.\
 */
class CustomButton extends LisioAriaLabelComponent {
  /**
   * @async
   * Public method implementing abstract method render of LisioComponent
   * @returns Returns a promise containing the representation of a button in HTML string
   * @source
   */
  public async render(): Promise<string> {
    return `
      <button id="${
        this._id
      }" class="lisio-custom-button ${this.renderClasses()}" ${this.renderAttributes()}
      >
        <children></children>
      </button>
    `;
  }

  /**
   * Constructor of class {@link CustomButton | CustomButton}
   * @param {string} id - Id of the component
   * @param {LisioComponent[]} children - Children of component
   * @param {(...args: any) => void} eventHandler - Handler for click event
   * @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
   * @property {string | undefined} aria.controls - Arria controls
   * @property {boolean | undefined} aria.checked - Aria checked
   * @property {boolean | undefined} aria.hasPopup - Aria hasPopup
   * @param {object[] | undefined} otherEventHandlers - Other event handlers
   * @property {string} otherEventHandlers.triggerer - Triggerer of the event
   * @property {(...args: any) => void} otherEventHandlers.handler - Handler of the event
   * @param {"checkbox" | "link" | "spinbutton" | "tab" | undefined} role
   * @source
   */
  constructor(
    id: string,
    children: LisioComponent[],
    eventHandler: (...args: any) => void,
    cssClasses?: string[],
    aria?: {
      label?: {
        noTranslate?: boolean;
        id: string;
      };
      hidden?: boolean;
      controls?: string;
      checked?: boolean;
      hasPopup?: string;
      describedby?: string;
    },
    role?: "checkbox" | "link" | "spinbutton" | "tab",
    tabindex?: "-1" | "0",
    otherEventHandlers?: {
      triggerer: string;
      handler: (...args: any) => void;
    }[],
  ) {
    const attributes: Map<string, string> = new Map<string, string>();
    if (aria) {
      if (aria.hidden != undefined) {
        attributes.set("aria-hidden", String(aria.hidden));
      }
      if (aria.controls) {
        attributes.set("aria-controls", aria.controls);
      }
      if (aria.checked != undefined) {
        attributes.set("aria-checked", String(aria.checked));
      }
      if (aria.hasPopup) {
        attributes.set("aria-haspopup", aria.hasPopup);
      }
      if (aria.describedby) {
        attributes.set("aria-describedby", aria.describedby);
      }
      if (tabindex) {
        attributes.set("tabindex", tabindex);
      }
    }
    if (role) {
      attributes.set("role", role);
      if (role === "tab") {
        attributes.set("aria-selected", "false");
      }
    }
    super(
      CustomButton.name,
      aria?.label?.id,
      id,
      cssClasses,
      attributes,
      aria?.label?.noTranslate,
    );
    this._children = children;
    this._eventListeners.push({
      type: "click",
      handler: eventHandler,
    });
    if (otherEventHandlers) {
      otherEventHandlers.forEach((otherEvent) => {
        this._eventListeners.push({
          type: otherEvent.triggerer,
          handler: otherEvent.handler,
        });
      });
    }
  }
}

new LisioComponentStyles(CustomButton.name, customButtonStyles);

export { CustomButton };
