#include msgbox.jsx
#include parsing.js
#include utility.js
#include ext/eeprom.js

let MszForumEditorAllowClose = false;

const MszForumEditor = function(form) {
    if(!(form instanceof Element))
        throw 'form must be an instance of element';

    const buttonsElem = form.querySelector('.js-forum-posting-buttons'),
        textElem = form.querySelector('.js-forum-posting-text'),
        parserElem = form.querySelector('.js-forum-posting-parser'),
        previewElem = form.querySelector('.js-forum-posting-preview'),
        modeElem = form.querySelector('.js-forum-posting-mode'),
        markupActs = form.querySelector('.js-forum-posting-actions');

    let lastPostText = '',
        lastPostParser;

    MszEEPROM.init()
        .catch(() => console.error('Failed to initialise EEPROM'))
        .then(() => {
            const eepromClient = new EEPROM(peepApp, peepPath);
            const eepromHistory = <div class="eeprom-widget-history-items"/>;

            const eepromHandleFileUpload = async file => {
                const uploadElemNameValue = <div class="eeprom-widget-file-name-value" title={file.name}>{file.name}</div>;
                const uploadElemName = <a class="eeprom-widget-file-name" target="_blank">{uploadElemNameValue}</a>;
                const uploadElemProgressText = <div class="eeprom-widget-file-progress">Please wait...</div>;
                const uploadElemProgressBarValue = <div class="eeprom-widget-file-bar-fill" style={{ width: '0%' }}/>;
                const uploadElem = <div class="eeprom-widget-file">
                    <div class="eeprom-widget-file-info">
                        {uploadElemName}
                        {uploadElemProgressText}
                    </div>
                    <div class="eeprom-widget-file-bar">
                        {uploadElemProgressBarValue}
                    </div>
                </div>;

                if(eepromHistory.children.length > 0)
                    $ib(eepromHistory.firstChild, uploadElem);
                else
                    eepromHistory.appendChild(uploadElem);

                const explodeUploadElem = () => $r(uploadElem);
                const uploadTask = eepromClient.create(file);

                uploadTask.onProgress(prog => {
                    const progress = `}%`;
                    uploadElemProgressBarValue.style.width = `${Math.ceil(prog.progress * 100)}%`;
                    uploadElemProgressText.textContent = `${prog.progress.toLocaleString(undefined, { style: 'percent' })} (${prog.total - prog.loaded} bytes remaining)`;
                });

                try {
                    const fileInfo = await uploadTask.start();

                    uploadElem.classList.add('eeprom-widget-file-done');
                    uploadElemName.href = fileInfo.url;
                    uploadElemProgressText.textContent = '';

                    const insertTheLinkIntoTheBoxEx2 = () => {
                        const parserMode = parseInt(parserElem.value);
                        let insertText = location.protocol + fileInfo.url;

                        if(parserMode == 1) { // bbcode
                            if(fileInfo.isImage())
                                insertText = `[img]${fileInfo.url}[/img]`;
                            else if(fileInfo.isAudio())
                                insertText = `[audio]${fileInfo.url}[/audio]`;
                            else if(fileInfo.isVideo())
                                insertText = `[video]${fileInfo.url}[/video]`;
                        } else if(parserMode == 2) { // markdown
                            if(fileInfo.isMedia())
                                insertText = `![](${fileInfo.url})`;
                        }

                        $insertTags(textElem, insertText, '');
                        textElem.value = textElem.value.trim();
                    };

                    uploadElemProgressText.appendChild(<a href="javascript:void(0)" onclick={() => insertTheLinkIntoTheBoxEx2()}>Insert</a>);
                    uploadElemProgressText.appendChild($t(' '));
                    uploadElemProgressText.appendChild(<a href="javascript:void(0)" onclick={() => {
                        eepromClient.delete(fileInfo)
                            .then(() => explodeUploadElem())
                            .catch(ex => {
                                console.error(ex);
                                MszShowMessageBox(ex, 'Upload Error');
                            });
                    }}>Delete</a>);

                    insertTheLinkIntoTheBoxEx2();
                } catch(ex) {
                    let errorText = 'Upload aborted.';

                    if(!ex.aborted) {
                        console.error(ex);
                        errorText = ex.toString();
                    }

                    uploadElem.classList.add('eeprom-widget-file-fail');
                    uploadElemProgressText.textContent = errorText;
                    await MszShowMessageBox(errorText, 'Upload Error');
                }
            };

            const eepromFormInput = <input type="file" multiple={true} class="eeprom-widget-form-input"
                onchange={() => {
                    const files = eepromFormInput.files;
                    for(const file of files)
                        eepromHandleFileUpload(file);
                    eepromFormInput.value = '';
                }}/>;

            const eepromForm = <label class="eeprom-widget-form">
                {eepromFormInput}
                <div class="eeprom-widget-form-text">
                    Select Files...
                </div>
            </label>;

            const eepromWidget = <div class="eeprom-widget">
                {eepromForm}
                <div class="eeprom-widget-history">
                    {eepromHistory}
                </div>
            </div>;

            form.appendChild(eepromWidget);

            textElem.addEventListener('paste', ev => {
                if(ev.clipboardData && ev.clipboardData.files.length > 0) {
                    ev.preventDefault();

                    const files = ev.clipboardData.files;
                    for(const file of files)
                        eepromHandleFileUpload(file);
                }
            });

            document.body.addEventListener('dragenter', ev => {
                ev.preventDefault();
                ev.stopPropagation();
            });
            document.body.addEventListener('dragover', ev => {
                ev.preventDefault();
                ev.stopPropagation();
            });
            document.body.addEventListener('dragleave', ev => {
                ev.preventDefault();
                ev.stopPropagation();
            });
            document.body.addEventListener('drop', ev => {
                ev.preventDefault();
                ev.stopPropagation();

                if(ev.dataTransfer && ev.dataTransfer.files.length > 0) {
                    const files = ev.dataTransfer.files;
                    for(const file of files)
                        eepromHandleFileUpload(file);
                }
            });
        });

    // hack: don't prompt user when hitting submit, really need to make this not stupid.
    buttonsElem.firstChild.addEventListener('click', () => MszForumEditorAllowClose = true);

    window.addEventListener('beforeunload', function(ev) {
        if(!MszForumEditorAllowClose && textElem.value.length > 0) {
            ev.preventDefault();
            ev.returnValue = '';
        }
    });

    const switchButtons = parser => {
        $rc(markupActs);

        const tags = MszParsing.getTagsFor(parser);
        for(const tag of tags)
            markupActs.appendChild(<button class={['forum__post__action', 'forum__post__action--tag', `forum__post__action--${tag.name}`]}
                type="button" title={tag.summary} onclick={() => $insertTags(textElem, tag.open, tag.close)}>
                <i class={tag.icon}/>
            </button>);
    };

    const renderPreview = async (parser, text) => {
        if(typeof text !== 'string')
            return '';

        const formData = new FormData;
        formData.append('post[mode]', 'preview');
        formData.append('post[text]', text);
        formData.append('post[parser]', parseInt(parser));

        const result = await $x.post('/forum/posting.php', { authed: true }, formData);

        return result.body();
    };

    const previewBtn = <button class="input__button" type="button" value="preview">Preview</button>;
    previewBtn.addEventListener('click', function() {
        if(previewBtn.value === 'back') {
            previewElem.setAttribute('hidden', 'hidden');
            textElem.removeAttribute('hidden');
            previewBtn.value = 'preview';
            previewBtn.textContent = 'Preview';
            modeElem.textContent = modeElem.dataset.original;
            modeElem.dataset.original = null;
        } else {
            const postText = textElem.value,
                postParser = parseInt(parserElem.value);

            if(lastPostText === postText && lastPostParser === postParser) {
                previewElem.removeAttribute('hidden');
                textElem.setAttribute('hidden', 'hidden');
                previewBtn.value = 'back';
                previewBtn.textContent = 'Edit';
                modeElem.dataset.original = modeElem.textContent;
                modeElem.textContent = 'Previewing';
                return;
            }

            parserElem.setAttribute('disabled', 'disabled');
            previewBtn.setAttribute('disabled', 'disabled');
            previewBtn.classList.add('input__button--busy');

            renderPreview(postParser, postText)
                .catch(() => {
                    previewElem.innerHTML = '';
                    MszShowMessageBox('Failed to render preview.');
                })
                .then(body => {
                    previewElem.classList.toggle('markdown', postParser === 2);

                    lastPostText = postText;
                    lastPostParser = postParser;
                    previewElem.innerHTML = body;

                    MszEmbed.handle($qa('.js-msz-embed-media'));

                    previewElem.removeAttribute('hidden');
                    textElem.setAttribute('hidden', 'hidden');
                    previewBtn.value = 'back';
                    previewBtn.textContent = 'Back';
                    previewBtn.removeAttribute('disabled');
                    parserElem.removeAttribute('disabled');
                    previewBtn.classList.remove('input__button--busy');
                    modeElem.dataset.original = modeElem.textContent;
                    modeElem.textContent = 'Previewing';
                });
        }
    });
    buttonsElem.insertBefore(previewBtn, buttonsElem.firstChild);

    switchButtons(parserElem.value);

    parserElem.addEventListener('change', () => {
        const postParser = parseInt(parserElem.value);
        switchButtons(postParser);

        if(previewElem.hasAttribute('hidden'))
            return;

        // dunno if this would even be possible, but ech
        if(postParser === lastPostParser)
            return;

        parserElem.setAttribute('disabled', 'disabled');
        previewBtn.setAttribute('disabled', 'disabled');
        previewBtn.classList.add('input__button--busy');

        renderPreview(postParser, lastPostText)
            .catch(() => {
                previewElem.innerHTML = '';
                MszShowMessageBox('Failed to render preview.');
            })
            .then(body => {
                previewElem.classList.add('markdown', postParser === 2);
                lastPostParser = postParser;
                previewElem.innerHTML = body;

                MszEmbed.handle($qa('.js-msz-embed-media'));

                previewBtn.removeAttribute('disabled');
                parserElem.removeAttribute('disabled');
                previewBtn.classList.remove('input__button--busy');
            });
    });
};
