/**
 * Base class for all sanitization strategies.
 *
 * Strategy defines:
 * - Allowed tags
 * - Allowed attributes per tag
 * - Text preservation behavior
 */
export class SanitizeStrategy {
  constructor() {
    this.preserveTextContent = true;
  }
  /**
   * @param {Node} node - Node to sanitize.
   * @param {Document} doc - document reference.
   * @returns {Nullable<Node>} - Sanitized node
   */
  execute(node, doc) {
    var _a;
    switch (node.nodeType) {
      case Node.TEXT_NODE:
        return this.preserveTextContent ? doc.createTextNode((_a = node.textContent) !== null && _a !== void 0 ? _a : '') : null;
      case Node.ELEMENT_NODE:
        return this.sanitizeElement(node, doc);
      default:
        return null;
    }
  }
  /**
   * @param {HTMLElement} element - HTMLElement to sanitize.
   * @param {Document} doc - document reference.
   * @returns {Nullable<Node>} - Sanitized node
   */
  sanitizeElement(element, doc) {
    var _a;
    const tagName = element.tagName;
    if (!this.allowedTags.has(tagName)) {
      const fragment = doc.createDocumentFragment();
      element.childNodes.forEach((child) => {
        const clean = this.execute(child, doc);
        if (clean)
          fragment.appendChild(clean);
      });
      return fragment;
    }
    const cleanElement = doc.createElement(tagName.toLowerCase());
    const allowedAttrs = (_a = this.allowedAttributes) === null || _a === void 0 ? void 0 : _a.get(tagName);
    if (allowedAttrs) {
      Array.from(element.attributes).forEach((attr) => {
        if (allowedAttrs.has(attr.name)) {
          cleanElement.setAttribute(attr.name, attr.value);
        }
      });
    }
    element.childNodes.forEach((child) => {
      const clean = this.execute(child, doc);
      if (clean)
        cleanElement.appendChild(clean);
    });
    return cleanElement;
  }
}
