import { BaseHandler } from './base-handler';
import { RTETextBlock } from '../../../../dto/blocks/text-block';
import { LineBreakSingleBlockAction } from '../../../../dto/actions/line-break-single-block-action';
import { lineBreakMultipleBlocksAction } from '../../../../dto/actions/line-break-multiple-block-action';
/** User press shift + enter will tigger this callback */
export class InsertLineBreakHandler extends BaseHandler {
  /**
   * Create new line break node and add node to state value
   */
  handleEvent() {
    const range = this.selectionController.getCurrentRange();
    const selectedBlocks = this.selectionController.getSelectedBlocks();
    if (this.isRootContainer(range.startContainer)) {
      this.breakNewBlock();
    }
    if (selectedBlocks.length) {
      if (selectedBlocks.length < 2) {
        this.breakSingleBlock();
      }
      else {
        this.breakMultipleBlocks();
      }
    }
  }
  /**
   * Insert the \n in text element when root container is empty, should create text block and text node
   * <p>
   *  <span></span>
   *  <span></span>
   * </p>
   */
  breakNewBlock() {
    if (this.currentState &&
      this.currentState.children[0] &&
      this.currentState.children[0] instanceof RTETextBlock) {
      const lineBreakAction = new LineBreakSingleBlockAction(this.currentState.children[0].children[0], 0);
      this.currentState.children[0].apply(lineBreakAction);
      this.switchCaretPositionToSpecifiedNode(lineBreakAction.lineBreakNode);
    }
  }
  /**
   * If the selected node is a text node
   * <p>
   *  <span>text</span>
   * </p>
   * Insert a line break and the selected node will be split into three text nodes
   * <p>
   *  <span>te</span>
   *  <br>
   *  <span>xt</span>
   * </p>
   */
  breakSingleBlock() {
    const range = this.selectionController.getCurrentRange();
    const cursorNode = this.removeSelectionRange();
    const currentBlock = cursorNode.parent;
    if (currentBlock) {
      const lineBreakAction = new LineBreakSingleBlockAction(cursorNode, range.startOffset);
      currentBlock.apply(lineBreakAction);
      if (lineBreakAction.lineBreakNode) {
        this.switchCaretPositionToSpecifiedNode(lineBreakAction.lineBreakNode);
      }
    }
  }
  /**
   * Handles breaking blocks in an RTE editor based on the current selection and position.
   */
  breakMultipleBlocks() {
    const selectedBlocks = this.selectionController.getSelectedBlocks();
    const cursorNode = this.removeSelectionRange();
    const lineBreakAction = new lineBreakMultipleBlocksAction(selectedBlocks);
    cursorNode.parent.apply(lineBreakAction);
    this.switchCaretPositionToSpecifiedNode(lineBreakAction.lineBreakNode);
  }
  /**
   * Moves the caret to the next node element in a rich text editor.
   *
   * @param {RTENode} lineBreakNode - Represents a node element in a rich text editor.
   */
  switchCaretPositionToSpecifiedNode(lineBreakNode) {
    this.selectionController.enqueueSelectionRangeFutureState(this.getNextRTENode(lineBreakNode), 0);
  }
  /**
   * Returns the next sibling node of a given block element in a rich text editor.
   *
   * @param {RTENode} lineBreakNode - The `lineBreakNode` parameter is of type `RTENode`, which is used to represent the new line break element in a rich text editor.
   * @returns {RTENode} The next sibling node of the current line break element, or the current node if next node is not exists.
   */
  getNextRTENode(lineBreakNode) {
    const index = lineBreakNode.parent.children.indexOf(lineBreakNode);
    const nextNode = lineBreakNode.parent.children[index + 1];
    return nextNode || lineBreakNode;
  }
}
