/**
 * Add a create new group modal to the page.
 *
 * @module     block_ned_teacher_tools/userextension
 * @class      UserExtension
 * @package    block_ned_teacher_tools
 * @copyright  2019 Michael Gardener <mgardener@cissq.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
define(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/fragment', 'core/ajax', 'core/yui', 'core/templates'],
    function($, Str, ModalFactory, ModalEvents, Fragment, Ajax, Y, Templates) {

        /**
         * Constructor
         *
         * @param {int} contextid
         * @param {int} userid
         * @param {int} cmid
         * @param {boolean} new_ext
         * @param {boolean} can_add
         *
         * Each call to init gets it's own instance of this class.
         */
        var UserExtension = function(contextid, userid, cmid, new_ext=false, can_add=false) {
            this.contextid = contextid;
            this.userid = userid;
            this.cmid = cmid;
            this.new_ext = new_ext;
            this.can_add = !new_ext && can_add;
            this.can_add_extension = (this.new_ext || this.can_add) ? 1 : 0;
            this.confirm = false;
            this.init();
        };

        /**
         * @var {Modal} modal
         * @private
         */
        UserExtension.prototype.modal = null;

        /**
         * @var {int} contextid
         * @private
         */
        UserExtension.prototype.contextid = -1;

        /**
         * @var {int} cmid
         * @private
         */
        UserExtension.prototype.userid = -1;

        /**
         * @var {int} cmid
         * @private
         */
        UserExtension.prototype.cmid = -1;

        /**
         * Initialise the class.
         *
         * @private
         * @return {Promise}
         */
        UserExtension.prototype.init = function() {
            function _get_main_modal(){
                return (this.can_add_extension ? get_ask_modal : get_main_modal).bind(this)();
            }

            function get_main_modal(){
                return ModalFactory.create({
                    type: ModalFactory.types[(this.new_ext || this.can_add) ? 'SAVE_CANCEL' : 'ALERT'],
                    title: txt['deadlineextension'],
                    body: this.getBody(),
                }).then(function(modal) {
                    // Keep a reference to the modal.
                    this.modal = modal;
                    let root = this.modal.getRoot();

                    // Forms are big, we want a big modal.
                    this.modal.setLarge();
                    modal.getModal().addClass('user-extension-modal extension-modal extension-main');

                    if (this.can_add && !this.confirm){
                        this.modal.setSaveButtonText(txt['addnewextension']);
                    }

                    // We want to reset the form every time it is opened.
                    root.on(ModalEvents.hidden, function() {
                        this.modal.setBody(this.getBody());
                    }.bind(this));

                    // We want to hide the submit buttons every time it is opened.
                    root.on(ModalEvents.shown, function() {
                        this.modal.getModal().find('.modal-footer .btn-primary').focus();
                    }.bind(this));

                    // We catch the modal save event, and use it to submit the form inside the modal.
                    // Triggering a form submission will give JS validation scripts a chance to check for errors.
                    if (this.can_add_extension){
                        root.on(ModalEvents.save, ((this.new_ext || (this.can_add && this.confirm)) ? this.submitForm : get_ask_modal).bind(this));
                    } else {
                        root.on(ModalEvents.save, this.submitForm.bind(this));
                    }
                    // We also catch the form submit event and use it to submit the form with ajax.
                    root.on('submit', 'form', this.submitFormAjax.bind(this));

                    this.modal.show();
                }.bind(this));
            }

            function get_main_modal_confirm() {
                this.confirm = true;
                return get_main_modal.bind(this)();
            }

            function get_ask_modal(){
                return ModalFactory.create({
                    type: ModalFactory.types.SAVE_CANCEL,
                    title: txt['deadlineextension'],
                    body: Templates.render('block_ned_teacher_tools/userextension_confirmation_modal', {}),
                }).then(function(modal) {
                    this.modal = modal;
                    let root = this.modal.getRoot();
                    modal.getModal().addClass('extension-modal extension-ask');
                    root.on(ModalEvents.hidden, modal.destroy.bind(modal));
                    modal.setSaveButtonText(txt['yes']);
                    root.on(ModalEvents.save, get_main_modal_confirm.bind(this));
                    root.on(ModalEvents.shown, function() {
                        this.modal.getModal().find('.modal-footer .btn-primary').focus();
                    }.bind(this));
                    modal.show();
                }.bind(this));
            }

            let txt = {};
            let strings = ['deadlineextension', 'yes', 'addnewextension'];
            let strings_comp = [];

            strings.forEach(el => strings_comp.push({key: el, component: 'block_ned_teacher_tools'}));
            return Str.get_strings(strings_comp).then(function(string_result) {
                strings.forEach((el,i) => (txt[el] = string_result[i]));
                return (_get_main_modal).bind(this)();
            }.bind(this));
        };

        /**
         * @method getBody
         * @private
         * @return {Promise}
         */
        UserExtension.prototype.getBody = function(formdata) {
            if (typeof formdata === "undefined") {
                formdata = {};
            }
            // Get the content of the modal.
            var params = {
                jsonformdata: JSON.stringify(formdata),
                userid: this.userid,
                cmid: this.cmid,
                add_new: (this.can_add_extension && this.confirm) ? 1 : 0,
            };
            return Fragment.loadFragment('block_ned_teacher_tools', 'user_extension_form', this.contextid, params);
        };

        /**
         * @method handleFormSubmissionResponse
         * @private
         * @return {Promise}
         */
        UserExtension.prototype.handleFormSubmissionResponse = function() {
            this.modal.hide();
            // We could trigger an event instead.
            // Yuk.
            Y.use('moodle-core-formchangechecker', function() {
                M.core_formchangechecker.reset_form_dirty_state();
            });
            document.location.reload();
        };

        /**
         * @method handleFormSubmissionFailure
         * @private
         * @return {Promise}
         */
        UserExtension.prototype.handleFormSubmissionFailure = function(data) {
            // Oh noes! Epic fail :(
            // Ah wait - this is normal. We need to re-display the form with errors!
            this.modal.setBody(this.getBody(data));
        };

        /**
         * Private method
         *
         * @method submitFormAjax
         * @private
         * @param {Event} e Form submission event.
         */
        UserExtension.prototype.submitFormAjax = function(e) {
            // We don't want to do a real form submission.
            e.preventDefault();

            /**
             * It does not work with server validation
             * Uncomment next block, if you change type of the form validation
             *
             * Additional info:
             * @see block_ned_teacher_tools_external::submit_user_extension_form()
             * @link blocks/ned_teacher_tools/externallib.php
             *
             * @see \block_ned_teacher_tools\form\user_extension::validation()
             * @link blocks/ned_teacher_tools/classes/form/user_extension.php
             */
            /*
            // start validation
            var changeEvent = document.createEvent('HTMLEvents');
            changeEvent.initEvent('change', false, false);

            // Prompt all inputs to run their validation functions.
            // Normally this would happen when the form is submitted, but
            // since we aren't submitting the form normally we need to run client side
            // validation.
            this.modal.getRoot().find(':input').each(function(index, element) {
                element.dispatchEvent(changeEvent);
            });

            // Now the change events have run, see if there are any "invalid" form fields.
            var invalid = $.merge(
                this.modal.getRoot().find('[aria-invalid="true"] :input'),
                this.modal.getRoot().find('.error :input')
            );

            // If we found invalid fields, focus on the first one and do not submit via ajax.
            if (invalid.length) {
                invalid.first().focus();
                return;
            }
            // end validation
            */

            // Convert all the form elements values to a serialised string.
            var formData = this.modal.getRoot().find('form').serialize();

            // Now we can continue...
            Ajax.call([{
                methodname: 'block_ned_teacher_tools_submit_user_extension_form',
                args: {
                    contextid: this.contextid,
                    jsonformdata: JSON.stringify(formData)
                },
                done: this.handleFormSubmissionResponse.bind(this, formData),
                fail: this.handleFormSubmissionFailure.bind(this, formData)
            }]);
        };

        /**
         * This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.
         *
         * @method submitForm
         * @param {Event} e Form submission event.
         * @private
         */
        UserExtension.prototype.submitForm = function(e) {
            e.preventDefault();
            this.modal.getRoot().find('form').submit();
        };

        return /** @alias module:block_ned_teacher_tools/UserExtension */ {
            // Public variables and functions.
            /**
             * Attach event listeners to initialise this module.
             *
             * @method init
             * @param {int} contextid The course context id.
             * @param {int} userid The user id.
             * @param {int} cmid The course module id.
             * @param {boolean} new_ext Add new extension
             * @param {boolean} can_add Can add one more extension
             *
             * @return {Promise}
             */
            init: function(contextid, userid, cmid, new_ext, can_add) {
                return new UserExtension(contextid, userid, cmid, new_ext, can_add);
            },

            /**
             * Attach event listeners to initialise this module.
             *
             * @method add
             * @param {string} selector - where search elements to click
             * @param {int} contextid The course context id.
             *
             * @return {Promise}
             */
            add: function(selector, contextid){
                let UE = this;
                $(selector).delegate('[data-action=userextensionmodal]', 'click', function(e) {
                    e.preventDefault();
                    let $this = $(this);
                    let userid = $this.data('userid');
                    let cmid = $this.data('cmid');
                    let new_ext = $this.hasClass('new_extension');
                    let can_add_more = $this.hasClass('add_extension');
                    UE.init(contextid, userid, cmid, new_ext, can_add_more);
                });
            },
        };
    });