import LisioStyleSheetController from "../controllers/lisio-stylesheet-controller";
import LisioCSSProperties from "../enums/lisio-css-properties";
import LisioTextTreeWalker from "../walkers/lisio-text-tree-walker";
import LisioAdapter from "./lisio-adapter";

/**
 * Class representing a bigger click adapter extending an adapter.\
 * It aims to represents the font style functionality of Lisio.\
 * A bigger click adapter is basically a functionality of Lisio which will change the bigger click of texts in the main page.\
 */
class LisioBiggerClickAdapter extends LisioAdapter<number> {
  private _mouseEnterHandlerBind = this.mouseEnterHandler.bind(this);
  private _mouseLeaveHandlerBind = this.mouseLeaveHandler.bind(this);
  private _numericValue = 0;

  /**
   * Public method implementing abstract method adapt of Adapter
   * @param {LisioTextTreeWalker} walker - A walker to explore the DOM
   * @param {string} value - Value of the functionality
   * @returns Returns nothing
   * @source
   */
  public adapt(_: LisioTextTreeWalker, value: number): void {
    const elements = document.body.querySelectorAll<HTMLElement>(
      "input, button, a, select, textarea",
    );
    for (const element of elements) {
      this._numericValue = value;
      this.adaptFunction(element, value);
    }
  }

  protected adaptFunction(element: HTMLElement, value: number): void {
    const prefix = "lisio-bigger-";
    let paddingT = 0;
    let paddingR = 0;
    let paddingB = 0;
    let paddingL = 0;
    if (value === 0) {
      element.removeEventListener("mouseenter", this._mouseEnterHandlerBind);
      element.removeEventListener("mouseleave", this._mouseLeaveHandlerBind);
      const classesToRemove = Array.from(element.classList).filter((cssClass) =>
        cssClass.includes(prefix),
      );
      for (const classToRemove of classesToRemove) {
        LisioStyleSheetController.current.removeRule(classToRemove);
        element.classList.remove(classToRemove);
      }
    } else {
      const classToRemove = Array.from(element.classList).find((cssClass) =>
        cssClass.includes(prefix),
      );
      if (classToRemove != undefined) {
        element.classList.remove(classToRemove);
      }
      if (element.dataset.lisioBigger == null) {
        const { paddingTop, paddingRight, paddingBottom, paddingLeft } =
          window.getComputedStyle(element);
        paddingT = Number.parseInt(paddingTop);
        paddingR = Number.parseInt(paddingRight);
        paddingB = Number.parseInt(paddingBottom);
        paddingL = Number.parseInt(paddingLeft);
      } else {
        const paddings = element.dataset.lisioBigger.split(" ");
        paddingT = Number.parseInt(paddings[0]);
        paddingR = Number.parseInt(paddings[1]);
        paddingB = Number.parseInt(paddings[2]);
        paddingL = Number.parseInt(paddings[3]);
      }
      element.dataset.lisioBigger = `${paddingT} ${paddingR} ${paddingB} ${paddingL}`; //on attribut la valeur par défaut
      paddingT = Math.ceil(paddingT + 5 * value);
      paddingR = Math.ceil(paddingR + 5 * value);
      paddingB = Math.ceil(paddingB + 5 * value);
      paddingL = Math.ceil(paddingL + 5 * value);
      element.addEventListener("mouseenter", this._mouseEnterHandlerBind);
      element.addEventListener("mouseleave", this._mouseLeaveHandlerBind);

      LisioStyleSheetController.current.replaceImportantInStyleAttribute(
        [
          LisioCSSProperties.PADDING,
          LisioCSSProperties.PADDING_TOP,
          LisioCSSProperties.PADDING_RIGHT,
          LisioCSSProperties.PADDING_BOTTOM,
          LisioCSSProperties.PADDING_LEFT,
        ],
        element,
      );
      const selector = `${paddingT}${paddingR}${paddingB}${paddingL}`;
      const propertiesToAdd: Map<string, string> = new Map<string, string>([
        [
          LisioCSSProperties.PADDING,
          `${paddingT}px ${paddingR}px ${paddingB}px ${paddingL}px`,
        ],
        [LisioCSSProperties.BORDER, "5px solid blue"],
      ]);
      LisioStyleSheetController.current.insertRule(
        `.lisio-bigger-${selector}`,
        propertiesToAdd,
      );
      // propertiesToAdd.set(LisioCSSProperties.LINE_HEIGHT, "1px");
      propertiesToAdd.set(LisioCSSProperties.DISPLAY, "inline-block");
      LisioStyleSheetController.current.insertRule(
        `.lisio-bigger-display-${selector}`,
        propertiesToAdd,
      );
    }
  }

  private mouseEnterHandler(event: MouseEvent) {
    if (event.target instanceof HTMLElement) {
      const paddings = event.target?.dataset.lisioBigger?.split(" ");
      if (paddings != undefined) {
        const paddingT = parseInt(paddings[0]);
        const paddingR = parseInt(paddings[1]);
        const paddingB = parseInt(paddings[2]);
        const paddingL = parseInt(paddings[3]);
        const selectorValue = `${Math.ceil(
          paddingT + 5 * this._numericValue,
        )}${Math.ceil(paddingR + 5 * this._numericValue)}${Math.ceil(
          paddingB + 5 * this._numericValue,
        )}${Math.ceil(paddingL + 5 * this._numericValue)}`;
        if (window.getComputedStyle(event.target).display == "inline") {
          event.target.classList.add(`lisio-bigger-display-${selectorValue}`);
        } else {
          event.target.classList.add(`lisio-bigger-${selectorValue}`);
        }
      }
    }
  }

  private mouseLeaveHandler(event: MouseEvent) {
    if (event.target instanceof HTMLElement) {
      const paddings = event.target?.dataset.lisioBigger?.split(" ");
      if (paddings != undefined) {
        const paddingT = parseInt(paddings[0]);
        const paddingR = parseInt(paddings[1]);
        const paddingB = parseInt(paddings[2]);
        const paddingL = parseInt(paddings[3]);
        const selectorValue = `${Math.ceil(
          paddingT + 5 * this._numericValue,
        )}${Math.ceil(paddingR + 5 * this._numericValue)}${Math.ceil(
          paddingB + 5 * this._numericValue,
        )}${Math.ceil(paddingL + 5 * this._numericValue)}`;
        event.target.classList.remove(`lisio-bigger-${selectorValue}`);
        event.target.classList.remove(`lisio-bigger-display-${selectorValue}`);
      }
    }
  }
}

export default LisioBiggerClickAdapter;
