/**
 * HTML Sanitization Utility using DOMPurify
 *
 * Provides XSS protection for dynamic content by sanitizing HTML before insertion.
 * Use these functions instead of direct innerHTML assignments to prevent XSS attacks.
 *
 * @module sanitizer
 */

import DOMPurify from 'dompurify';

/**
 * Configuration for different sanitization contexts
 */
const SANITIZE_CONFIG = {
    // Strict: For user-generated content, only allow safe formatting
    strict: {
        ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br', 'span', 'div'],
        ALLOWED_ATTR: ['href', 'title', 'class'],
        ALLOW_DATA_ATTR: false,
        ALLOW_UNKNOWN_PROTOCOLS: false,
        SAFE_FOR_TEMPLATES: true
    },

    // UI: For UI components, allow common elements
    ui: {
        ALLOWED_TAGS: ['div', 'span', 'i', 'strong', 'em', 'b', 'p', 'br', 'small', 'code', 'pre'],
        ALLOWED_ATTR: ['class', 'id', 'title', 'aria-label', 'role', 'data-*'],
        ALLOW_DATA_ATTR: true,
        ALLOW_UNKNOWN_PROTOCOLS: false,
        SAFE_FOR_TEMPLATES: true
    },

    // Rich: For research content, allow more formatting
    rich: {
        ALLOWED_TAGS: [
            'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
            'p', 'br', 'hr', 'div', 'span',
            'strong', 'em', 'b', 'i', 'u', 's', 'strike',
            'ul', 'ol', 'li',
            'a', 'code', 'pre',
            'blockquote', 'q', 'cite',
            'table', 'thead', 'tbody', 'tr', 'th', 'td',
            'img'
        ],
        ALLOWED_ATTR: [
            'href', 'title', 'class', 'id',
            'alt', 'src',  // For images
            'cite',        // For citations
            'target', 'rel'  // For links
        ],
        ALLOW_DATA_ATTR: false,
        ALLOW_UNKNOWN_PROTOCOLS: false,
        SAFE_FOR_TEMPLATES: true,
        // Enforce safe link targets
        ADD_ATTR: ['target'],
        FORBID_ATTR: ['onerror', 'onload']
    }
};

/**
 * Sanitize HTML string using DOMPurify with given configuration
 *
 * @param {string} dirty - Potentially unsafe HTML string
 * @param {string} level - Sanitization level: 'strict', 'ui', or 'rich'
 * @returns {string} Sanitized HTML string safe for insertion
 *
 * @example
 * const clean = sanitizeHTML('<script>alert("xss")</script><p>Safe content</p>', 'strict');
 * // Returns: '<p>Safe content</p>'
 */
export function sanitizeHTML(dirty, level = 'ui') {
    if (!dirty || typeof dirty !== 'string') {
        return '';
    }

    const config = SANITIZE_CONFIG[level] || SANITIZE_CONFIG.ui;
    return DOMPurify.sanitize(dirty, config);
}

/**
 * Safely set innerHTML of an element with sanitized HTML
 *
 * @param {HTMLElement} element - Target element
 * @param {string} htmlString - HTML string to sanitize and insert
 * @param {string} level - Sanitization level: 'strict', 'ui', or 'rich'
 *
 * @example
 * safeSetHTML(element, '<b>Bold text</b><script>alert("xss")</script>', 'ui');
 * // Sets element.innerHTML to: '<b>Bold text</b>'
 */
export function safeSetHTML(element, htmlString, level = 'ui') {
    if (!element || !(element instanceof HTMLElement)) {
        console.error('safeSetHTML: Invalid element provided');
        return;
    }

    element.innerHTML = sanitizeHTML(htmlString, level);
}

/**
 * Escape HTML special characters for plain text display
 * Use this when you want to display user input as-is without any HTML parsing
 *
 * @param {string} text - Text to escape
 * @returns {string} Escaped text safe for HTML context
 *
 * @example
 * const safe = escapeHTML('<script>alert("xss")</script>');
 * // Returns: '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'
 */
export function escapeHTML(text) {
    if (!text || typeof text !== 'string') {
        return '';
    }

    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

/**
 * Safely set text content of an element (no HTML parsing)
 * Use this for plain text that should never be interpreted as HTML
 *
 * @param {HTMLElement} element - Target element
 * @param {string} text - Plain text to set
 *
 * @example
 * safeSetText(element, '<b>This will be displayed as literal text</b>');
 */
export function safeSetText(element, text) {
    if (!element || !(element instanceof HTMLElement)) {
        console.error('safeSetText: Invalid element provided');
        return;
    }

    element.textContent = text || '';
}

/**
 * Create a safe DOM element from HTML string
 * Returns a DocumentFragment containing sanitized elements
 *
 * @param {string} htmlString - HTML string to parse
 * @param {string} level - Sanitization level
 * @returns {DocumentFragment} Document fragment with sanitized content
 *
 * @example
 * const fragment = createSafeElement('<div>Safe content</div>');
 * parentElement.appendChild(fragment);
 */
export function createSafeElement(htmlString, level = 'ui') {
    const template = document.createElement('template');
    template.innerHTML = sanitizeHTML(htmlString, level);
    return template.content;
}

/**
 * Sanitize URL to prevent javascript: and data: URI attacks
 *
 * @param {string} url - URL to sanitize
 * @returns {string} Safe URL or empty string if unsafe
 *
 * @example
 * const safe = sanitizeURL('javascript:alert("xss")');
 * // Returns: ''
 *
 * const safe2 = sanitizeURL('https://example.com');
 * // Returns: 'https://example.com'
 */
export function sanitizeURL(url) {
    if (!url || typeof url !== 'string') {
        return '';
    }

    const trimmed = url.trim().toLowerCase();

    // Block dangerous protocols
    const dangerousProtocols = ['javascript:', 'data:', 'vbscript:', 'file:'];
    for (const protocol of dangerousProtocols) {
        if (trimmed.startsWith(protocol)) {
            console.warn(`Blocked dangerous URL protocol: ${protocol}`);
            return '';
        }
    }

    // Allow safe protocols
    const safeProtocols = ['http:', 'https:', 'mailto:', 'tel:', 'ftp:', '//', '/'];
    const isSafe = safeProtocols.some(proto => trimmed.startsWith(proto));

    if (!isSafe && trimmed.includes(':')) {
        console.warn('Blocked URL with unknown protocol:', url);
        return '';
    }

    return url;
}

/**
 * Configure DOMPurify hooks for additional security
 */
function configureDOMPurify() {
    // Hook to enforce safe link targets
    DOMPurify.addHook('afterSanitizeAttributes', (node) => {
        // Set all links to open in new tab with noopener noreferrer
        if (node.tagName === 'A') {
            node.setAttribute('target', '_blank');
            node.setAttribute('rel', 'noopener noreferrer');
        }

        // Remove any remaining inline event handlers
        for (const attr of node.attributes) {
            if (attr.name.startsWith('on')) {
                node.removeAttribute(attr.name);
            }
        }
    });
}

// Initialize DOMPurify configuration on module load
configureDOMPurify();

export default {
    sanitizeHTML,
    safeSetHTML,
    escapeHTML,
    safeSetText,
    createSafeElement,
    sanitizeURL
};
