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 { MapToComponentField, MapToComponentMethod, VegaSlimmer } from 'vega-slimmer/core';
import { InsertTextHandler } from './helper/input-event-handler/insert-text-handler';
import { InsertParagraphHandler } from './helper/input-event-handler/insert-paragraph-handler';
import { InsertLineBreakHandler } from './helper/input-event-handler/insert-line-break-handler';
import { DeleteContentHandler } from './helper/input-event-handler/delete-content-handler';
import { VegaRTEContent } from '../../dto/content-state';
import { InsertPasteHandler } from './helper/input-event-handler/insert-paste-handler';
import { generateUUID } from '../../../../utils/misc';
import { RTECodeBlock } from '../../dto/blocks/code-block';
/** Used to monitoring the user input actions by event listener */
export class UserInputController extends VegaSlimmer {
  constructor() {
    super(...arguments);
    this.insertTextHandler = new InsertTextHandler();
    this.insertParagraphHandler = new InsertParagraphHandler();
    this.insertLineBreakHandler = new InsertLineBreakHandler();
    this.deleteContentHandler = new DeleteContentHandler();
    this.insertPasteHandler = new InsertPasteHandler();
    /**
     * When a user performs an input action within the editable element, this function is triggered.
     *
     * @param {InputEvent} e the before input event object
     */
    this.handleUserInputAction = (e) => {
      const inputType = e.inputType;
      e.preventDefault();
      this.initValueIfEmpty();
      // The insertCompositionText type input event can not be prevented, so we process the current action by insertCompositionTextController.
      // If the focus node is a non-editable element, we do not process the input event.
      if (inputType === 'insertCompositionText' || this.isFocusNodeNonEditable()) {
        return;
      }
      this.insertCompositionTextController.removeObserver();
      let updateFlag = false;
      switch (inputType) {
        case 'insertParagraph':
          updateFlag = true;
          this.insertParagraphHandler.execute(this.value, this.selectionController, this.host, e);
          break;
        case 'insertText':
          updateFlag = true;
          this.insertTextHandler.execute(this.value, this.selectionController, this.host, e);
          break;
        case 'insertLineBreak':
          updateFlag = true;
          this.insertLineBreakHandler.execute(this.value, this.selectionController, this.host, e);
          break;
        case 'deleteContentBackward':
          updateFlag = true;
          this.deleteContentHandler.execute(this.value, this.selectionController, this.host, e);
          break;
        case 'insertFromPaste':
          updateFlag = true;
          this.insertPasteHandler.execute(this.value, this.selectionController, this.host, e);
          break;
      }
      if (updateFlag) {
        void this.valueController.flushChanges(this.value);
      }
    };
  }
  /**
   * Adds event listener to an editable HTML element to handle user input actions.
   */
  addActionListener() {
    const editableElement = this.getEditableElementRef();
    if (editableElement) {
      editableElement.addEventListener('beforeinput', this.handleUserInputAction);
      editableElement.addEventListener('drop', this.preventDropEvent);
    }
  }
  /**
   * Removes event listener for user input actions from an editable HTML div element.
   */
  removeActionListener() {
    const editableElement = this.getEditableElementRef();
    if (editableElement) {
      editableElement.removeEventListener('beforeinput', this.handleUserInputAction);
      editableElement.removeEventListener('drop', this.preventDropEvent);
    }
  }
  /**
   * The function `getEditableElementRef` returns a reference to the editable HTMLDivElement within a rich text editor.
   *
   * @returns {Nullable<HTMLDivElement>} A reference to an HTMLDivElement element that is editable.
   */
  getEditableElementRef() {
    if (!this.editableElementRef) {
      this.editableElementRef = this.vegaRichTextEditorRenderer.getRTEEditableElementRef();
    }
    return this.editableElementRef;
  }
  /**
   * Prevents the default behavior of a drag event.
   *
   * @param {DragEvent} e - drop event object
   */
  preventDropEvent(e) {
    e.preventDefault();
  }
  /**
   * Initializes the value to an empty array if it is currently empty.
   */
  initValueIfEmpty() {
    if (!this.value) {
      const id = generateUUID();
      const defaultParagraph = [
        { id, type: 'paragraph', nodes: [{ id: `${id}1`, type: 'text', text: '' }] },
      ];
      void this.valueController.flushChanges(VegaRTEContent.fromJSON(defaultParagraph));
    }
  }
  /**
   * The code block placeholder element is non-editable, so we need to check if the focus node is a code block placeholder element.
   *
   * @returns {boolean} - Returns true if the focus node is a code block placeholder element, otherwise false.
   */
  isFocusNodeNonEditable() {
    const { startContainer, endContainer } = this.selectionController.getCurrentRange();
    const selectedNodes = this.selectionController.getSelectedNodes();
    if (startContainer && startContainer === endContainer && selectedNodes.length === 0) {
      const focusElement = startContainer.nodeType === Node.ELEMENT_NODE
        ? startContainer
        : startContainer.parentElement;
      return (focusElement &&
        focusElement.classList.contains(RTECodeBlock.CODE_BLOCK_PLACEHOLDER_CLASS_NAME));
    }
    return false;
  }
}
__decorate([
  MapToComponentField()
], UserInputController.prototype, "host", void 0);
__decorate([
  MapToComponentField()
], UserInputController.prototype, "value", void 0);
__decorate([
  MapToComponentField()
], UserInputController.prototype, "valueController", void 0);
__decorate([
  MapToComponentField()
], UserInputController.prototype, "vegaRichTextEditorRenderer", void 0);
__decorate([
  MapToComponentField()
], UserInputController.prototype, "selectionController", void 0);
__decorate([
  MapToComponentField()
], UserInputController.prototype, "insertCompositionTextController", void 0);
__decorate([
  MapToComponentMethod('componentDidLoad')
], UserInputController.prototype, "addActionListener", null);
__decorate([
  MapToComponentMethod('disconnectedCallback')
], UserInputController.prototype, "removeActionListener", null);
