import Vue, {Component, CreateElement, RenderContext, VNode} from 'vue';
import { CoreBBCodeParser, analyzeUrlTag } from '../bbcode/core';
//tslint:disable-next-line:match-default-export-name
import BaseEditor from '../bbcode/Editor.vue';
import {BBCodeTextTag} from '../bbcode/parser';
import ChannelView from './ChannelTagView.vue';
import {characterImage} from './common';
import core from './core';
import {Character} from './interfaces';
import {default as UrlView} from '../bbcode/UrlTagView.vue';
import UserView from './UserView.vue';

export const BBCodeView: Component = {
    functional: true,
    render(createElement: CreateElement, context: RenderContext): VNode {
        /*tslint:disable:no-unsafe-any*///because we're not actually supposed to do any of this
        context.data.hook = {
            insert(node: VNode): void {
                node.elm!.appendChild(core.bbCodeParser.parseEverything(
                    context.props.text !== undefined ? context.props.text : context.props.unsafeText));
                if(context.props.afterInsert !== undefined) context.props.afterInsert(node.elm);
            },
            destroy(node: VNode): void {
                const element = (<BBCodeElement>(<Element>node.elm).firstChild);
                if(element.cleanup !== undefined) element.cleanup();
            }
        };
        const vnode = createElement('span', context.data);
        vnode.key = context.props.text;
        return vnode;
        //tslint:enable
    }
};

export class Editor extends BaseEditor {
    parser = core.bbCodeParser;
}

export type BBCodeElement = HTMLElement & {cleanup?(): void};

export default class BBCodeParser extends CoreBBCodeParser {
    cleanup: Vue[] = [];

    constructor() {
        super();
        this.addTag(new BBCodeTextTag('user', (parser, parent, param, content) => {
            if(param.length > 0)
                parser.warning('Unexpected parameter on user tag.');
            const uregex = /^[a-zA-Z0-9_\-\s]+$/;
            if(!uregex.test(content)) return;
            const el = parser.createElement('span');
            parent.appendChild(el);
            const view = new UserView({el, propsData: {character: core.characters.get(content)}});
            this.cleanup.push(view);
            return el;
        }));
        this.addTag(new BBCodeTextTag('icon', (parser, parent, param, content) => {
            if(param.length > 0)
                parser.warning('Unexpected parameter on icon tag.');
            const uregex = /^[a-zA-Z0-9_\-\s]+$/;
            if(!uregex.test(content))
                return;
            const img = parser.createElement('img');
            img.src = characterImage(content);
            img.style.cursor = 'pointer';
            img.className = 'character-avatar icon';
            img.title = img.alt = content;
            (<HTMLImageElement & {character: Character}>img).character = core.characters.get(content);
            parent.appendChild(img);
            return img;
        }));
        this.addTag(new BBCodeTextTag('eicon', (parser, parent, param, content) => {
            if(param.length > 0)
                parser.warning('Unexpected parameter on eicon tag.');
            const uregex = /^[a-zA-Z0-9_\-\s]+$/;
            if(!uregex.test(content))
                return;
            const extension = core.connection.isOpen && !core.state.settings.animatedEicons ? 'png' : 'gif';
            const img = parser.createElement('img');
            img.src = `https://static.f-list.net/images/eicon/${content.toLowerCase()}.${extension}`;
            img.title = img.alt = content;
            img.className = 'character-avatar icon';
            parent.appendChild(img);
            return img;
        }));
        this.addTag(new BBCodeTextTag('session', (parser, parent, param, content) => {
            const root = parser.createElement('span');
            const el = parser.createElement('span');
            parent.appendChild(root);
            root.appendChild(el);
            const view = new ChannelView({el, propsData: {id: content, text: param}});
            this.cleanup.push(view);
            return root;
        }));
        this.addTag(new BBCodeTextTag('channel', (parser, parent, _, content) => {
            const root = parser.createElement('span');
            const el = parser.createElement('span');
            parent.appendChild(root);
            root.appendChild(el);
            const view = new ChannelView({el, propsData: {id: content, text: content}});
            this.cleanup.push(view);
            return root;
        }));

        this.addTag(new BBCodeTextTag(
            'url',
            (parser, parent, _, content) => {
                const tagData = analyzeUrlTag(parser, _, content);

                const root = parser.createElement('span');
                // const el = parser.createElement('span');
                parent.appendChild(root);
                // root.appendChild(el);

                if (!tagData.success) {
                    root.textContent = tagData.textContent;
                    return;
                }

                const view = new UrlView({el: root, propsData: {url: tagData.url, text: tagData.textContent, domain: tagData.domain}});
                this.cleanup.push(view);

                return root;
            }));
    }

    parseEverything(input: string): BBCodeElement {
        const elm = <BBCodeElement>super.parseEverything(input);
        if(this.cleanup.length > 0)
            elm.cleanup = ((cleanup: Vue[]) => () => {
                for(const component of cleanup) component.$destroy();
            })(this.cleanup);
        this.cleanup = [];
        return elm;
    }
}