import { LogUtility } from '../../../../utils/log';
import { ModifyContentAction } from '../actions/modify-content-action.abstract';
import { ActionHandlerInterceptorRegistry } from './action-handle-interceptor-registry';
/**
 * The strategies registry, contains static methods `register`, `get` and `getStrategyAndExecute`.
 */
export class ActionHandleStrategyRegistry {
  /**
   * Bind a specific strategy to a special action type of the rich text node.
   *
   * @param {string} actionType - The special action type or the action class name.
   * @param {string} targetClass - The rich text node class name.
   * @param {ActionHandleStrategy} strategy - The action handle strategy instance.
   */
  static register(actionType, targetClass, strategy) {
    if (!this.registry.has(targetClass)) {
      this.registry.set(targetClass, new Map());
    }
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    this.registry.get(targetClass).set(actionType, strategy);
  }
  /**
   * Unregister the strategy for the specific action type and target class.
   *
   * @param {string} actionType - The special action type or the action class name.
   * @param {string} targetClass - The rich text node class name.
   */
  static unregister(actionType, targetClass) {
    const strategyMap = this.registry.get(targetClass);
    if (strategyMap) {
      strategyMap.delete(actionType);
    }
  }
  /**
   * Get the special strategy that handle the action logic.
   *
   * @typedef T generic type
   * @typedef target generic type
   * @typedef R generic type
   * @param {string} actionType - The special action type or the action class name.
   * @param {string} targetClass - The rich text node class name.
   * @returns {Nullable<ActionHandleStrategy<T, target, R>>} - The action handle strategy instance if defined.
   */
  static get(actionType, targetClass) {
    const strategyMap = this.registry.get(targetClass);
    if (strategyMap) {
      return strategyMap.get(actionType);
    }
  }
  /**
   * Get the special strategy from the registry and run the strategy execute method.
   *
   * @typedef R generic type
   * @param {ModifyContentAction | AnnotationAction} action - The update node action instance.
   * @param {RTENode | RTEBlock | VegaRTEContent} RTEInstance - The rich text editor node.
   * @returns {R | undefined} The return value of the strategy method execute invoke result.
   */
  static executeTheStrategy(action, RTEInstance) {
    const interceptor = ActionHandlerInterceptorRegistry.get(action, RTEInstance);
    // eslint-disable-next-line jsdoc/require-jsdoc
    const executeStrategy = () => {
      const actionType = action instanceof ModifyContentAction ? action.type : action.constructor.name;
      const strategy = ActionHandleStrategyRegistry.get(actionType, RTEInstance.constructor.name);
      if (strategy) {
        action['executedFlag'] = true;
        return strategy.execute(action, RTEInstance);
      }
      else {
        LogUtility.warn(`Type ${actionType} action handle strategy is not registered in class ${RTEInstance.constructor.name}`);
      }
    };
    if (interceptor) {
      return interceptor.intercept(executeStrategy, action, RTEInstance);
    }
    else {
      return executeStrategy();
    }
  }
  /**
   * Check if the action type can be handled by strategy for the specific RTE instance.
   *
   * @param {string} actionType - The special action type or the action class name.
   * @param {RTENode | RTEBlock | VegaRTEContent} RTEInstance - The rich text editor node.
   * @returns {boolean} - Whether the action type can be handled by the strategy.
   */
  static canHandle(actionType, RTEInstance) {
    const strategy = ActionHandleStrategyRegistry.get(actionType, RTEInstance.constructor.name);
    return strategy ? true : false;
  }
}
ActionHandleStrategyRegistry.registry = new Map();
