/**
 * @mergeTarget
 * @module Src/Versions
 */

import { CompleteVersion } from "./complete-version";
import { LisioWidgetVersionNames, WidgetVersion } from "./widget-version";
import { EssentialVersion } from "./essential-version";
import { FirstVersion } from "./first-version";
import { WelcomeVersion } from "./welcome-version";
import { CoreErrorCodes } from "@lisio/lisio-engine";
import { ErrorCodes } from "../../misc/error-codes";

/**
 * ## How to create a new version ? Part 2
 *
 * Create a builder method and add it to {@link LisioWidgetVersionFactory._builders | _builders}.\
 *
 * ## How to delete a version ? Part 2
 *
 * Delete the builder method and remove it from {@link LisioWidgetVersionFactory._builders | _builders}.\
 *
 * ## Documentation
 *
 * Abstract class representing a widget version.\
 * It aims to centralize the logic of a widget version.\
 * A widget version allows to define which screen and features has to be included.\
 * To execute his responsability this class provides :
 *  * Initialization method
 *  * Methods to create each categories and they corresponding screen
 *  * Method to check if group is empty or not
 *  * Method to get group position
 */
class LisioWidgetVersionFactory {
  /**
   * Private attribute to store instance of {@link LisioWidgetVersionFactory | LisioWidgetVersionFactory}
   * @source
   */
  private static _current: LisioWidgetVersionFactory;

  /**
   * @static
   * Getter for attribute {@link _current | _current}
   * @returns Returns _current attribute
   * @source
   */
  public static get current(): LisioWidgetVersionFactory {
    return LisioWidgetVersionFactory._current;
  }

  /**
   * Private attribute to store all builders
   * @source
   */
  private _builders: Map<LisioWidgetVersionNames, () => WidgetVersion> =
    new Map<LisioWidgetVersionNames, () => WidgetVersion>([
      [LisioWidgetVersionNames.COMPLETE, this.completeVersionBuilder],
      [LisioWidgetVersionNames.ESSENTIAL, this.essentialVersionBuilder],
      [LisioWidgetVersionNames.FIRST, this.firstVersionBuilder],
      [LisioWidgetVersionNames.WELCOME, this.welcomeVersionBuilder],
    ]);

  /**
   * Private method to initialize a complete version of the widget
   * @returns Returns a complete version of widget
   * @source
   */
  private completeVersionBuilder(): WidgetVersion {
    return new CompleteVersion();
  }

  /**
   * Private method to initialize an essential version of the widget
   * @returns Returns an essential version of widget
   * @source
   */
  private essentialVersionBuilder(): WidgetVersion {
    return new EssentialVersion();
  }

  /**
   * Private method to initialize a first version of the widget
   * @returns Returns a first version of widget
   * @source
   */
  private firstVersionBuilder(): WidgetVersion {
    return new FirstVersion();
  }

  /**
   * Private method to initialize a welcome version of the widget
   * @returns Returns a welcome version of widget
   * @source
   */
  private welcomeVersionBuilder(): WidgetVersion {
    return new WelcomeVersion();
  }
  /**
   * Public method to build a widget version
   * @param {LisioWidgetVersionNames} widgetVersionName - Name of widget version
   * @throws If version was not found.\
   * See {@link https://env-preprod-docs.lisio.fr/lisio-engine/enums/Src_Core.CoreErrorCodes.html#SINGLETON_NOT_UNIQUE | CoreErrorCodes.SINGLETON_NOT_UNIQUE}
   * @returns Returns choosed version
   */
  public buildLisioWidgetVersion(
    widgetVersionName: LisioWidgetVersionNames,
  ): WidgetVersion {
    const builder: (() => WidgetVersion) | undefined =
      this._builders.get(widgetVersionName);
    if (builder == undefined) {
      throw new Error(
        `Code : ${ErrorCodes.WIDGET_VERSION_NOT_FOUND}. Builder ${widgetVersionName} not found`,
      );
    } else {
      return builder();
    }
  }

  /**
   * Constructor of class {@link LisioWidgetVersionFactory | LisioWidgetVersionFactory}
   * @throws If singleton already initialize.\
   * See {@link https://env-preprod-docs.lisio.fr/lisio-engine/enums/Src_Core.CoreErrorCodes.html#SINGLETON_NOT_UNIQUE | CoreErrorCodes.SINGLETON_NOT_UNIQUE}
   * @source
   */
  constructor() {
    if (LisioWidgetVersionFactory._current == undefined) {
      LisioWidgetVersionFactory._current = this;
    } else {
      throw new Error(
        `Code : ${CoreErrorCodes.SINGLETON_NOT_UNIQUE}. Singleton already initialize`,
      );
    }
  }
}

export { LisioWidgetVersionFactory };
