import sanitizeHtml from 'sanitize-html';

/**
 * Rich-text / HTML editors often encode `>` as `&gt;`, turning `{{> partial}}` into `{{&gt; partial}}`
 * which Handlebars cannot parse. Decode entities only inside handlebars segments.
 */
export function decodeHandlebarsEntities(html: string): string {
    const hb = /\{\{\{[\s\S]*?\}\}\}|\{\{[\s\S]*?\}\}/g;
    return html.replace(hb, (block) =>
        block
            .replace(/&amp;lt;/gi, '<')
            .replace(/&amp;gt;/gi, '>')
            .replace(/&amp;quot;/gi, '"')
            .replace(/&amp;#39;/g, "'")
            .replace(/&lt;/g, '<')
            .replace(/&gt;/g, '>')
            .replace(/&quot;/g, '"')
            .replace(/&#39;/g, "'")
            .replace(/&amp;/g, '&')
    );
}

/** Preserve `{{...}}` / `{{{...}}}` so `{{> partial}}` is not mangled by the HTML sanitizer. */
function maskHandlebars(html: string): { masked: string; tokens: string[] } {
    const tokens: string[] = [];
    const hb = /\{\{\{[\s\S]*?\}\}\}|\{\{[\s\S]*?\}\}/g;
    let i = 0;
    const masked = html.replace(hb, (m) => {
        tokens.push(m);
        return `__HANDLEBARS_TOKEN_${i++}__`;
    });
    return { masked, tokens };
}

function unmaskHandlebars(html: string, tokens: string[]): string {
    let out = html;
    tokens.forEach((t, idx) => {
        out = out.split(`__HANDLEBARS_TOKEN_${idx}__`).join(t);
    });
    return out;
}

const emailBodyOptions: sanitizeHtml.IOptions = {
    allowedTags: [
        ...sanitizeHtml.defaults.allowedTags,
        'img',
        'h1',
        'h2',
        'h3',
        'h4',
        'table',
        'thead',
        'tbody',
        'tr',
        'td',
        'th',
        'caption'
    ],
    allowedAttributes: {
        ...sanitizeHtml.defaults.allowedAttributes,
        '*': ['style', 'class', 'align'],
        a: ['href', 'name', 'target', 'style', 'class'],
        img: ['src', 'alt', 'width', 'height', 'style', 'class'],
        td: ['colspan', 'rowspan', 'style', 'class'],
        th: ['colspan', 'rowspan', 'style', 'class'],
        table: ['border', 'cellpadding', 'cellspacing', 'style', 'class', 'width']
    },
    allowedSchemes: ['http', 'https', 'mailto'],
    allowedSchemesByTag: {
        img: ['http', 'https']
    },
    allowProtocolRelative: false
};

/** Strip dangerous markup from stored template bodies while keeping typical email HTML. */
export function sanitizeEmailTemplateBody(html: string): string {
    const decoded = decodeHandlebarsEntities(html || '');
    const { masked, tokens } = maskHandlebars(decoded);
    const cleaned = sanitizeHtml(masked, emailBodyOptions);
    return unmaskHandlebars(cleaned, tokens);
}

/** Plain-text-style subject: no HTML tags. */
export function sanitizeEmailTemplateSubject(subject: string): string {
    const stripped = sanitizeHtml(subject || '', {
        allowedTags: [],
        allowedAttributes: {}
    });
    return stripped.trim().slice(0, 998);
}
