import { Window as HappyDom } from "happy-dom";
import config from "../../../../config/index.js";
import { intersperse } from "../../../../prelude/array.js";
import { resolveMentionFromCache } from "../../../../remote/resolve-user.js";
export class MfmHelpers {
    static async toHtml(nodes, mentionedRemoteUsers = [], objectHost, inline = false, quoteUri = null) {
        if (nodes == null) {
            return null;
        }
        const { window } = new HappyDom();
        const doc = window.document;
        async function appendChildren(children, targetElement) {
            if (children) {
                for (const child of (await Promise.all(children.map(async (x)=>await handlers[x.type](x)))))targetElement.appendChild(child);
            }
        }
        const handlers = {
            async bold (node) {
                const el = doc.createElement("span");
                el.textContent = '**';
                await appendChildren(node.children, el);
                el.textContent += '**';
                return el;
            },
            async small (node) {
                const el = doc.createElement("small");
                await appendChildren(node.children, el);
                return el;
            },
            async strike (node) {
                const el = doc.createElement("span");
                el.textContent = '~~';
                await appendChildren(node.children, el);
                el.textContent += '~~';
                return el;
            },
            async italic (node) {
                const el = doc.createElement("span");
                el.textContent = '*';
                await appendChildren(node.children, el);
                el.textContent += '*';
                return el;
            },
            async fn (node) {
                const el = doc.createElement("span");
                el.textContent = '*';
                await appendChildren(node.children, el);
                el.textContent += '*';
                return el;
            },
            blockCode (node) {
                const pre = doc.createElement("pre");
                const inner = doc.createElement("code");
                const nodes = node.props.code.split(/\r\n|\r|\n/).map((x)=>doc.createTextNode(x));
                for (const x of intersperse("br", nodes)){
                    inner.appendChild(x === "br" ? doc.createElement("br") : x);
                }
                pre.appendChild(inner);
                return pre;
            },
            async center (node) {
                const el = doc.createElement("div");
                await appendChildren(node.children, el);
                return el;
            },
            emojiCode (node) {
                return doc.createTextNode(`\u200B:${node.props.name}:\u200B`);
            },
            unicodeEmoji (node) {
                return doc.createTextNode(node.props.emoji);
            },
            hashtag (node) {
                const a = doc.createElement("a");
                a.setAttribute('href', `${config.url}/tags/${node.props.hashtag}`);
                a.textContent = `#${node.props.hashtag}`;
                a.setAttribute("rel", "tag");
                a.setAttribute("class", "hashtag");
                return a;
            },
            inlineCode (node) {
                const el = doc.createElement("code");
                el.textContent = node.props.code;
                return el;
            },
            mathInline (node) {
                const el = doc.createElement("code");
                el.textContent = node.props.formula;
                return el;
            },
            mathBlock (node) {
                const el = doc.createElement("code");
                el.textContent = node.props.formula;
                return el;
            },
            async link (node) {
                const a = doc.createElement("a");
                a.setAttribute("rel", "nofollow noopener noreferrer");
                a.setAttribute("target", "_blank");
                a.setAttribute('href', node.props.url);
                await appendChildren(node.children, a);
                return a;
            },
            async mention (node) {
                const { username, host, acct } = node.props;
                const resolved = await resolveMentionFromCache(username, host, objectHost, mentionedRemoteUsers);
                const el = doc.createElement("span");
                if (resolved === null) {
                    el.textContent = acct;
                } else {
                    el.setAttribute("class", "h-card");
                    el.setAttribute("translate", "no");
                    const a = doc.createElement("a");
                    a.setAttribute('href', resolved.href);
                    a.className = "u-url mention";
                    const span = doc.createElement("span");
                    span.textContent = resolved.username;
                    a.textContent = '@';
                    a.appendChild(span);
                    el.appendChild(a);
                }
                return el;
            },
            async quote (node) {
                const el = doc.createElement("blockquote");
                await appendChildren(node.children, el);
                return el;
            },
            text (node) {
                const el = doc.createElement("span");
                const nodes = node.props.text.split(/\r\n|\r|\n/).map((x)=>doc.createTextNode(x));
                for (const x of intersperse("br", nodes)){
                    el.appendChild(x === "br" ? doc.createElement("br") : x);
                }
                return el;
            },
            url (node) {
                const a = doc.createElement("a");
                a.setAttribute("rel", "nofollow noopener noreferrer");
                a.setAttribute("target", "_blank");
                a.setAttribute('href', node.props.url);
                a.textContent = node.props.url.replace(/^https?:\/\//, '');
                return a;
            },
            search (node) {
                const a = doc.createElement("a");
                a.setAttribute('href', `${config.searchEngine}${node.props.query}`);
                a.textContent = node.props.content;
                return a;
            },
            async plain (node) {
                const el = doc.createElement("span");
                await appendChildren(node.children, el);
                return el;
            }
        };
        await appendChildren(nodes, doc.body);
        if (quoteUri !== null) {
            const a = doc.createElement("a");
            a.setAttribute('href', quoteUri);
            a.textContent = quoteUri.replace(/^https?:\/\//, '');
            const quote = doc.createElement("span");
            quote.setAttribute("class", "quote-inline");
            quote.appendChild(doc.createElement("br"));
            quote.appendChild(doc.createElement("br"));
            quote.innerHTML += 'RE: ';
            quote.appendChild(a);
            doc.body.appendChild(quote);
        }
        return inline ? doc.body.innerHTML : `<p>${doc.body.innerHTML}</p>`;
    }
}
