import { AppendChildrenAction } from '../../../../dto/actions/append-child-nodes-action';
import { DeleteBlockContentAction } from '../../../../dto/actions/delete-block-content-action';
import { InsertChildrenBeforeAction } from '../../../../dto/actions/insert-children-before-block';
import { RemoveChildrenAction } from '../../../../dto/actions/remove-child-action';
import { ReplaceChildNodesAction } from '../../../../dto/actions/replace-child-nodes-action';
import { RTETextBlock } from '../../../../dto/blocks/text-block';
import { RTETextNode } from '../../../../dto/nodes/text-node';
import { BaseHandler } from './base-handler';
/** Handles the deletion of content within a VegaRTE editor. User press backspace or delete will trigger this method */
export class DeleteContentHandler extends BaseHandler {
  /**
   * Delete the selected node from the current state.
   */
  handleEvent() {
    const selectedBlocks = this.selectionController.getSelectedBlocks();
    if (selectedBlocks.length < 2) {
      this.deleteContentWithSingleBlock();
    }
    else {
      this.deleteContentWithMultipleNodes();
    }
  }
  /**
   * Handles the deletion of content within a single block in an RTE editor.
   */
  deleteContentWithSingleBlock() {
    const range = this.selectionController.getCurrentRange();
    const { startOffset, endOffset, startContainer, endContainer } = range;
    const selectedBlocks = this.selectionController.getSelectedBlocks();
    const selectedNodes = this.selectionController.getSelectedNodes();
    if (startOffset !== endOffset || startContainer !== endContainer) {
      this.deleteContentWithMultipleNodes();
    }
    else if (selectedBlocks[0]) {
      const deleteAction = new DeleteBlockContentAction(selectedNodes[0], startOffset);
      selectedBlocks[0].apply(deleteAction);
      if (deleteAction.previousNode) {
        const nextOffset = deleteAction.previousNode === selectedNodes[0]
          ? Math.max(0, startOffset - 1)
          : deleteAction.previousNode.getRangeEndOffset();
        this.selectionController.enqueueSelectionRangeFutureState(deleteAction.previousNode, nextOffset);
      }
      else if (deleteAction.nextNode) {
        this.selectionController.enqueueSelectionRangeFutureState(deleteAction.nextNode, 0);
      }
      else if (this.currentState.children.length === 0) {
        // Add a empty paragraph if delete all content to make sure the caret position
        this.insertDefaultParagraph();
      }
    }
  }
  /**
   * Deletes the content within multiple nodes selected by the user.
   */
  deleteContentWithMultipleNodes() {
    const selectedNodes = this.selectionController.getSelectedNodes();
    const cursorNode = this.removeSelectionRange(true);
    const lastSelectedNode = selectedNodes[selectedNodes.length - 1];
    if (selectedNodes.length > 1 &&
      lastSelectedNode instanceof RTETextNode &&
      lastSelectedNode.isEmpty()) {
      lastSelectedNode.parent.apply(new RemoveChildrenAction(lastSelectedNode));
    }
    this.convertFirstBlockToParagraph(cursorNode.parent);
  }
  /**
   * If the first block is not paragraph, convert the block to paragraph after delete all text
   *
   * @param {RTEBlock} block - The first block instance
   */
  convertFirstBlockToParagraph(block) {
    const firstBlock = this.currentState.children[0];
    if (firstBlock === block &&
      block instanceof RTETextBlock &&
      block.children.length === 1 &&
      block.children[0].isEmpty() &&
      block.type !== 'paragraph') {
      const paragraph = this.createEmptyParagraph();
      paragraph.apply(new ReplaceChildNodesAction(block.children));
      block.parent.apply(new InsertChildrenBeforeAction(block, paragraph));
      block.parent.apply(new RemoveChildrenAction(block));
    }
  }
  /**
   * Creates a new paragraph element with a text node and appends it to the current state.
   */
  insertDefaultParagraph() {
    const paragraph = this.createEmptyParagraph();
    this.currentState.apply(new AppendChildrenAction([paragraph]));
    this.selectionController.enqueueSelectionRangeFutureState(paragraph.children[0], 1);
  }
}
