import { RTEListBlock } from './blocks/list-block';
import { ModifyContentActionType } from './actions/modify-content-action.abstract';
import { AppendChildrenAction } from './actions/append-child-nodes-action';
import { generateUUID } from '../../../utils/misc';
import { RTEListItemBlock } from './blocks/list-item-block';
import { SyncUpSelectionAction } from './actions/sync-up-selection-action';
import { ActionHandleStrategyRegistry } from './action-handle-strategies/action-handle-strategy-registry';
import { BlockTransformToCodeBlockStrategy } from './action-handle-strategies/modify-content-strategies/block-transform-to-code-block-strategy';
import ElementToDtoStrategyProcessor from '../slimmers/controllers/helper/element-to-dto-strategy/element-to-dto-strategy-processor';
import { isNonNullable } from '../../../types/type-guard';
import RTEDTOClassManager from '../../../helpers/rte-manager/dto-class-manager';
import { UpdateCursorPositionStrategy } from './action-handle-strategies/modify-content-strategies/update-cursor-position-strategy';
import { RemoveChildrenStrategy } from './action-handle-strategies/modify-content-strategies/remove-children-strategy';
import { AppendChildrenStrategy } from './action-handle-strategies/modify-content-strategies/append-children-strategy';
import { InsertChildrenBeforeStrategy } from './action-handle-strategies/modify-content-strategies/insert-children-before-strategy';
import { InsertChildrenAfterStrategy } from './action-handle-strategies/modify-content-strategies/insert-children-after-strategy';
import stateEntityRenderingRegistry from '../slimmers/controllers/state-entity-rendering-registry';
import changeManager from '../../../helpers/change-manager/change-manager';
import domNodeSubjectFactory from '../../../helpers/change-manager/subject/dom-node-subject/dom-node-subject-factory';
import { VegaInternalRichTextEditorFlushChanges } from '../../../helpers/event-manager/event-id/vega-internal-event-id';
import './setup';
import { StylePreservator } from '../../../helpers/csp/styles-preservator';
import { LogUtility } from '../../../utils/log';
import { HTMLContentCleaner } from '../slimmers/controllers/html-cleaner';
import { RTEFilterStylesStrategyRegistry } from './filter-styles-strategies/filter-styles-strategy-registry';
/**
 * Class representing the content state of the rich text editor.
 */
