#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');
    const textElem = form.querySelector('.js-forum-posting-text');
    const parserElem = form.querySelector('.js-forum-posting-parser');
    const previewElem = form.querySelector('.js-forum-posting-preview');
    const modeElem = form.querySelector('.js-forum-posting-mode');
    const markupActs = form.querySelector('.js-forum-posting-actions');

    let lastPostText = '';
    let lastPostParser;

    const storagePool = $meta.get('forum-storage-pool');
    if(storagePool) {
        const eepromClient = new MszEEPROM(storagePool);
        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>;

            eepromHistory.insertAdjacentElement('afterbegin', uploadElem);

            const explodeUploadElem = () => { uploadElem.remove(); };
            const uploadTask = eepromClient.create(file);

            uploadTask.onProgress(prog => {
                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 = () => {
                    let insertText = location.protocol + fileInfo.url;

                    if(parserElem.value == 'bb') { // 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(parserElem.value == 'md') { // 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($text(' '));
                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 => {
        $removeChildren(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 '';
        if(typeof parser !== 'string')
            return '';

        const formData = new FormData;
        formData.append('preview', '1');
        formData.append('text', text);
        formData.append('format', parser);

        const { body } = await $xhr.post('/forum/posting.php', { authed: true }, formData);
        return 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;
            const postParser = 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 === 'md');

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

                    MszEmbed.handle($queryAll('.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', () => {
        switchButtons(parserElem.value);

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

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

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

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

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

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