import { h } from '@stencil/core';
import { RTEBlockRenderer } from './block-renderer.abstract';
import { RTECodeBlock } from '../../blocks/code-block';
import RTECodeBlockNodeRenderer from '../nodes/code-block-node-renderer';
import { ZERO_WIDTH_SPACE } from '../../../constants/constant';
import { tryGetDocument } from '../../../../../utils/try-get-document';
/**
 * The code block renderer.
 */
class RTECodeBlockRenderer extends RTEBlockRenderer {
  constructor() {
    super(...arguments);
    /**
     * Prevent the click event bubble, avoid the rich text content trigger focus event.
     *
     * @param {MouseEvent} e - The event object.
     */
    this.preventParentDoFocus = (e) => {
      e.stopPropagation();
      if (e.type === 'keydown') {
        this.dispatchMockKeydownEvent(e);
      }
    };
  }
  /**
   * Render the code block.
   *
   * @param {RTECodeBlock} block - The code block.
   * @param {RTERenderContext} renderContext - The render context.
   * @returns {HTMLElement} - The code block container element and code node elements.
   */
  render(block, renderContext) {
    const { id, children: nodes } = block;
    return (
    // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
    h("pre", { key: id, class: "code-block-container", ref: (node) => this.registerRef(node, block), onKeyDown: this.preventParentDoFocus, onClick: this.preventParentDoFocus, "data-language": nodes[0].language },
      this.renderPlaceholderElement('TOP'),
      RTECodeBlockNodeRenderer.render(nodes[0], renderContext),
      this.renderPlaceholderElement('BOTTOM')));
  }
  /**
   * The current element used to define the upper and lower bounds of a code block and to ensure that they are reflected in the range object when the code block is selected.
   *
   * @param {'TOP' | 'BOTTOM'} position - The element position.
   * @returns {HTMLElement} - The empty span element.
   */
  renderPlaceholderElement(position) {
    const marginTop = position === 'BOTTOM' ? '-1px' : '0px';
    const marginBottom = position === 'BOTTOM' ? '0px' : '-1px';
    return (h("span", { class: RTECodeBlock.CODE_BLOCK_PLACEHOLDER_CLASS_NAME, style: {
        display: 'block',
        height: '1px',
        overflow: 'hidden',
        zIndex: '1',
        marginTop,
        marginBottom,
      } }, ZERO_WIDTH_SPACE));
  }
  /**
   * If redo and undo in code block, here need a mock keydown event to make the helper class `KeyboardManager` could monitor the current keydown event.
   *
   * @param {KeyboardEvent} e - The keyboard event object.
   */
  dispatchMockKeydownEvent(e) {
    const safeDocument = tryGetDocument();
    if (safeDocument) {
      const { type, code, metaKey, ctrlKey, shiftKey } = e;
      const event = new Event(type, { bubbles: false, cancelable: true });
      event['code'] = code;
      event['metaKey'] = metaKey;
      event['ctrlKey'] = ctrlKey;
      event['shiftKey'] = shiftKey;
      safeDocument.dispatchEvent(event);
    }
  }
}
export default new RTECodeBlockRenderer();
