Modals = (function () {
    /**
     * Store all the modals Instances
     * @type {object}
     * @private
     */
    const _modals = {};

    /**
     * Store all the modals Options objects
     * @type {object}
     * @private
     */
    const _modalsOptions = {};

    let me = null;

    /**
     * Initialization Method
     * @private
     */
    function _init() {
        //
    }

    /**
     * Get the jQuery Object of the Modal DOM Element using it's name
     * @param modalName (String) Mandatory
     * @returns {jQuery.fn.init|*|jQuery|HTMLElement}
     * @private
     */
    function _getElement(modalName) {
        return $(_modalsOptions[modalName].element);
    }

    /**
     * Open a modal
     * @param modalName (String mandatory)
     * @private
     */
    function _open(modalName) {
        const $element = _getElement(modalName);
        const options = Modals.getOptions(modalName);
        const hasSteps = options.steps !== undefined;

        if (hasSteps) {
            const isInitialized = options.steps.initialized === true;
            isInitialized ? _setStep(modalName, 1) : '';
        }

        if (!$element.hasClass('is-active')) {
            $element.addClass('is-active animated fadeIn faster');
            $('html').addClass('is-clipped');
            discord.hide();
        }
    }

    /**
     * Close a modal
     * @param modalName (String) Mandatory
     * @private
     */
    function _close(modalName) {
        const $element = _getElement(modalName);
        const options = Modals.getOptions(modalName);
        const hasSteps = options.steps !== undefined;

        if (hasSteps) {
            const isInitialized = options.steps.initialized === true;
            isInitialized ? _setStep(modalName, 1) : '';
        }

        if ($element.hasClass('is-active')) {
            $element.removeClass('is-active animated fadeIn faster');
            $('html').removeClass('is-clipped');
            discord.show();
        }
    }

    function _initSteps(modalName) {
        const $element = Modals.getElement(modalName);
        const options = Modals.getOptions(modalName);
        const hasSteps = options.steps !== undefined;
        const isInitialized = options.steps.initialized === true;
        const isClickable = options.steps.clickable === true;

        if (hasSteps) {
            if (!isInitialized) {
                if (isClickable) {
                    $('.modal-card-head [data-step]', $element).on('click', function () {
                        const stepIndex = $(this).data('step');
                        _setStep(modalName, stepIndex);
                    }).addClass('has-pointer');
                }

                $('.modal-card-foot [data-step] .next-step', $element).on('click', function () {
                    const activeStep = _getActiveStep(modalName);
                    const nextStep = activeStep + 1;

                    _setStep(modalName, nextStep);
                });

                $('.modal-card-foot [data-step] .previous-step', $element).on('click', function () {
                    const activeStep = _getActiveStep(modalName);
                    const previousStep = activeStep - 1;

                    _setStep(modalName, previousStep);
                });

                options.steps.initialized = true;
                _setStep(modalName, 1);
                // console.log(modalName + ' steps initialized');

            } else {
                // console.log('Steps for this Modal are already initialized');
            }
        } else {
            // console.log('No Steps for this Modal');
        }
    }

    function _setStep(modalName, stepIndex) {
        const $element = Modals.getElement(modalName);
        const options = Modals.getOptions(modalName);
        const hasSteps = options.steps !== undefined;
        const hasValidation = options.steps.validation !== undefined;
        let isValidated = true;

        if (hasValidation) {
            const validationMethod = options.steps.validation['step' + stepIndex];
            validationMethod !== undefined ? isValidated = validationMethod() : '';
        }

        if (hasSteps && isValidated) {
            $('.modal-card-head [data-step]', $element).removeClass('is-active');
            $('.modal-card-head [data-step="' + stepIndex + '"]', $element).addClass('is-active');

            $('.modal-card-body [data-step]', $element).addClass('is-hidden').removeClass('is-active');
            $('.modal-card-body [data-step="' + stepIndex + '"]', $element).removeClass('is-hidden').addClass('is-active');

            $('.modal-card-foot [data-step]', $element).addClass('is-hidden').removeClass('is-active');
            $('.modal-card-foot [data-step="' + stepIndex + '"]', $element).removeClass('is-hidden').addClass('is-active');

            options.steps.activeStep = stepIndex;
        }
    }

    function _getActiveStep(modalName) {
        const options = Modals.getOptions(modalName);
        const hasSteps = options.steps !== undefined;

        if (hasSteps) {
            return options.steps.activeStep;
        } else {
            return false;
        }
    }

    _init();

    return {
        onInit: function () {}, /** Default onInit Method */
        onLoad: function () {}, /** Default onLoad Method */
        onResize: function () {}, /** Default onResize Method */

        /**
         * Check if the Modal is opened / active
         * @param modalName (String) Mandatory
         * @returns {boolean}
         */
        isActive: function (modalName) { // test si la vue est déjà ouverte
            return Modals.getElement(modalName).hasClass('is-active');
        },

        /**
         * Open the Modal using it's name and execute the onOpen method
         * @param modalName (String) Mandatory
         */
        open: function (modalName) {
            _open(modalName);
            this.onOpen(modalName);
        },

        /**
         * Close the Modal using it's name and execute the onClose method
         * @param modalName (String) Mandatory
         */
        close: function (modalName) {
            _close(modalName);
            this.onClose(modalName);
        },

        initSteps: function (modalName) {
            return _initSteps(modalName);
        },

        setStep: function (modalName, stepIndex) {
            return _setStep(modalName, stepIndex);
        },

        getActiveStep: function (modalName) {
            return _getActiveStep(modalName);
        },

        /**
         * Get the jQuery Object of the Modal DOM Element using it's name
         * @param modalName (String) Mandatory
         * @returns {jQuery.fn.init|*|jQuery|HTMLElement}
         */
        getElement: function (modalName) {
            return _getElement(modalName);
        },

        /**
         * Get the modal instance using it's name
         * @param modalName (String) Mandatory
         * @returns {object}
         */
        getModal: function (modalName) {
            return _modals[modalName];
        },

        /**
         * Get the modal options using it's name
         * @param modalName (String) Mandatory
         * @returns {object}
         */
        getOptions: function (modalName) {
            return _modalsOptions[modalName];
        },

        /**
         * Return all the Modals instances
         * @returns {object}
         */
        getModals: function () {
            return _modals;
        },

        /**
         * Return all the Modals options
         * @returns {object}
         */
        getModalsOptions: function () {
            return _modalsOptions;
        },

        /**
         * Create a Modal Instance, Merge default modal methods and it's own class methods, store everying in an object.
         * @param modalSingleton (Function) Mandatory
         * @param modalOptions (Object) Mandatory
         * @returns {object}
         */
        set: function (modalSingleton, modalOptions) {

            // Check for arguments types and values
            if (typeof modalSingleton !== 'function') {
                console.log('Error : First Parameter (modalSingleton) of Set Method must be a Function');
                return false;
            }

            if (typeof modalOptions !== 'object') {
                console.log('Error : Second Parameter (modalOptions) of Set Method must be an Object');
                return false;
            }

            if (typeof modalOptions.name !== 'string' && modalOptions.name === undefined) {
                console.log('Error : modalOptions.name must be defined as a String');
                return false;
            }

            if (typeof modalOptions.element !== 'string' && modalOptions.element === undefined) {
                console.log('Error : modalOptions.element must be defined as a String');
                return false;
            }

            const fnCleaned = new modalSingleton;
            const modalName = modalOptions.name;

            const ModalsClone = Object.assign({}, Modals);

            $.each(fnCleaned, function (index, value) { // Remove override method if it's a native method of the mainModal
                if (index.substring(0, 2) !== 'on' && ModalsClone[index] !== undefined) {
                    delete fnCleaned[index]; // The found function is native to Nudl, we delete it
                }
            });

            _modals[modalName] === undefined ? _modals[modalName] = {} : '';
            _modals[modalName] = $.extend(ModalsClone, fnCleaned);

            _modalsOptions[modalName] === undefined ? _modalsOptions[modalName] = {} : '';
            _modalsOptions[modalName] = modalOptions;

            return _modals[modalName];
        }
    }
})();
