/* eslint no-var: "error" */
/* eslint no-console: "off" */
/* eslint no-bitwise: "off" */
/* eslint-disable no-trailing-spaces */
/* 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';
// import {markFormSubmitted} from 'core_form/changechecker'; // Moodle 4.00+ only
// import {notifyFormSubmittedByJavascript} from 'core_form/events'; // Moodle 4.00+ only

/* Moodle 3.11 safe import for when needed
let markFormSubmitted = () => {};
let notifyFormSubmittedByJavascript = () => {};

import('core_form/changechecker').then((ns) => {
    debug.info(ns);
    if(ns.markFormSubmitted) {
        markFormSubmitted = ns.markFormSubmitted;
    }
    if(ns.notifyFormSubmittedByJavascript) {
        notifyFormSubmittedByJavascript = ns.notifyFormSubmittedByJavascript;
    }
}).catch(()=>{});
*/

/**
 * 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({
            editmod: {
                save$core: "save$core",
                cancel$core: "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,
                    submitok: false,
                    observer: null,
                    inputs: [],
                };
            },
            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 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() {
                    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()) {
                        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);
                            self.$emit("saved", updatedplan, formdata);
                            return;
                        }).catch(notification.exception);
                    }
                    /* 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"
                    :ok-title="text.save$core"
                    ><div :class="'s-mform-content'" ref="content"
                        ><div class="d-flex justify-content-center mb-3"
                            ><b-spinner variant="primary"></b-spinner
                        ></div
                    ></div
                ></b-modal>
            </span>
            `,
        });
    }
};

