import DOMPurify from 'dompurify';

/**
 * Canonical HTML sanitization utility for XSS prevention.
 *
 * Single source of truth for the client-side allowlist.
 * Must stay in sync with config/html-sanitization.php on the server side.
 * Uses DOMPurify with an explicit allowlist of safe tags and attributes.
 */

const ALLOWED_TAGS = [
  'p',
  'h1',
  'h2',
  'h3',
  'h4',
  'h5',
  'h6',
  'strong',
  'em',
  'ul',
  'ol',
  'li',
  'blockquote',
  'a',
  'br',
  'span',
  'code',
  'pre',
  'table',
  'thead',
  'tbody',
  'tr',
  'th',
  'td',
  'img',
  'div',
  'figure',
  'figcaption',
  'picture',
  'source',
];

const ALLOWED_ATTR = [
  'href',
  'target',
  'rel',
  'src',
  'alt',
  'width',
  'height',
  'loading',
  'class',
  'id',
  'srcset',
  'type',
];

/**
 * DOMPurify hook: force rel="noopener noreferrer" on every <a target="_blank">.
 * Prevents tab-napping: a new tab with window.opener set can navigate the
 * opener to a phishing page. This hook fires after DOMPurify's attribute
 * allowlisting so the added rel attribute is not stripped.
 */
// Guard prevents duplicate hook registration under Vitest module re-imports and HMR.
// DOMPurify deduplicates hooks by reference internally, but the flag is cheaper than relying on that.
const __sanitize__ = DOMPurify as typeof DOMPurify & { __hookRegistered__?: boolean };
if (!__sanitize__.__hookRegistered__) {
  __sanitize__.__hookRegistered__ = true;
  DOMPurify.addHook('afterSanitizeAttributes', (node: Element) => {
    if (node.tagName === 'A' && node.getAttribute('target') === '_blank') {
      node.setAttribute('rel', 'noopener noreferrer');
    }
  });
}

/**
 * Sanitizes HTML content to prevent XSS attacks.
 * Only allows a strict set of formatting tags and safe attributes.
 * Removes all script tags, event handlers, and dangerous attributes.
 * External links with target="_blank" automatically get rel="noopener noreferrer".
 *
 * @param dirty - The potentially unsafe HTML content
 * @returns Sanitized HTML string safe for rendering
 */
export function sanitizeHtml(dirty: string): string {
  return DOMPurify.sanitize(dirty, {
    ALLOWED_TAGS,
    ALLOWED_ATTR,
    KEEP_CONTENT: true, // Keep text content even if tag is removed
    ALLOW_DATA_ATTR: false, // Explicitly disallow data-* attributes
  });
}

export default sanitizeHtml;
