import { RTEFilterStylesStrategy } from '../filter-styles-strategy.abstract';
import { Predicate } from '../predicate';
/**
 * The TitleHeadingNodeFilterStylesStrategy is responsible for filtering styles from text nodes that are children of title and heading blocks.
 * In title and heading blocks, the text nodes will have a default bold style.
 */
export class TitleHeadingNodeFilterStylesStrategy extends RTEFilterStylesStrategy {
  constructor() {
    super(...arguments);
    this.stylesToBeFiltered = TitleHeadingNodeFilterStylesStrategy.BOLD_STYLES;
    this.elementTagName = 'span';
    this.parentBlockTypes = [
      'heading-1',
      'heading-2',
      'heading-3',
      'heading-4',
      'heading-5',
      'heading-6',
      'title',
    ];
    this.parentElementSelectors = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', '.v-rte-title'];
    this.toBeCheckedSelector = this.parentElementSelectors.join(',');
  }
  /**
   * Don't run filterAnnotations method, because already handle it in text format filter strategy.
   *
   * @inheritDoc
   */
  filterAnnotations(annotations) {
    return annotations;
  }
  /**
   * Determines whether the dto instance is text node and its parent block is a heading or title.
   *
   * @param {RTEBlock | RTENode} blockOrNodeInstance - The block or node instance to check.
   * @returns {boolean} - True if the instance is a text node and its parent block is a heading or title, false otherwise.
   */
  canFilter(blockOrNodeInstance) {
    return (Predicate.isTextNode(blockOrNodeInstance.dtoName) &&
      this.parentBlockIsHeadingOrTitle(blockOrNodeInstance));
  }
  /**
   * Check if the node is a text node and its parent block is a heading or title.
   *
   * @param {string} blockOrNodeClassName - The class name of the block or node instance to check.
   * @param {HTMLElement} element - The HTML element of the node instance.
   * @returns {boolean} True if the node is a text node and its parent block is a heading or title, false otherwise.
   */
  canRefill(blockOrNodeClassName, element) {
    return (Predicate.isTextNode(blockOrNodeClassName) &&
      element.nodeName === 'SPAN' &&
      this.isHeadingOrTitleChild(element));
  }
  /**
   * @inheritDoc
   */
  toCssText() {
    const selectors = this.parentElementSelectors.map((key) => `.${TitleHeadingNodeFilterStylesStrategy.RTE_CONTENT_CONTAINER_CLASS_NAME} ${key}`);
    return `${selectors.join(',')} { ${this.convertStylesMapToCssText()} }`;
  }
  /**
   * Checks if the parent block of the given node instance is a heading or title.
   *
   * @param {RTENode | RTEBlock} blockOrNodeInstance - The node instance to check.
   * @returns {boolean} True if the parent block is a heading or title, false otherwise.
   */
  parentBlockIsHeadingOrTitle(blockOrNodeInstance) {
    const parentBlock = blockOrNodeInstance.parent;
    return parentBlock ? this.parentBlockTypes.includes(parentBlock.type) : false;
  }
  /**
   * Check if the element is a descendant of a heading or title element.
   * Traverses upward through the DOM, stopping at the block element or body element
   * to avoid unbounded traversal to the document root.
   *
   * <h1><span>bold text</span></h1>
   * <h1><a><span>link text</span></a></h1>
   * <h1><a><b><span>nested text</span></b></a></h1>
   *
   * @param {HTMLElement} element - The element to check.
   * @returns {boolean} True if the element is a descendant of a heading or title, false otherwise.
   */
  isHeadingOrTitleChild(element) {
    let current = element.parentElement;
    while (current) {
      if (current.matches(this.toBeCheckedSelector))
        return true;
      // Stop traversing upward if we reach a block element to prevent unbounded traversal to the document root. The title children will always be wrapped in a div, so we can safely stop at div as well.
      if (TitleHeadingNodeFilterStylesStrategy.NON_HEADING_TITLE_ELEMENT_TAGS.includes(current.tagName))
        return false;
      current = current.parentElement;
    }
    return false;
  }
}
TitleHeadingNodeFilterStylesStrategy.BOLD_STYLES = {
  fontWeight: '700',
};
TitleHeadingNodeFilterStylesStrategy.NON_HEADING_TITLE_ELEMENT_TAGS = [
  'TD',
  'TH',
  'TR',
  'TABLE',
  'THEAD',
  'TBODY',
  'DIV',
  'BODY',
];
