/* eslint no-var: "error" */
/* eslint no-console: "off" */
/* eslint no-bitwise: "off" */
/* eslint camelcase: "off" */
/* eslint capitalized-comments: "off" */
/* eslint-env es6 */

import {call} from 'core/ajax';
import {processCollectedJavascript} from 'core/fragment';
import {replaceNodeContents} from 'core/templates';
import notification from 'core/notification';
import {loadStrings} from './string-helper';
import Debugger from './debugger';

/**
 * Create a random UUID in both secure and insecure contexts
 * @returns {String} UUID
 */
function create_uuid() {
    if (crypto.randomUUID !== undefined) {
        return crypto.randomUUID();
    } else {
        return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
            (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        );
    }
}

export default {
    install(Vue /* ,options */) {
        let debug = new Debugger("treestudyplan-mform-helper");
        let strings = loadStrings({
            mform: {
                save: "save@core",
                cancel: "cancel@core",
            }
        });

        Vue.component('mform', {
            props: {
                name: {
                    type: String,
                },
                params: {
                    type: Object,
                },
                title: {
                    type: String,
                    'default': "",
                },
                variant: {
                    type: String,
                    'default': "primary",
                },
                type: {
                    type: String,
                    'default': "link",
                }
            },
            data() {
                return {
                    content: "",
                    loading: true,
                    uuid: create_uuid(),
                    text: strings.mform,
                    submitok: false,
                    observer: null,
                    inputs: [],
                    saving: false,
                };
            },
            computed: {
            },
            methods: {
                openForm() {
                    const self = this;
                    self.$refs.editormodal.show();
                },
                onShown() {
                    const self = this;
                    debug.info(`Loading form "${self.name}" with params`, self.params);
                    self.loading = false;
                    call([{
                        methodname: 'local_treestudyplan_get_mform',
                        args: {formname: self.name, params: JSON.stringify(self.params)}
                    }])[0].then((data) => {

                        const modalbody = self.$refs.editormodal.$refs.body;
                        modalbody.style.scrollBehavior = "smooth";
                        new ResizeObserver((entries, ro) => {
                            setTimeout(() => {
                                debug.info("Scrolling modal to top", modalbody);
                                modalbody.scrollTo(0, 0);
                            }, 100);
                            ro.disconnect();
                        }).observe(modalbody);

                        const html = data.html;
                        self.loading = false;
                        // Process the collected javascript;
                        const js = processCollectedJavascript(data.javascript);
                        replaceNodeContents(self.$refs.content, html, js);
                        self.initListenChanges();
                        return;
                    }).catch(notification.exception);

                },
                onSave(bvModalEvent) {
                    const self = this;
                    let form = this.$refs.content.getElementsByTagName("form")[0];
                    // markFormSubmitted(form); // Moodle 4.00+ only
                    // We call this, so other modules can update the form with the latest state.
                    form.dispatchEvent(new Event("save-form-state"));
                    // Tell all form fields we are about to submit the form.
                    // notifyFormSubmittedByJavascript(form); // Moodle 4.00+ only

                    const formdata = new FormData(form);
                    const data = new URLSearchParams(formdata).toString();

                    if (this.checkSave()) {
                        bvModalEvent.preventDefault(); // Do not hide the modal.
                        this.saving = true;
                        call([{
                            methodname: 'local_treestudyplan_submit_mform',
                            args: {formname: self.name, params: JSON.stringify(self.params), formdata: data}
                        }])[0].then((response) => {
                            const updatedplan = JSON.parse(response.data);
                            // Hide the modal manually after save was complete.
                            self.$nextTick(() => {
                                debug.info("Attempting hide");
                                self.$refs.editormodal.hide();
                            });
                            self.saving = false;
                            self.$emit("saved", updatedplan, formdata);
                            return;
                        }).catch(notification.exception).catch(() => {
                            self.saving = false;
                        });
                    }
                    /* No error if we cannot save, since it would just be to handle the edge case
                       where someone clicks on the save button before
                       an invalid input got a chance to update. */
                },
                checkSave() {
                    let canSave = true;
                    this.inputs.forEach(el => {
                        el.focus();
                        el.blur();
                        if (el.classList.contains("is-invalid")) {
                            canSave = false;
                        }
                    }, this);
                    this.submitok = canSave;
                    return canSave;
                },
                initListenChanges() {
                    const content = this.$refs.content;
                    this.inputs = content.querySelectorAll("input.form-control");

                    // Check if save needs to be blocked immediately. (delay call by a few ms)
                    setTimeout(this.checkSave, 100);

                    // Disconnect any existing observer.
                    if (this.observer) {
                        this.observer.disconnect();
                    }
                    // Initialize new observer and callback.
                    this.observer = new MutationObserver((mutationList) => {
                        for (const mix in mutationList) {
                            const mutation = mutationList[mix];
                            if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                                this.checkSave();
                            }
                        }
                    });

                    // Connect the observer to the form inputs.
                    this.inputs.forEach(el => {
                        this.observer.observe(el, {attributes: true});
                    }, this);
                },
            },
            unmount() {
                if (this.observer) {
                    this.observer.disconnect();
                }
            },
            template: `
            <span class='mform-container'>
                <b-button :variant="variant" v-if='type == "button"' @click.prevent='openForm'
                    ><slot><i class='fa fa-gear'></i></slot></b-button>
                <a variant="variant" v-else href='#' @click.prevent='openForm'
                    ><slot><i class='fa fa-gear'></i></slot></a>
                <b-modal
                    ref="editormodal"
                    scrollable
                    centered
                    size="xl"
                    :id="'modal-'+uuid"
                    @shown="onShown"
                    @ok="onSave"
                    :ok-disabled="!submitok"
                    :title="title"
                    ><div :class="'s-mform-content'" ref="content"
                        ><div class="d-flex justify-content-center mb-3"
                            ><b-spinner variant="primary"></b-spinner
                        ></div
                    ></div>
                    <template #modal-ok>
                        <span v-if="!saving">{{ text.save }}</span>
                        <span v-else class='spinner-border spinner-border-sm'><span class='sr-only'>Saving...</span></span>
                    </template>
                </b-modal>
            </span>
            `,
        });
    }
};

