<script lang="ts">
import { defineComponent, h } from 'vue';
import type { VNode } from 'vue';

import useConfig from '../composables/useConfig.ts';
import useSpelling from '../composables/useSpelling.ts';
import { escapeHtml } from '../src/helpers.ts';

import Icon from './Icon.vue';

import { NuxtLink } from '#components';

export default defineComponent({
    props: {
        text: { default: '', type: String },
        noicons: { type: Boolean },
        escape: { type: Boolean },
    },
    setup() {
        const { handleSpelling } = useSpelling();
        return {
            config: useConfig(),
            handleSpelling,
        };
    },
    render() {
        let text = this.text;
        if (this.escape) {
            text = escapeHtml(text);
        }
        if (!text) {
            return h('span', this.$attrs);
        }

        let isLink = false;
        let isIcon = false;
        let isEscape = false;
        let buffer = '';
        let linkBuffer = '';
        const children: VNode[] = [];
        const buildLink = (): VNode => {
            if (isIcon) {
                return h(Icon, { v: buffer });
            }

            const attrs = { ...this.$attrs, innerHTML: this.handleSpelling(buffer) };

            if (!isLink) {
                return h('span', attrs);
            }

            linkBuffer = linkBuffer.replace(/≡/g, '='); // meh workaround, i know…

            if (linkBuffer === '') {
                linkBuffer = `#${buffer}`;
            }

            if (linkBuffer.startsWith('https://') ||
                linkBuffer.startsWith('http://') ||
                linkBuffer.startsWith('mailto:') ||
                linkBuffer.endsWith('.pdf')
            ) {
                return h(
                    'a',
                    { ...attrs, href: linkBuffer, target: '_blank', rel: 'noopener' },
                );
            }

            if (linkBuffer.indexOf('#') === 0) {
                return h('a', { ...attrs, href: linkBuffer });
            }

            const to = encodeURI(linkBuffer) || `/${this.config.nouns.route}#${this.handleSpelling(buffer)}`;
            return h(NuxtLink, { ...attrs, to });
        };
        const addChild = (): void => {
            if (!buffer) {
                return;
            }
            children.push(buildLink());
            buffer = '';
            linkBuffer = '';
        };
        for (const c of text) {
            if (c === '{') {
                addChild();
                isLink = true;
                continue;
            } else if (c === '}') {
                addChild();
                isLink = false;
                continue;
            } else if (isLink && c === '=') {
                if (linkBuffer) {
                    linkBuffer += '=';
                }
                linkBuffer += buffer;
                buffer = '';
                continue;
            } else if (c === '[' && !this.noicons) {
                addChild();
                if (isEscape) {
                    isEscape = false;
                } else {
                    isIcon = true;
                    continue;
                }
            } else if (c === ']' && !this.noicons) {
                addChild();
                if (isIcon) {
                    isIcon = false;
                    continue;
                }
            } else if (c === '\\') {
                isEscape = true;
                continue;
            } else if (isEscape) {
                buffer += '\\';
                isEscape = false;
            }
            buffer += c;
        }
        addChild();

        return children;
    },
});
</script>