export class VegaRTEContent {
  constructor(blocks) {
    this.dtoName = VegaRTEContent.dtoName;
    blocks.forEach((block) => {
      block.parent = this;
    });
    this.children = blocks;
  }
  /**
   * Converts a JSON array of blocks to a class array of RTEContentBlock.
   *
   * @param {VegaRTEContentBlock[]} value The JSON array of blocks to convert.
   * @param {VegaRTETransformOptions} options - Optional transformation options.
   * @returns {VegaRTEContent} The converted array of RTEContentBlock.
   */
  static fromJSON(value, options = { autoMatchFormat: true }) {
    const blocks = value.map((block) => {
      const BlockClass = RTEDTOClassManager.getRTEBlockClass(block.type);
      if (BlockClass) {
        return BlockClass.from(block, options);
      }
      else {
        throw new Error(`[Vega] Unknown block type: ${block.type}`);
      }
    });
    return new VegaRTEContent(blocks);
  }
  /**
   * Create an empty content state
   *
   * @param {VegaRTETransformOptions} options - Optional transformation options.
   * @returns {VegaRTEContent} An empty content state
   */
  static createEmptyContent(options = { autoMatchFormat: true }) {
    return VegaRTEContent.fromJSON([
      {
        id: generateUUID(),
        type: 'paragraph',
        annotations: {
          internalWrapper: !options.autoMatchFormat,
        },
        nodes: [
          {
            id: generateUUID(),
            annotations: { plainText: !options.autoMatchFormat },
            type: 'text',
            text: '',
          },
        ],
      },
    ], options);
  }
  /**
   * Converts HTML content to a VegaRTEContent instance.
   *
   * @param {string} html - The HTML string to convert.
   * @param {VegaRTETransformOptions} options - Optional transformation options.
   * @returns {VegaRTEContent} The converted content state.
   */
  static fromHtml(html, options = { autoMatchFormat: true, skipCustomAnnotations: false }) {
    const cleaner = new HTMLContentCleaner();
    const formattedHtml = cleaner.clean(html);
    const context = StylePreservator.preserve(formattedHtml);
    const safeHtml = context.getProcessedHtml();
    const body = new DOMParser().parseFromString(safeHtml, 'text/html').body;
    const htmlElements = Array.from(body.childNodes);
    context.restore(htmlElements);
    const blocks = ElementToDtoStrategyProcessor.process(htmlElements, options)
      .filter(isNonNullable)
      .map((output) => output.toDto(options))
      .filter(isNonNullable);
    return new VegaRTEContent(blocks);
  }
  /**
   * Generates the content style file for the rich text editor based on the registered filter styles strategies.
   *
   * @param {VegaRTEGenerateStyleOptions} options - Options for generating the content style file.
   * @returns {string} The html template style text.
   */
  static generateContentStyles(options) {
    return RTEFilterStylesStrategyRegistry.generateAllStylesContent(options === null || options === void 0 ? void 0 : options.enableFontImports);
  }
  /**
   * Clones the content state.
   *
   * @param {boolean} deep - If true, performs a deep clone of the content state.
   * @returns {VegaRTEContent} The cloned content state.
   */
  clone(deep = false) {
    return deep
      ? new VegaRTEContent(this.children.map((block) => block.clone(this)))
      : new VegaRTEContent([...this.children]);
  }
  /**
   * Converts the content state to a JSON array of blocks.
   *
   * @returns {VegaRTEContentBlock[]} The JSON array of blocks.
   */
  toJSON() {
    return this.children.map((block) => block.toJSON());
  }
  /**
   * Converts the content state to HTML.
   *
   * @param {VegaRTETransformOptions} [options] - The conversion options.
   * @returns {string} The HTML representation of the content state.
   */
  toHtml(options) {
    if (options &&
      (isNonNullable(options.autoMatchFormat) || isNonNullable(options.skipCustomAnnotations))) {
      LogUtility.warn(`The 'options' parameter's properties 'autoMatchFormat' and 'skipCustomAnnotations' in toHtml method are deprecated and will be removed in the future.`);
    }
    if (this.isEmpty()) {
      return '';
    }
    return this.children
      .map((block) => block.toHtml({ filterInlineStyles: options === null || options === void 0 ? void 0 : options.filterInlineStyles }))
      .join('');
  }
  /**
   * Checks if the content state is empty.
   *
   * @returns {boolean} True if the content state is empty, false otherwise.
   */
  isEmpty() {
    if (this.children.length === 0) {
      return true;
    }
    if (this.children.length === 1) {
      const block = this.children[0];
      return !block.isNotEmpty();
    }
    return false;
  }
  /**
   * Internal method to add the block item, remove the block item
   *
   * @param {ModifyContentAction} action - Modify content action
   */
  apply(action) {
    ActionHandleStrategyRegistry.executeTheStrategy(action, this);
    // Check if the action has been executed and is flushable
    if (action['executedFlag'] && action.isFlushable) {
      const host = stateEntityRenderingRegistry.getDOMByEntity(this);
      if (host) {
        changeManager.notify(domNodeSubjectFactory.getSubject(host, VegaInternalRichTextEditorFlushChanges), {});
      }
    }
  }
  /**
   * Get the last node in the content.
   *
   * @returns {Nullable<RTENode>} The last node in the content or null if there are no nodes.
   */
  getLastNode() {
    if (this.children.length === 0) {
      return null;
    }
    const lastBlock = this.children[this.children.length - 1];
    return lastBlock.getLastNode();
  }
  /**
   * Convert text to list.
   *
   * @param {RTETextBlock} block - block
   * @returns {RTEListItemBlock} list item block dto.
   */
  toListItem(block) {
    block.children.map((node) => node.apply(new SyncUpSelectionAction()));
    const listItemBlock = new RTEListItemBlock(generateUUID());
    listItemBlock.apply(new AppendChildrenAction(block['children']));
    listItemBlock['annotationMap'] = block['annotationMap'];
    return listItemBlock;
  }
  /**
   * create list.
   *
   * @param {ListType} type - type
   * @returns {RTEListBlock} list block dto.
   */
  createList(type) {
    return new RTEListBlock(generateUUID(), type);
  }
  /**
   * Finds a node by its ID in the content.
   *
   * @param {string} id - The ID of the node to find.
   * @returns {Nullable<RTENode>} The found node or null if not found.
   */
  findNodeById(id) {
    return this.findNodeInBlocksById(id, this.children);
  }
  /**
   * Recursively searches for a node by its ID in the given blocks.
   *
   * @param {string} id - The ID of the node to find.
   * @param {RTEContentBlock[]} blocks - The blocks to search within.
   * @returns {Nullable<RTENode>} The found node or null if not found.
   */
  findNodeInBlocksById(id, blocks) {
    for (const block of blocks) {
      if ('children' in block) {
        for (const node of block.children) {
          if (node.id === id) {
            return node;
          }
        }
      }
      if (block instanceof RTEListItemBlock && block.nestList) {
        for (const cBlock of block.nestList) {
          const foundNode = this.findNodeInBlocksById(id, cBlock.children);
          if (foundNode) {
            return foundNode;
          }
        }
      }
      if (block instanceof RTEListBlock && block.children) {
        const foundNode = this.findNodeInBlocksById(id, block.children);
        if (foundNode) {
          return foundNode;
        }
      }
    }
    return null;
  }
}
(() => {
  ActionHandleStrategyRegistry.register(ModifyContentActionType.DELETE_CHILDREN, VegaRTEContent.name, new RemoveChildrenStrategy());
  ActionHandleStrategyRegistry.register(ModifyContentActionType.APPEND_CHILDREN, VegaRTEContent.name, new AppendChildrenStrategy());
  ActionHandleStrategyRegistry.register(ModifyContentActionType.INSERT_CHILDREN_BEFORE, VegaRTEContent.name, new InsertChildrenBeforeStrategy());
  ActionHandleStrategyRegistry.register(ModifyContentActionType.INSERT_CHILDREN_AFTER, VegaRTEContent.name, new InsertChildrenAfterStrategy());
  ActionHandleStrategyRegistry.register(ModifyContentActionType.TRANSFORM_TO_CODE_BLOCK, VegaRTEContent.name, new BlockTransformToCodeBlockStrategy());
  ActionHandleStrategyRegistry.register(ModifyContentActionType.UPDATE_CURSOR_POSITION, VegaRTEContent.name, new UpdateCursorPositionStrategy());
})();
/** Minimize-safe type discriminator for VegaRTEContent. */
VegaRTEContent.dtoName = 'VegaRTEContent';
