(function ($, document, window, viewport) {
    'use strict';

    // PLUGIN CLASS
    // ============
    const MobileMenuPluginClass = {

        $mobileMenuWrapper: null,

        mobileMenuContainerSelector: '.et-menu-mobile',
        $mobileMenuContainer: null,

        footerPlaceholderSelector: '.et-menu-mobile-footer-placeholder',
        $footerPlaceholder: null,

        logoPlaceholderSelector: '.et-menu-mobile-logo',
        $logoPlaceholder: null,

        animationDuration: 500,
        body: null,
        $body: null,
        isFirstOpen: true,

        // mobile menu contents, i.e. the main menu's "dropdown" equivalent of the mobile menu
        contentSelector: '.et-menu-mobile-content',
        $content: null,
        contentTitleSelector: '.et-menu-mobile-content-title',
        $contentTitle: null,
        contentContainerSelector: '.et-menu-mobile-content-container',
        $contentContainer: null,
        contentBackSelector: '.et-menu-mobile-content-back-trigger',
        $contentBack: null,
        activeMenuItemId: null,
        $activeMenuItem: null,
        contentOpen: false,
        footerEnabled: true,

        $menuItems: [],
        menuContentCache: {},

        prepareMenuForFirstOpen: function () {
            // clone the footer into the menu
            if (this.$footerPlaceholder !== null && this.footerEnabled) {
                this.$footerPlaceholder.empty();
                $('#footer').clone(true, true).attr('id', 'footer-mobile-menu').appendTo(this.$footerPlaceholder);

            }
            if (this.$logoPlaceholder !== null) {
                this.$logoPlaceholder.empty();
                $('#logo').clone(true, true).attr('id', 'logo-mobile-menu').appendTo(this.$logoPlaceholder);
                // Fix the id of the cloned logo to prevent duplicate IDs
                this.$logoPlaceholder.find('#shop-logo').attr('id', 'shop-logo-mobile-menu');
            }

            // calculate the scrollbar width of the site and set it as CSS variable as this will be used to calculate the correct offset (in vw, which usually ignores scrollbars) from the right.
            document.documentElement.style.setProperty('--document-scrollbar-width', (window.innerWidth - document.documentElement.clientWidth) + 'px');

            this.Events.publish('easytemplate/Plugin/etMobileMenuPlugin/onPepareMenuForFirstOpen', [this]); // Deprecated, typo.
            this.Events.publish('easytemplate/Plugin/etMobileMenuPlugin/onPrepareMenuForFirstOpen', [this]);
        },

        closeMenu: function () {
            // animate hiding of the menu, we need to transition it manually or everything gets hidden before the transition is done
            this.$mobileMenuWrapper.find('.et-mobile-menu').animate({right: '100vw'}, {duration: this.animationDuration});
            this.$mobileMenuWrapper.removeClass('active-transition');
            setTimeout(() => {
                this.$mobileMenuWrapper.removeClass('active')
            }, this.animationDuration);
            // re-enable scrolling of the body
            this.$body.css({'overflow-y': '', 'max-height': ''});

            this.Events.publish('easytemplate/Plugin/etMobileMenuPlugin/onCloseMenu', [this]);
        },

        openMenu: function () {
            if (this.isFirstOpen) {
                this.isFirstOpen = false;
                this.prepareMenuForFirstOpen();
            }
            // animate showing of the menu - note that this works purely through css
            this.$mobileMenuWrapper.addClass('active active-transition');
            // prevent the body from scrolling in the background
            this.$body.css({'overflow-y': 'hidden', 'max-height': '100vh'});

            this.Events.publish('easytemplate/Plugin/etMobileMenuPlugin/onOpenMenu', [this]);
        },

        toggleMenu: function () {
            if (this.$mobileMenuWrapper.hasClass('active')) {
                this.closeMenu();
            } else {
                this.openMenu();
            }

            this.Events.publish('easytemplate/Plugin/etMobileMenuPlugin/onToggleMenu', [this]);
        },

        closeContent: function() {
            this.$mobileMenuContainer.css({'overflow-y': ''});
            this.$content.removeClass('active');
            this.contentOpen = false;

            this.Events.publish('easytemplate/Plugin/etMobileMenuPlugin/onCloseContent', [this]);
        },

        setContent: function($menuItem, $content) {
            if(!$content || !$content.length) {
                // probably a link menu item with no content - no need to show the popup
                return;
            }
            if($menuItem.attr('id') !== this.activeMenuItemId) {
                this.activeMenuItemId = $menuItem.attr('id');
                this.$activeMenuItem = $menuItem;
                const $title = $menuItem.find('.et-menu-item-title').first();
                this.activeMenuItemId = $menuItem.attr('id');
                this.$activeMenuItem = $menuItem;
                this.$contentTitle.empty().append($title.html());
                let $newContent;
                if(this.menuContentCache[this.activeMenuItemId]) {
                    $newContent = this.menuContentCache[this.activeMenuItemId];
                } else {
                    $newContent = $content.clone(true).removeClass('d-none');
                    if($content.data('et-menu-async-load')) {
                        let targetActiveMenuId = this.activeMenuItemId;
                        this.loadAsync(String($content.data('et-menu-async-load')), (html) => {
                            $newContent.html($(html).find('.et-menu-item-content').removeClass('d-none').html());
                            this.menuContentCache[targetActiveMenuId] = Object.assign({}, $newContent);
                        });
                    } else {
                        this.menuContentCache[this.activeMenuItemId] = Object.assign({}, $newContent);
                    }
                }
                this.$contentContainer.empty().append($newContent);
            }

            this.Events.publish('easytemplate/Plugin/etMobileMenuPlugin/onSetContent', [this, {$menuItem, $content}]);
        },

        openContent: function() {
            this.$content.css({ top: this.$mobileMenuContainer.scrollTop() + 'px'}); // correct the top position by the scroll offset of the parent container
            this.$mobileMenuContainer.css({'overflow-y': 'hidden'});
            this.$content.addClass('active');
            this.contentOpen = true;

            this.Events.publish('easytemplate/Plugin/etMobileMenuPlugin/onOpenContent', [this]);
        },

        loadAsync: function(id, callback) {
            $.evo.io().call('et360_render_widget', [id, { menuType: 'mobile', ajax: true}], {}, function (error, data) {
                if(!error && data && data.result && typeof callback === 'function') {
                    // Only apply the callback if the active menu item has not changed in the meanwhile
                    callback(data.result);
                } else {
                    console.error(error);
                }
            });
        },

        registerEvents: function () {
            // Note this plugin registers itself on body, but actually listens to events on document
            $(document).on('toggle-mobile-menu.et', () => {
                this.toggleMenu();
            });
            let $mobileMenuToggles = $('[data-toggle-mobile-menu]');
            $mobileMenuToggles.on('click', (e) => {
                e.preventDefault();
                this.toggleMenu();
            });
            $mobileMenuToggles.on('keyup', (e) => {
                e.preventDefault();
                e.stopImmediatePropagation();
                if(e.key === 'Enter' || e.key === ' ') {
                    this.toggleMenu();
                }
            });
            // register event handler to close the menu if the user clicks outside of a menu item or outside of the popup container
            $(document).click((event) => {
                const $target = $(event.target);
                if (!$target.closest(this.mobileMenuContainerSelector).length
                    && !$target.closest('[data-toggle-mobile-menu]').length) {
                    this.closeMenu();
                }
            });
            // register events on menu items and navigation within the menu
            this.$contentBack.on('click', this.closeContent.bind(this));
            this.$menuItems.each((index, menuItem) => {
                const $menuItem = $(menuItem);
                const $menuItemContent = $menuItem.find('.et-menu-item-content');
                $menuItem.on('click', (event) => {
                    if($menuItemContent.length) {
                        event.preventDefault();
                        this.setContent($menuItem, $menuItemContent);
                        this.openContent();
                    }
                });
                $menuItem.on('keypress', (event) => {
                    if(event.key === ' ' || event.key === 'Enter') {
                        if($menuItemContent.length) {
                            event.preventDefault();
                            this.setContent($menuItem, $menuItemContent);
                            this.openContent();
                        }
                    }
                });
            });

            // Swipe events - those are not native and not available without jQuery Mobile
            window.easytemplate.PointerEvents.on('swipeleft', this.$mobileMenuContainer, () => {
                if(this.contentOpen) {
                    this.closeContent();
                } else {
                    this.closeMenu();
                }
            });

            this.Events.publish('easytemplate/Plugin/etMobileMenuPlugin/onRegisterEvents', [this]);
        },

        /**
         * @this {PluginBase & MobileMenuPluginClass}
         * @param {HTMLElement} element
         * @param {Object} options
         */
        init: function (element, options) {
            this.body = element;
            this.$body = this.$el;
            this.$mobileMenuWrapper = $('#et-menu-mobile-wrapper');
            if (this.$mobileMenuWrapper.length) {
                let $mobileMenuContainer = this.$mobileMenuWrapper.find(this.mobileMenuContainerSelector);
                if ($mobileMenuContainer.length) {
                    this.$mobileMenuContainer = $mobileMenuContainer;
                }
                let $footerPlaceholder = this.$mobileMenuWrapper.find(this.footerPlaceholderSelector);
                if ($footerPlaceholder.length) {
                    this.$footerPlaceholder = $footerPlaceholder;
                }
                let $logoPlaceholder = this.$mobileMenuWrapper.find(this.logoPlaceholderSelector);
                if ($logoPlaceholder.length) {
                    this.$logoPlaceholder = $logoPlaceholder;
                }
                let $content = this.$mobileMenuWrapper.find(this.contentSelector);
                if ($content.length) {
                    this.$content = $content;
                }
                let $contentBack = this.$mobileMenuWrapper.find(this.contentBackSelector);
                if ($contentBack.length) {
                    this.$contentBack = $contentBack;
                }
                let $contentTitle = this.$mobileMenuWrapper.find(this.contentTitleSelector);
                if ($contentTitle.length) {
                    this.$contentTitle = $contentTitle;
                }
                let $contentContainer = this.$mobileMenuWrapper.find(this.contentContainerSelector);
                if ($contentContainer.length) {
                    this.$contentContainer = $contentContainer;
                }
                this.$menuItems = this.$mobileMenuWrapper.find('.et-menu-item');
                if (this.$mobileMenuContainer.length) {
                    this.registerEvents();
                }
                if(typeof this.$mobileMenuWrapper.data('menuFooterEnabled') !== 'undefined') {
                    this.footerEnabled = this.$mobileMenuWrapper.data('menuFooterEnabled');
                }
            }
        },
    };

    // REGISTER AND ADD THE PLUGIN
    // ===========================
    if (!window.easytemplate && !window.easytemplate.PluginManager) {
        throw Error('Cannot initialize Easytemplate Plugin. plugin-manager.js has to be loaded first!');
    }

    /** @type {PluginManager} manager */
    const manager = window.easytemplate.PluginManager;
    manager.addPlugin('body', MobileMenuPluginClass, 'etMobileMenuPlugin');
})(jQuery, document, window, ResponsiveBootstrapToolkit);