
import { toDisposable, DisposableStore } from '../common/lifecycle.js';
import { Schemas } from '../common/network.js';
import { createElement } from './dom.js';
import dompurify from 'dompurify';

const basicMarkupHtmlTags = ( Object.freeze([
    'a',
    'abbr',
    'b',
    'bdo',
    'blockquote',
    'br',
    'caption',
    'cite',
    'code',
    'col',
    'colgroup',
    'dd',
    'del',
    'details',
    'dfn',
    'div',
    'dl',
    'dt',
    'em',
    'figcaption',
    'figure',
    'h1',
    'h2',
    'h3',
    'h4',
    'h5',
    'h6',
    'hr',
    'i',
    'img',
    'ins',
    'kbd',
    'label',
    'li',
    'mark',
    'ol',
    'p',
    'pre',
    'q',
    'rp',
    'rt',
    'ruby',
    'samp',
    'small',
    'small',
    'source',
    'span',
    'strike',
    'strong',
    'sub',
    'summary',
    'sup',
    'table',
    'tbody',
    'td',
    'tfoot',
    'th',
    'thead',
    'time',
    'tr',
    'tt',
    'u',
    'ul',
    'var',
    'video',
    'wbr',
]));
const defaultAllowedAttrs = ( Object.freeze([
    'href',
    'target',
    'src',
    'alt',
    'title',
    'for',
    'name',
    'role',
    'tabindex',
    'x-dispatch',
    'required',
    'checked',
    'placeholder',
    'type',
    'start',
    'width',
    'height',
    'align',
]));
function addDompurifyHook(hook, cb) {
    dompurify.addHook(hook, cb);
    return toDisposable(() => dompurify.removeHook(hook));
}
function hookDomPurifyHrefAndSrcSanitizer(allowedLinkProtocols, allowedMediaProtocols) {
    const anchor = createElement('a');
    function validateLink(value, allowedProtocols) {
        if (allowedProtocols === '*') {
            return true;
        }
        anchor.href = value;
        return allowedProtocols.includes(anchor.protocol.replace(/:$/, ''));
    }
    dompurify.addHook('afterSanitizeAttributes', (node) => {
        for (const attr of ['href', 'src']) {
            if (node.hasAttribute(attr)) {
                const attrValue = node.getAttribute(attr);
                if (attr === 'href') {
                    if (!attrValue.startsWith('#') && !validateLink(attrValue, allowedLinkProtocols)) {
                        node.removeAttribute(attr);
                    }
                }
                else {
                    if (!validateLink(attrValue, allowedMediaProtocols)) {
                        node.removeAttribute(attr);
                    }
                }
            }
        }
    });
    return toDisposable(() => dompurify.removeHook('afterSanitizeAttributes'));
}
const defaultDomPurifyConfig = ( Object.freeze({
    ALLOWED_TAGS: [...basicMarkupHtmlTags],
    ALLOWED_ATTR: [...defaultAllowedAttrs],
    RETURN_DOM: false,
    RETURN_DOM_FRAGMENT: false,
    RETURN_TRUSTED_TYPE: true,
    ALLOW_UNKNOWN_PROTOCOLS: true,
}));
function sanitizeHtml(untrusted, config) {
    const store = ( new DisposableStore());
    try {
        const resolvedConfig = { ...defaultDomPurifyConfig };
        if (config?.allowedTags) {
            if (config.allowedTags.override) {
                resolvedConfig.ALLOWED_TAGS = [...config.allowedTags.override];
            }
            if (config.allowedTags.augment) {
                resolvedConfig.ALLOWED_TAGS = [...(resolvedConfig.ALLOWED_TAGS ?? []), ...config.allowedTags.augment];
            }
        }
        if (config?.allowedAttributes) {
            if (config.allowedAttributes.override) {
                resolvedConfig.ALLOWED_ATTR = [...config.allowedAttributes.override];
            }
            if (config.allowedAttributes.augment) {
                resolvedConfig.ALLOWED_ATTR = [...(resolvedConfig.ALLOWED_ATTR ?? []), ...config.allowedAttributes.augment];
            }
        }
        store.add(hookDomPurifyHrefAndSrcSanitizer(config?.allowedLinkProtocols?.override ?? [Schemas.http, Schemas.https], config?.allowedMediaProtocols?.override ?? [Schemas.http, Schemas.https]));
        if (config?._do_not_use_hooks?.uponSanitizeElement) {
            store.add(addDompurifyHook('uponSanitizeElement', config?._do_not_use_hooks.uponSanitizeElement));
        }
        if (config?._do_not_use_hooks?.uponSanitizeAttribute) {
            store.add(addDompurifyHook('uponSanitizeAttribute', config._do_not_use_hooks.uponSanitizeAttribute));
        }
        return dompurify.sanitize(untrusted, {
            ...resolvedConfig,
            RETURN_TRUSTED_TYPE: true
        });
    }
    finally {
        store.dispose();
    }
}
function safeSetInnerHtml(node, untrusted, config) {
    node.innerHTML = sanitizeHtml(untrusted, config);
}

export { basicMarkupHtmlTags, defaultAllowedAttrs, safeSetInnerHtml, sanitizeHtml };
