import { BoldAnnotationHandler } from './bold-annotaion-handler';
import { CustomAttributeAnnotationHandler } from './custom-attribute-annotation-handler';
import { CustomClassAnnotationHandler } from './custom-class-annotation-handler';
import { CustomStyleAnnotationHandler } from './custom-style-annotation-handler';
import { IndentAnnotationHandler } from './indent-annotation-handler';
import { TextAlignAnnotationHandler } from './text-align-annotation-handler';
import { CodeAnnotationHandler } from './code-annotation-handler';
import { ColorAnnotationHandler } from './color-annotation-handler';
import { ItalicAnnotationHandler } from './italic-annotation-handler';
import { LinkAnnotationHandler } from './link-annotation-handler';
import { StrikeThroughAnnotationHandler } from './strike-through-annotation-handler';
import { UnderlineAnnotationHandler } from './underline-annotation-handler';
import { TextStyleAnnotation } from '../../../../../dto/annotations/text-style-annotation';
import { TextStyleAnnotationHandler } from './text-style-annotation-handler';
import { ImageSizeAnnotationHandler } from './image-size-annotation-handler';
import { ImageAltAnnotationHandler } from './image-alt-annotation-handler';
import { InlineHtmlAnnotationHandler } from './inline-html-annotation-handler';
import { RTEFilterStylesStrategyRegistry } from '../../../../../dto/filter-styles-strategies/filter-styles-strategy-registry';
import { Predicate } from '../predicate';
/** Html element to annotations generator */
class HtmlElementToAnnotationGenerator {
  constructor() {
    this.handlers = [
      new TextAlignAnnotationHandler(),
      new IndentAnnotationHandler(),
      new BoldAnnotationHandler(),
      new ItalicAnnotationHandler(),
      new UnderlineAnnotationHandler(),
      new StrikeThroughAnnotationHandler(),
      new ColorAnnotationHandler(),
      new LinkAnnotationHandler(),
      new CodeAnnotationHandler(),
      new ImageSizeAnnotationHandler(),
      new ImageAltAnnotationHandler(),
      new CustomAttributeAnnotationHandler(),
      new CustomClassAnnotationHandler(),
      new CustomStyleAnnotationHandler(),
      new TextStyleAnnotationHandler(),
      new InlineHtmlAnnotationHandler(),
    ];
  }
  /**
   * Register a custom annotation handler.
   * Custom handlers are added to the beginning of the handlers array,
   * giving them higher priority than default handlers.
   *
   * @param {AnnotationGeneratorStrategyAbstract} handler - The annotation handler to register.
   */
  registerHandler(handler) {
    this.handlers.unshift(handler);
  }
  /**
   * The function generates annotations for a given target DTO and HTML element based on a set of
   * strategies.
   *
   * @typedef T class name of target DTO
   * @typedef V generated annotations type
   * @param {T} targetDto - Which DTO is the generated annotations to set.
   * @param {HTMLElement} element - Current html element.
   * @param {HtmlElementToAnnotationGenerateOptions} [options] - Options
   * @returns {V} Generated annotations.
   */
  generate(targetDto, element, options = { autoMatchFormat: true }) {
    if (options && options.filterInlineStyles) {
      RTEFilterStylesStrategyRegistry.executeTheStrategyRefillAction(targetDto.dtoName, element);
    }
    // Guard against <a> wrapping block content (e.g. <a><video></a>), which is processed as an
    // html-block (targetDto !== RTETextNode) — link-only mode should not apply in that case.
    const isLinkElement = Predicate.isLinkElement(element) && targetDto.dtoName === 'RTETextNode';
    const annotations = this.handlers
      .filter((handler) => !options.autoMatchFormat && isLinkElement ? handler instanceof LinkAnnotationHandler : true)
      .filter((handler) => element.nodeType !== Node.TEXT_NODE &&
      handler.canHandle(targetDto, {
        skipCustomAnnotations: options.skipCustomAnnotations || isLinkElement,
        autoMatchFormat: options.autoMatchFormat,
      }))
      .reduce((annotations, handler) => {
      const result = handler.handle(element, options.parentAnnotations);
      return Object.assign(Object.assign({}, annotations), result);
    }, {});
    this.removeTextStyleDefaultsFromCustomStyle(annotations);
    const strategies = RTEFilterStylesStrategyRegistry.getStrategies(targetDto.dtoName);
    for (const strategy of strategies) {
      if (options.autoMatchFormat || strategy.alwaysFilter) {
        strategy.filterAnnotations(annotations);
      }
    }
    return annotations;
  }
  /**
   * Remove default text-style properties from customStyle.
   * This prevents repeated styling when switching between source edit and normal mode.
   *
   * Note: This method mutates the customStyle object inside `annotations` in place and returns the same reference.
   *
   * @param {V} annotations - The generated annotations.
   * @returns {V} The same annotations reference with customStyle cleaned up.
   */
  removeTextStyleDefaultsFromCustomStyle(annotations) {
    const textStyle = 'textStyle' in annotations ? annotations.textStyle : undefined;
    const customStyle = annotations.customStyle;
    if (!textStyle || !customStyle) {
      return annotations;
    }
    const defaultStyles = TextStyleAnnotation.getDefaultStyles(textStyle);
    if (!defaultStyles) {
      return annotations;
    }
    for (const key of Object.keys(defaultStyles)) {
      if (customStyle[key] === defaultStyles[key]) {
        delete customStyle[key];
      }
    }
    if (Object.keys(customStyle).length === 0) {
      delete annotations.customStyle;
    }
    return annotations;
  }
}
export default new HtmlElementToAnnotationGenerator();
