<template>
    <div class="markdown-editor">
        <div class="md-editor">
            <div class="controls">
                <ul ref="controlsList">
                    <li><a href="javascript:void(0)" @click="insertTag('**', '**')"><i class="fas fa-bold"></i></a></li>
                    <li><a href="javascript:void(0)" @click="insertTag('*', '*')"><i class="fas fa-italic"></i></a></li>
                    <li><a href="javascript:void(0)" @click="insertTag('<u>', '</u>')"><i class="fas fa-underline"></i></a></li>
                    <li><a href="javascript:void(0)" @click="insertTag('<s>', '</s>')"><i class="fas fa-strikethrough"></i></a></li>
                    <li><a href="javascript:void(0)" @click="insertTag('- ', null, true)"><i class="fas fa-list-ul"></i></a></li>
                    <li><a href="javascript:void(0)" @click="insertTag('1. ', null, true)"><i class="fas fa-list-ol"></i></a></li>
                    <li><a href="javascript:void(0)" @click="imagePopupOpen = !imagePopupOpen"><i class="fas fa-image"></i></a></li>
                    <li><a href="javascript:void(0)" @click="linkPopupOpen = !linkPopupOpen"><i class="fas fa-link"></i></a></li>
                    <li><a href="javascript:void(0)" @click="insertTag('> ', null, true)"><i class="fas fa-quote-left"></i></a></li>
                    <li><a href="javascript:void(0)" @click="insertTag('`', '`')"><i class="fas fa-code"></i></a></li>
                    <li><a href="javascript:void(0)" @click="insertTag('<details><summary>', '</summary>\n    \n</details>')"><i class="fas fa-caret-square-down"></i></a></li>
                    <li><a href="javascript:void(0)" @click="insertTag('\n| header | header |\n| ------ | ------ |\n| cell | cell |\n| cell | cell |\n', '')"><i class="fas fa-table"></i></a></li>
                </ul>
            </div>
            <textarea class="input" ref="textarea" v-model="markdown" :cols="cols" :rows="rows"></textarea>
        </div>
        <button class="submit" @click="save">Save</button>
        <div class="render" v-html="html" v-if="render"></div>

        <div class="popup" :style="{ top: popupTop + 'px', left: popupLeft + 'px' }" v-if="imagePopupOpen">
            Insert Image
            <form @submit.prevent="onImageInsert">
                <input type="text" name="url">
                or
                <input type="file" name="image" accept="image/*">
                <button class="submit">Insert</button>
            </form>
        </div>
        <div class="popup" :style="{ top: popupTop + 'px', left: popupLeft + 'px' }" v-else-if="linkPopupOpen">
            Insert Link
            <form @submit.prevent="onLinkInsert">
                <input type="text" name="url">
                <button class="submit">Insert</button>
            </form>
        </div>
    </div>
</template>

<script>
import { debounce } from "../helpers";
import { nextTick } from "vue";

export default {
    data() {
        return {
            edited: false,
            markdown: "",
            html: null,
            converter: null,
            onChange: () => {},
            imagePopupOpen: false,
            linkPopupOpen: false,
        };
    },
    props: {
        render: {
            type: Boolean,
            default: true,
        },
        cols: {
            type: Number,
            default: 30,
        },
        rows: {
            type: Number,
            default: 10,
        },
    },
    mounted() {
        this.converter = new showdown.Converter({
            tables: true,
        });
        this.onChange = debounce(() => {
            this.onChangeHandler();
        }, 500);
    },
    methods: {
        onChangeHandler() {
            this.html = this.converter.makeHtml(this.markdown);
        },
        save() {
            this.$emit('save', this.markdown);
            this.edited = false;
        },
        canRouteChange() {
            if (!this.edited) {
                return true;
            }

            return window.confirm('Do you really want to leave? You have unsaved changes!');
        },
        setContent(markdown, blockSave = true) {
            this.markdown = markdown;
            nextTick(() => {
                this.edited = blockSave;
            });
        },
        insertTag(tagFront, tagBack, startOfLine = false) {
            const textarea = this.$refs.textarea;
            const start = textarea.selectionStart;
            const end = textarea.selectionEnd;

            textarea.focus();

            if (!startOfLine) {
                textarea.selectionStart = end;
                document.execCommand('insertText', false, tagBack);

                textarea.selectionStart = start;
                textarea.selectionEnd = start;
                document.execCommand('insertText', false, tagFront);

                textarea.selectionStart = start + tagFront.length;
                textarea.selectionEnd = end + tagFront.length;
            } else {
                const contentBeforeSelection = this.markdown.slice(0, start);
                const contentSelection = this.markdown.slice(start, end - 1);

                let startLinePos = contentBeforeSelection.lastIndexOf('\n');

                if (startLinePos < 0) {
                    startLinePos = -1;
                }

                let endLinePos = contentSelection.lastIndexOf('\n');

                if (endLinePos < 0) {
                    endLinePos = 0;
                } else {
                    endLinePos += contentBeforeSelection.length;
                }

                const allNewlines = [startLinePos];
                let i = startLinePos;
                while ((i = this.markdown.indexOf('\n', i+1)) >= 0) {
                    if (i <= endLinePos) {
                        allNewlines.push(i);
                    }
                }

                for (let i = 0; i < allNewlines.length; i++) {
                    textarea.selectionStart = textarea.selectionEnd = allNewlines[i] + tagFront.length * i + 1;
                    document.execCommand('insertText', false, tagFront);
                }
            }
        },
        onImageInsert(event) {
            const data = new FormData(event.target);
            const url = data.get('url');
            const image = data.get('image');

            if (image.size > 0) {
                const fr = new FileReader();
                fr.addEventListener('load', event => {
                    this.insertTag("![", `](${event.target.result})`);
                });
                fr.readAsDataURL(image);
            } else {
                if (url.length > 0) {
                    this.insertTag("![", `](${url})`);
                }
            }
        },
        onLinkInsert(event) {
            const data = new FormData(event.target);
            const url = data.get('url');

            if (url.length > 0) {
                this.insertTag("[", `](${url})`);
            }
        }
    },
    watch: {
        markdown() {
            this.edited = true;
            this.$emit('update:markdown', this.markdown);
            this.onChange();
        },
        html() {
            this.$emit('update:html', this.html);
        }
    },
    computed: {
        popupTop() {
            const rect = this.$refs.controlsList.getBoundingClientRect();
            return rect.bottom;
        },
        popupLeft() {
            const rect = this.$refs.controlsList.getBoundingClientRect();
            return rect.left;
        },
    }
}
</script>
