var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { createDynamicSlimmer, InjectVegaSlimmer, VegaSlimmer } from 'vega-slimmer/core';
import ChangeManager from '../../change-manager/change-manager';
import domNodeSubjectFactory from '../../change-manager/subject/dom-node-subject/dom-node-subject-factory';
import { DomNodeSubjectObserverFactory } from '../../change-manager/subject/dom-node-subject/dom-node-subject-observer-factory';
import InternalVegaEventManager from '../internal-vega-event-manager';
import { VegaEventEmitHandlerSlimmer } from './event-emit-handlers/vega-event-emit-handler';
import { NativeEventEmitHandlerSlimmer } from './event-emit-handlers/native-event-emit-handler';
import { JqueryDelegatedEventEmitHandlerSlimmer } from './event-emit-handlers/jquery-delegated-event-emit-handler';
import { tryGetDocument } from '../../../utils/try-get-document';
/** The EventEmitSlimmerBase class is a TypeScript class that extends VegaSlimmer and provides methods for emitting events with or without notifications. */
export class EventEmitSlimmerBase extends VegaSlimmer {
  /**
   * The constructor function takes an object with an eventName property and assigns it to the eventName property of the class.
   *
   * @param {{ eventName: string }} eventName  - The constructor function takes in an object with a property called "eventName" of type
   * string. The value of "eventName" is then assigned to the instance variable "this.eventName".
   */
  constructor({ eventID }) {
    super();
    this.vegaEventEmitHandler = new VegaEventEmitHandlerSlimmer();
    this.nativeEventEmitHandler = new NativeEventEmitHandlerSlimmer();
    this.jqueryDelegatedEventEmitHandler = new JqueryDelegatedEventEmitHandlerSlimmer();
    /**
     * emit the vega component event
     *
     * @param {unknown} [detail] the event detail
     * @param {Event} [e] the event object
     * @returns {Nullable<Event>} The emitted event.
     */
    this.emit = (detail, e) => {
      let isChangeManagerPrevented = false;
      ChangeManager.notify(domNodeSubjectFactory.getSubject(this.host, this.eventID), {
        host: this.host,
        detail: detail,
        eventName: this.eventName,
        // eslint-disable-next-line jsdoc/require-jsdoc
        preventDefault: () => {
          isChangeManagerPrevented = true;
        },
      });
      const eventSemantics = InternalVegaEventManager.getSemantics(this.host);
      let event;
      for (const handler of this.eventHandlers) {
        if (handler.canHandle(eventSemantics)) {
          event = handler.handle(detail, e);
          break;
        }
      }
      if (event && isChangeManagerPrevented) {
        event.preventDefault();
      }
      return event;
    };
    /**
     * used to clean up and remove any observers that were added to the host element during the lifecycle of the class
     */
    this.removeObserverFromHost = () => {
      // add promise to fix the testPolyfill#replaceChildren
      void Promise.resolve(true).then(() => {
        if (this.isNodeRemovedFromDocument(this.host)) {
          DomNodeSubjectObserverFactory.removeUniqueObserverFromNode(this.host, this.eventID);
        }
      });
    };
    this.eventID = eventID;
    this.eventName = eventID.getVegaName();
    this.initialEventHandlers();
  }
  /**
   * The function checks if a given HTML element has been removed from the document.
   *
   * @param {Nullable<HTMLElement>} node - The `node` parameter is of type `Nullable<HTMLElement>`, which means it can either be
   * an `HTMLElement` or `null`. It represents the element that needs to be checked if it has been removed from the document.
   * @returns {boolean} a boolean value.
   */
  isNodeRemovedFromDocument(node) {
    var _a;
    // elementAppender#show will call the HTMLElement#append method, and the append method will call the component disconnectedCallback, but the component not remove from the page.
    // see the issue in test case vega-popover.e2e.ts->should behavior normal while click app header button and time picker nested in popover
    if (node && !((_a = tryGetDocument()) === null || _a === void 0 ? void 0 : _a.body.contains(node)) && !node.parentNode) {
      return true;
    }
    return false;
  }
  /**
   * The function initializes event handlers for different types of events.
   */
  initialEventHandlers() {
    this.jqueryDelegatedEventEmitHandler.setEventID(this.eventID);
    this.eventHandlers = [
      this.vegaEventEmitHandler,
      this.jqueryDelegatedEventEmitHandler,
      this.nativeEventEmitHandler,
    ];
  }
}
__decorate([
  InjectVegaSlimmer()
], EventEmitSlimmerBase.prototype, "vegaEventEmitHandler", void 0);
__decorate([
  InjectVegaSlimmer()
], EventEmitSlimmerBase.prototype, "nativeEventEmitHandler", void 0);
__decorate([
  InjectVegaSlimmer()
], EventEmitSlimmerBase.prototype, "jqueryDelegatedEventEmitHandler", void 0);
/**
 * The function `createEventEmitSlimmer` creates a slimmer version of an event emitter class by mapping specific properties and events.
 *
 * @param {ClassPrototype<unknown>} mapFromClass - The class prototype from which the event emitter will be created.
 * @param {VegaEventID} eventID - The eventName parameter is a VegaEventID that represents the name of the event.
 * @param {string} [nativeEventPropertyName] - usually the native event name is eventID#nativeName, set a property name when the native name is used by other method or property
 * @returns {EventEmitSlimmerBase} an instance of the `EventEmitSlimmerBase` class.
 */
export function createEventEmitSlimmer(mapFromClass, eventID, nativeEventPropertyName) {
  const eventName = eventID.getVegaName();
  const nativeEventName = nativeEventPropertyName || eventID.getNativeName();
  return createDynamicSlimmer(mapFromClass, EventEmitSlimmerBase, [
    { mapFrom: 'host', mapTo: 'host' },
    { mapFrom: eventName, mapTo: 'vegaEvent' },
    //optional for now
    { mapFrom: nativeEventName, mapTo: 'nativeEvent', isOptional: true },
  ], [{ mapFrom: 'disconnectedCallback', mapTo: 'removeObserverFromHost' }], [
    {
      eventID,
    },
  ]);
}
