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

    // PLUGIN CLASS
    // ============
     /**
     * @typedef {{
      *     tabsSelector: string,
      *     tabItemSelector: string,
      *     scrollerDisplayVisible: string,
      *     scrollerRightSelector: string,
      *     scrollerLeftSelector: string,
      *     animationSpeed: Number
      * }} TabsPlugin.Options
      */
    const TabsPlugin = {
        /** @type {TabsPlugin.Options} */
        DEFAULTS: {
            tabsSelector: '.nav-tabs',
            tabItemSelector: '.nav-item',
            scrollerDisplayVisible: 'flex',
            scrollerRightSelector: '.et-scroller-right',
            scrollerLeftSelector: '.et-scroller-left',
            animationSpeed: 400,
        },

        /** @type {TabsPlugin.Options} */
        options: null,

        /** @type {JQuery<HTMLElement>} */
        $tabs: null,

        /** @type {JQuery<HTMLElement>} */
        $tabItems: null,

        /** @type {JQuery<HTMLElement>} */
        $scrollerRight: null,

        /** @type {JQuery<HTMLElement>} */
        $scrollerLeft: null,

        /**
         * @this {PluginBase & TabsPlugin}
         * @param {HTMLElement} element
         * @param {Object} options
         */
        init: function (element, options) {
            if (this.$el.not('.initialized').length) {
                // Merge Options
                this.options = $.extend(this.options, {
                    "tabsSelector": this.$el.data('tab-selector'),
                    "tabItemSelector": this.$el.data('tab-item-selector'),
                    "scrollerRightSelector": this.$el.data('scroller-right-selector'),
                    "scrollerLeftSelector": this.$el.data('scroller-left-selector'),
                    "animationSpeed": this.$el.data('animation-speed'),
                });

                // Set Elements
                this.$tabs = this.$el.find(this.options.tabsSelector);
                this.$tabItems = this.$el.find(this.options.tabItemSelector);
                this.$scrollerRight = this.$el.find(this.options.scrollerRightSelector);
                this.$scrollerLeft = this.$el.find(this.options.scrollerLeftSelector);

                if(!this.$tabs || !this.$tabs.length || !this.$tabItems || !this.$tabItems.length) {
                    // This might happen if we try to initialize on the wrong element, e.g. a facebook iframe that also uses data-tabs
                    return;
                }


                this.registerEvents();
                this.adjustVisibility();
                this.$el.addClass('initialized');
            }
        },

        /**
         * Adjust the visibility of the scroller elements.
         *
         * @this {PluginBase & TabsPlugin}
         */
        adjustVisibility: function() {
            if (this.$el.outerWidth() < this.getWidthOfList()) {
                this.$scrollerRight.css('display', this.options.scrollerDisplayVisible);
            } else {
                this.$scrollerRight.hide();
            }

            if (this.getLeftPosition() < 0) {
                this.$scrollerLeft.css('display', this.options.scrollerDisplayVisible);
            } else {
                this.$scrollerLeft.hide();
            }

            this.Events.publish('easytemplate/Plugin/etTabsPlugin/onAdjustVisibility', [this]);
        },

        /**
         * Adjust the position of the tab items.
         *
         * @this {PluginBase & TabsPlugin}
         * @param {string} direction Either "next" or "prev"
         */
        adjustPosition: function(direction) {
            let viewportWidth = this.$el.width();
            let newOffset = 0;

            if (this.getLeftPosition() + this.getWidthOfList() < viewportWidth) {
                return;
            }

            // Get new offset to slide to based on direction
            direction = direction || 'next';
            if(direction === 'next') {
                var maxOffset = viewportWidth - this.getWidthOfList();
                newOffset = Math.max(maxOffset, this.getLeftPosition() - this.getStepSize());
            } else {
                newOffset = Math.min(0, this.getLeftPosition() + this.getStepSize());
            }

            this.$tabs.animate({ left: newOffset+"px" }, this.options.animationSpeed);

            // update button visibility
            this.$scrollerLeft.hide();
            this.$scrollerRight.hide();
            if (newOffset + this.getWidthOfList() > viewportWidth) {
                this.$scrollerRight.css('display', this.options.scrollerDisplayVisible);
            }
            if (newOffset < 0) {
                this.$scrollerLeft.css('display', this.options.scrollerDisplayVisible);
            }

            this.Events.publish(
                'easytemplate/Plugin/etTabsPlugin/onAdjustPosition',
                [this, {direction, viewportWidth, newOffset}
            ]);
        },

        /**
         * Get the width of all tab items combined.
         *
         * @this {PluginBase & TabsPlugin}
         * @returns {Number}
         */
        getWidthOfList: function() {
            let itemsWidth = 0;

            this.$tabItems.each(function() {
                itemsWidth += $(this).outerWidth(true);
            });

            this.Events.publish(
                'easytemplate/Plugin/etTabsPlugin/onGetWidthOfList',
                [this, {itemsWidth}
            ]);

            return itemsWidth;
        },

        /**
         * Get the left position offset of the tabs.
         *
         * @this {PluginBase & TabsPlugin}
         * @returns {Number}
         */
        getLeftPosition: function() {
            return Number(this.$tabs.css('left').replace('px', ''));
        },

        /**
         * Get the width of a tab item.
         *
         * @this {PluginBase & TabsPlugin}
         * @returns {Number}
         */
        getStepSize: function() {
            return this.$tabItems.width();
        },

        /**
         * Register all events
         * @this {PluginBase & TabsPlugin}
         */
        registerEvents: function() {
            const self = this;

            // Tab Control
            $('[data-tab-control]').on('click', function(e) {
                let $tabID = self.$el.find('a[href="' + $(this).attr('href') + '"]');

                if ($tabID.length) {
                    $tabID.tab('show');
                    $([document.documentElement, document.body]).animate({
                        scrollTop: $tabID.offset().top
                    }, self.options.animationSpeed);
                }
            });

            // Check scroller visibility
            $(window).on('resize',function() {
                self.adjustVisibility();
            });

            // Scroller Trigger
            self.adjustPosition.bind(self);
            this.$scrollerRight.on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();
                self.adjustPosition('next');
            });

            this.$scrollerLeft.on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();
                self.adjustPosition('prev');
            });

            // Scroller Swipe Trigger
            if (!window.easytemplate && !window.easytemplate.PointerEvents) {
                throw Error('Cannot use PointerEvents Plugin. pointer-events.js has to be loaded first!');
            }

            window.easytemplate.PointerEvents.on('swipeleft', this.$scrollerLeft, function () {
                self.adjustPosition('prev');
            });

            window.easytemplate.PointerEvents.on('swiperight', this.$scrollerRight, function () {
                self.adjustPosition('next');
            });

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

    // 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('[data-tabs]', TabsPlugin, 'etTabsPlugin');

    // Reinit Plugin after an article variation has been loaded
    $(document).on('article-variation-loaded.et', function() {
        manager.reinitialize('etTabsPlugin');
    });
})(jQuery, document, window, ResponsiveBootstrapToolkit);