/**
 * @mergeTarget
 * @module Src/Components/CustomIcon
 */

import {
  AssetsLoader,
  LisioComponent,
  LisioComponentStyles,
} from "@lisio/lisio-engine";
import { Icon, IconsObject } from "../component-types";
import { customIconStyles } from "./custom-icon.css";
import { ErrorCodes } from "../../../../misc/error-codes";
import { translateEvent } from "../../../../misc/events";
import { MessageManager } from "../../../managers/message-manager";

/**
 * Class representing an icon component extending LisioComponent.\
 * It aims to represent an icon component.\
 * An icon component is basically a svg, it content will be load dynamically.\
 */
class CustomIcon extends LisioComponent {
  /**
   * Private attribute to store icon file
   * @source
   */
  private _iconFile: string;

  /**
   * Private attribute to store icon name
   * @source
   */
  private _iconName: string;

  /**
   * Private attribute to store if icon was loaded
   * @source
   */
  private _iconWasLoaded: boolean = false;

  /**
   * @async
   * Public method implementing abstract method render of LisioComponent
   * @param {boolean | undefined} hasToLoadAssets - Indicates if icon has to be loaded
   * @returns Returns a promise containing the representation of a svg icon in HTML string
   * @source
   */
  public async render(hasToLoadAssets?: boolean): Promise<string> {
    if (hasToLoadAssets != undefined && hasToLoadAssets) {
      const iconsObject: IconsObject = await AssetsLoader.current
        .loadAsset<IconsObject>(`./icons/${this._iconFile}.json`)
        .catch(() => {
          throw new Error(
            `Code : ${ErrorCodes.TRANSLATIONS_FILE_NOT_FOUND}. Asset file not found : ${this._iconFile}`,
          );
        });
      if (this._iconName in iconsObject) {
        const icon: Icon = iconsObject[this._iconName];
        this._iconWasLoaded = true;
        return `
        <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="${
          icon.width
        }" height="${icon.height}" viewBox="0 0 ${icon.width} ${
          icon.height
        }" fill="none" class="lisio-custom-icon ${this.renderClasses()}">
          ${icon.svg}
        </svg>
      `;
      } else {
        throw new Error(
          `Icone name ${this._iconName} not in file ${this._iconFile}`,
        );
      }
    } else {
      return `
        <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="0" height="0" viewBox="0 0 0 0" fill="none" class="lisio-custom-icon ${this.renderClasses()}" data-file-name="${
          this._iconFile
        }" data-icon-name="${this._iconName}">
        </svg>
      `;
    }
  }

  /**
   * Public method to be called after render
   * @returns Returns nothing
   * @source
   */
  public postRender(): void {
    if (!this._iconWasLoaded && this._htmlElement != undefined) {
      AssetsLoader.current.intersectionObserver.observe(this._htmlElement);
    }
    if (
      this._htmlElement?.classList.contains("trans-icon") &&
      this._htmlElement != undefined &&
      !this._iconName.includes("trad")
    ) {
      this.changeIcon("trans-icons", MessageManager.current.flagIso);
      window.addEventListener(translateEvent.type, async (e: any) => {
        if (e.detail.flagIso) {
          this.changeIcon("trans-icons", e.detail.flagIso);
        } else {
          this.changeIcon("trans-icons", MessageManager.current.defaultFlagIso);
        }
      });
    }
  }

  /**
   * Public method to change the displayed icon
   * @param {string} iconFile - The new icon's file name
   * @param {string} iconName - The new icon name
   */
  public changeIcon(iconFile: string, iconName: string) {
    AssetsLoader.current
      .loadAsset<IconsObject>(`./icons/${iconFile}.json`)
      .then((iconsObject: IconsObject) => {
        if (iconName in iconsObject) {
          const icon: Icon = iconsObject[iconName];
          this._iconWasLoaded = true;
          this._htmlElement!.innerHTML = icon.svg;
          this._htmlElement?.setAttribute("width", icon.width.toString());
          this._htmlElement?.setAttribute("height", icon.height.toString());
          this._htmlElement?.setAttribute(
            "viewBox",
            `0 0 ${icon.width} ${icon.height}`,
          );
        }
      });
  }

  /**
   * Constructor of class {@link CustomIcon | CustomIcon}
   * @param {string} src - Source of icon
   * @param {string} iconName - Icon name
   * @param {string[] | undefined} cssClasses - Classes of the component
   * @source
   */
  constructor(src: string, iconName: string, cssClasses?: string[]) {
    super(CustomIcon.name, undefined, cssClasses);
    this._iconFile = src;
    this._iconName = iconName;
  }
}

new LisioComponentStyles(CustomIcon.name, customIconStyles);

export { CustomIcon };
