import { MergeTwoBlocksNodesAction } from '../../actions/merge-two-blocks-nodes-action';
import { RemoveChildrenAction } from '../../actions/remove-child-action';
import { UpdateTextAction } from '../../actions/update-text-action';
import { BlockDeleteNodeContentStrategy } from './block-delete-node-content-strategy';
/**
 * Block delete text or decorator node strategy.
 */
export class BlockDeleteTextOrDecoratorNodeStrategy extends BlockDeleteNodeContentStrategy {
  /**
   * @inheritDoc
   */
  handleAction(action, target) {
    const { startContainerNode } = action;
    if (!startContainerNode.isContentEditable()) {
      this.deleteDecoratorNodeContent(action, target);
    }
    else if (startContainerNode.isTextNode()) {
      this.deleteTextNodeContent(action, target);
    }
    const parent = target.parent;
    if (parent && target.isListItemBlock() && parent.children.length === 0) {
      parent.parent.apply(new RemoveChildrenAction(parent));
    }
  }
  /**
   * Handle the delete text logic when press delete key.
   *
   * @param {DeleteBlockContentAction} action - ModifyContentAction
   * @param {RTETextBlock} target - Current text block
   */
  deleteTextNodeContent(action, target) {
    const startContainerNode = action.startContainerNode;
    const startOffset = action.startOffset;
    if (startOffset !== 0 && !startContainerNode.isEmpty()) {
      const newText = startContainerNode.text.slice(0, startOffset - 1) +
        startContainerNode.text.slice(startOffset);
      startContainerNode.apply(new UpdateTextAction(newText));
      if (newText) {
        action.previousNode = startContainerNode;
        return;
      }
      else {
        const previousNode = this.getPreviousNode(startContainerNode);
        // Remove the last character will not delete paragraph, the paragraph will removed after press delete again
        if ((previousNode && previousNode.parent === target && previousNode['text'] === '\n') ||
          target.children.length === 1) {
          action.previousNode = startContainerNode;
          return;
        }
        else {
          target.apply(new RemoveChildrenAction(startContainerNode));
          action.previousNode = previousNode;
          return;
        }
      }
    }
    else {
      let previousNode = this.getPreviousNode(startContainerNode);
      let nextNode = null;
      const isCurrentNodeEmpty = startContainerNode.isEmpty();
      if (target.children.length && previousNode && previousNode.parent !== target) {
        if (isCurrentNodeEmpty) {
          target.apply(new RemoveChildrenAction(startContainerNode));
        }
        if (target.type === previousNode.parent.type) {
          previousNode.parent.apply(new MergeTwoBlocksNodesAction(target));
        }
      }
      else {
        if (this.isContentFirstNode(startContainerNode) && isCurrentNodeEmpty) {
          nextNode = this.getNextNode(startContainerNode);
        }
        /**
         * Remove line break
         *
         * @example caret at the first line
         * \n
         * test
         */
        if (isCurrentNodeEmpty) {
          target.apply(new RemoveChildrenAction(startContainerNode));
        }
        /**
         * Remove line break or non-editable node
         *
         * @example caret at the begin of second line
         * \n
         * test
         * @example caret at the end of non-editable node and start of the text node
         * <img/><span>test</span>
         */
        if (previousNode &&
          previousNode.isTextNode() &&
          (previousNode.isEmpty() ||
            (!previousNode.isContentEditable() && previousNode.parent === target))) {
          const shouldRemoveNode = previousNode;
          previousNode = this.getPreviousNode(previousNode);
          shouldRemoveNode.parent.apply(new RemoveChildrenAction(shouldRemoveNode));
          if (!previousNode && !isCurrentNodeEmpty) {
            nextNode = startContainerNode;
          }
        }
      }
      // Remove the paragraph block if the content is empty
      // TODO: Check whether need to remove below logic because already handled the same logic in remove node strategy
      if (target.children.length === 0) {
        target.parent.apply(new RemoveChildrenAction(target));
      }
      if (previousNode) {
        action.previousNode = previousNode;
      }
      else if (nextNode) {
        action.nextNode = nextNode;
      }
    }
  }
  /**
   * Delete decorator node content
   *
   * @param {DeleteBlockContentAction} action - The delete block content action
   * @param {RTEBlock} target - The target block
   */
  deleteDecoratorNodeContent(action, target) {
    const startContainerNode = action.startContainerNode, startOffset = action.startOffset;
    let previousNode = this.getPreviousNode(startContainerNode);
    let nextNode = null;
    if (startOffset !== 0) {
      const parentBlock = target;
      if (this.isContentFirstNode(startContainerNode)) {
        nextNode = this.getNextNode(startContainerNode);
      }
      if (parentBlock.children.length === 1) {
        parentBlock.parent.apply(new RemoveChildrenAction(parentBlock));
      }
      else {
        parentBlock.apply(new RemoveChildrenAction(startContainerNode));
      }
    }
    else {
      const shouldRemoveNode = previousNode;
      if (shouldRemoveNode && !shouldRemoveNode.isContentEditable()) {
        previousNode = this.getPreviousNode(shouldRemoveNode);
        shouldRemoveNode.parent.apply(new RemoveChildrenAction(shouldRemoveNode));
        if (!previousNode) {
          action.nextNode = startContainerNode;
        }
      }
    }
    if (previousNode) {
      action.previousNode = previousNode;
    }
    else if (nextNode) {
      action.nextNode = nextNode;
    }
  }
}
