import { RemoveWhitespaceBetweenTagsProcessor } from './processors/remove-whitespace-between-tags-processor';
import { RemoveWhitespaceAfterOpeningTagProcessor } from './processors/remove-whitespace-after-opening-tag-processor';
import { RemoveWhitespaceBeforeClosingTagProcessor } from './processors/remove-whitespace-before-closing-tag-processor';
/**
 * Main HTML content cleaner that orchestrates multiple cleaning processors.
 *
 * This class implements a chain of responsibility pattern where each processor
 * handles a specific aspect of HTML cleaning. The processors are applied in sequence
 * and the entire chain is repeated until no more changes occur.
 *
 * Processors (in order):
 * 1. RemoveWhitespaceBetweenTagsProcessor - Removes whitespace between non-matching tags
 * 2. RemoveWhitespaceAfterOpeningTagProcessor - Removes \n and \t after opening tags
 * 3. RemoveWhitespaceBeforeClosingTagProcessor - Removes \n and \t before closing tags
 */
export class HTMLContentCleaner {
  constructor() {
    this.processors = [
      new RemoveWhitespaceBetweenTagsProcessor(),
      new RemoveWhitespaceAfterOpeningTagProcessor(),
      new RemoveWhitespaceBeforeClosingTagProcessor(),
    ];
  }
  /**
   * Cleans HTML by applying all processors in the chain repeatedly until no changes occur.
   *
   * The cleaning process:
   * 1. Applies each processor in sequence
   * 2. Compares the result with the input
   * 3. If changes were made, repeats the process
   * 4. Returns the final cleaned HTML
   *
   * Examples of transformations:
   * - `<p>\n\t <span>test</span>\n\t </p>` → `<p><span>test</span></p>`
   * - `<p>\n\tHello</p>` → `<p>Hello</p>`
   * - `<p>Hello\n\t</p>` → `<p>Hello</p>`
   * - `<span> </span>` → `<span> </span>` (preserved - matching tags)
   * - `<p>Hello  World</p>` → `<p>Hello  World</p>` (preserved - regular spaces)
   *
   * @param {string} html - The HTML string to clean.
   * @returns {string} The cleaned HTML string.
   */
  clean(html) {
    if (!html || html.trim().length === 0) {
      return html;
    }
    let result = html;
    let previousResult;
    // Keep processing until no more changes occur
    do {
      previousResult = result;
      // Apply each processor in the chain
      for (const processor of this.processors) {
        result = processor.process(result);
      }
    } while (result !== previousResult);
    return result;
  }
}
