import { h } from '@stencil/core';
import { DomNodeSubjectObserverFactory } from '../../../../../helpers/change-manager/subject/dom-node-subject/dom-node-subject-observer-factory';
import { VegaChange, VegaRemove } from '../../../../../helpers/event-manager/event-id/vega-event-id';
import { RTENodeRenderer } from './node-renderer.abstract';
import { SwitchOutFromCodeBlockAction } from '../../actions/switch-out-from-code-block-action';
import { UpdateCodeBlockAction } from '../../actions/update-code-block-action';
import { SelectionChangeAction } from '../../actions/selection-change-action';
import { InternalAnnotationTypeEnum } from '../../annotations/annotation.abstract';
import { VegaInternalCodeBlockSelectionChange } from '../../../../../helpers/event-manager/event-id/vega-internal-event-id';
import { RemoveCodeBlockAction } from '../../actions/remove-code-block-action';
class RTECodeBlockNodeRenderer extends RTENodeRenderer {
  render(node, renderContext) {
    const { text: code, language } = node;
    return (h("vega-code-block", { key: node.id, value: { code, language }, readOnly: !renderContext.editable, "data-content": code, "data-language": language, ref: (ref) => {
        this.registerRef(ref, node);
        DomNodeSubjectObserverFactory.addUniqueObserverToNode(ref, VegaChange, (input) => this.handleCodeContentChange(input.detail, node));
        DomNodeSubjectObserverFactory.addUniqueObserverToNode(ref, VegaRemove, (input) => this.handleCodeBlockRemove(input, node));
        DomNodeSubjectObserverFactory.addUniqueObserverToNode(ref, VegaInternalCodeBlockSelectionChange, (input) => this.handleSelectionChange(input.detail, node));
      } }));
  }
  /**
   * Sync the code block DTO language and content when the component change event emit.
   *
   * @param {VegaCodeBlockValue} codeBlockValue - The code block value.
   * @param {RTECodeBlockNode} node - The DTO class instance.
   */
  handleCodeContentChange(codeBlockValue, node) {
    const { code, language } = codeBlockValue;
    if (this.shouldSwitchOutOfCodeBlock(node.text, code)) {
      const switchAction = new SwitchOutFromCodeBlockAction(code, language);
      node.parent.apply(switchAction);
    }
    else {
      node.apply(new UpdateCodeBlockAction(code, language));
    }
  }
  /**
   * Remove the code block from RTE value when the component remove event emit.
   *
   * @param {ChangeManagerEventLike<unknown>} input - The internal event payload object.
   * @param {RTECodeBlockNode} node - The DTO class instance.
   */
  handleCodeBlockRemove(input, node) {
    input.preventDefault();
    node.parent.apply(new RemoveCodeBlockAction());
  }
  /**
   * The cursor should jump out of code block if enter three line breaks at the end.
   *
   * @param {string} oldCode - The old code content.
   * @param {string} newCode - The new code content.
   * @returns {boolean} - Boolean value.
   */
  shouldSwitchOutOfCodeBlock(oldCode, newCode) {
    const newCodes = newCode.split('\n');
    if (newCode.length > oldCode.length &&
      newCodes.length > 4 &&
      newCodes.slice(newCodes.length - 4).join('') === ``) {
      return true;
    }
    return false;
  }
  /**
   * Apply the selection action to code node or remove from the annotation map.
   *
   * @param {boolean} isSelected - The code block is focus or not.
   * @param {RTECodeBlockNode} node - The DTO class instance.
   */
  handleSelectionChange(isSelected, node) {
    if (isSelected) {
      node.apply(new SelectionChangeAction(null));
    }
    else {
      node.annotationMap.delete(InternalAnnotationTypeEnum.SELECTION_RANGE);
    }
  }
}
export default new RTECodeBlockNodeRenderer();
