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

    // PLUGIN CLASS
    // ============
    const LineClampPlugin = {
        DEFAULTS: {
            "target": null,
            "maxHeight": {
                "xs": 0,
                "sm": 0,
                "md": 0,
                "lg": 0,
                "xl": 0
            },
            "triggerMore": ".et-line-clamp-more",
            "triggerLess": ".et-line-clamp-less"
        },

        /** @type {HTMLElement} */
        element: null,

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

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

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

        /**
         * @this {PluginBase & LineClampPlugin}
         * @param {HTMLElement} element
         * @param {Object} options
         */
        init: function (element, options) {
            this.element = element;
            this.options = $.extend(this.options, {
                "target": this.$el.data('line-clamp-target'),
                "maxHeight": this.$el.data('line-clamp'),
                "triggerMore": this.$el.data('line-clamp-more'),
                "triggerLess": this.$el.data('line-clamp-less')
            });

            if (this.options.target) {
                let $foundTarget = this.$el.parent().find(this.options.target);
                if ($foundTarget.length) {
                    this.$target = $foundTarget;
                } else {
                    this.$target = this.$el;
                }
            } else {
                this.$target = this.$el;
            }

            this.$triggerMore = this.$el.parent().find(this.options.triggerMore).first();
            this.$triggerLess = this.$el.parent().find(this.options.triggerLess).first();
            this.clampLines();
        },

        /**
         * Calculate number of lines based on the max height of the content to clamp appropriately.
         *
         * @this {PluginBase & LineClampPlugin}
         */
        clampLines: function () {
            const maxHeight = this.options.maxHeight[viewport.current()] || 0;
            if (maxHeight <= 0) {
                return;
            }

            this.$target.each((index, el) => {
                const $el = $(el);

                // Check if element was initialized before - if so, do nothing.
                if($el.hasClass('initialized')) {
                    return;
                }

                $el.addClass('initializing');

                const lines = Math.floor(maxHeight / parseFloat($el.css('line-height')));

                const clampProperties = {
                    'line-clamp': lines.toString(), // lines have to be a string, otherwise it will be ignored!
                    'overflow': 'hidden',
                    'display': '-webkit-box',
                    '-webkit-box-orient': 'vertical'
                };

                const resetProperties = {
                    'line-clamp': 'initial',
                    'overflow': $el.css('overflow'),
                    'display': $el.css('display'),
                    '-webkit-box-orient': $el.css('-webkit-box-orient')
                };

                // column-count messes with line clamp/overflow, so we have set it to initial
                if ($el.css('column-count') !== 'auto') {
                    clampProperties['column-count'] = 'auto';
                    resetProperties['column-count'] = $el.css('column-count');
                }

                if(lines <= 0) {
                    // 0 is not a valid value for line-clamping, we assume the intent is to hide the content in this case.
                    delete clampProperties['line-clamp'];
                    delete resetProperties['line-clamp'];
                    clampProperties['height'] = 0;
                    resetProperties['height'] = $el.css('height');
                }

                // line clamp the element
                $el.css(clampProperties);

                // Add Fixes for Firefox as it has problems with line clamping when containing display: block elements
                if (/Gecko.*Firefox\/(\d+)/.exec(window.navigator.userAgent)) {
                    $el.addClass('line-clamp-fix');
                }

                // detect if element is now actually line-clamped and show line-clamp-more trigger, we do not show the trigger if line-clamping removed all the text (i.e. lines <= 0)
                if ($el[0].offsetHeight < $el[0].scrollHeight && lines > 0) {
                    this.$triggerMore.attr('aria-expanded', 'false');
                    this.$triggerMore.show();
                    this.$triggerLess.attr('aria-expanded', 'false');
                    this.$triggerLess.hide();
                    $el.removeClass('is--open');

                    this.$triggerMore.on('click', (event) => {
                        event.preventDefault();
                        $el.css(resetProperties);
                        this.$triggerMore.attr('aria-expanded', 'true');
                        this.$triggerMore.hide();
                        this.$triggerLess.attr('aria-expanded', 'true');
                        this.$triggerLess.show();
                        $el.addClass('is--open');
                    });

                    this.$triggerMore.on('keyup', (e) => {
                        e.preventDefault();
                        e.stopImmediatePropagation();
                        if(e.key === 'Enter' || e.key === ' ') {
                            this.$triggerMore.trigger('click');
                        }
                    });

                    this.$triggerLess.on('click', (event) => {
                        event.preventDefault();
                        $el.css(clampProperties);
                        this.$triggerMore.attr('aria-expanded', 'true');
                        this.$triggerMore.hide();
                        this.$triggerLess.attr('aria-expanded', 'true');
                        this.$triggerLess.show();
                        $el.removeClass('is--open');
                    });

                    // Also register on keyboard events
                    this.$triggerLess.on('keyup', (e) => {
                        e.preventDefault();
                        e.stopImmediatePropagation();
                        if(e.key === 'Enter' || e.key === ' ') {
                            this.$triggerLess.trigger('click');
                        }
                    });
                } else {
                    // The element is shorter than the line-clamping setting, mark it as open.
                    $el.addClass('is--open');
                }

                $el.addClass('initialized').removeClass('initializing');
            });

            this.Events.publish('easytemplate/Plugin/LineClampPlugin/onClampLines', [this, {maxHeight}]);
        }
    };

    // 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-line-clamp]', LineClampPlugin, 'etLineClampPlugin');
    // Force plugin manager to re-initialize us on variation load
    $(window).on('article-variation-loaded.et evo:loaded.evo.content', function () {
        manager.reinitialize('etLineClampPlugin');
    });
})(jQuery, document, window, ResponsiveBootstrapToolkit);