(function(window, document, Mautic, $, Math) {
    class Heatmap {
        constructor(emailId) {
            this.emailId = emailId;
            this.mode = 'total';
            this.content = null;
            this.clickStats = null;
            this.$modal = null;
            this.$iframe = null;
            this.$iframeBody = null;
            this.iframeDocument = null;
            this.totalClicks  = null;
            this.totalUniqueClicks = null;
            this.legendTemplate = null;
            this.links = [];
            this.gradient = [
                [44, 59, 182],   // #2c3bb6
                [10, 133, 255],  // #0a85ff
                [240, 223, 66],  // #f0df42
                [248, 195, 68],  // #f8c344
                [255, 132, 58],  // #ff843a
                [248, 56, 52]    // #f83834
            ];
        }

        init() {
            this.fetchHeatmap(function() {
                this.render();
            }.bind(this));
        }

        render() {
            this.renderModal();
            this.bindEvents();
            this.$modal.modal('show');
        }

        fetchHeatmap(callback) {
            Mautic.ajaxActionRequest('email:heatmap', {id: this.emailId}, function(response){
                this.content = response.content;
                this.clickStats = response.clickStats;
                this.totalClicks = response.totalClicks;
                this.totalUniqueClicks = response.totalUniqueClicks;
                this.legendTemplate = response.legendTemplate;
                callback();
            }.bind(this), false, true, "GET");
        }

        waitForIframeContent(callback) {
            const self = this;
            const interval = setInterval(function () {
                const height = self.$iframeBody.height();
                if (height > 0 && self.lastHeight === height) {
                    callback();
                    clearInterval(interval);
                } else {
                    self.lastHeight = height;
                }
            }, 100);
        }

        bindEvents() {
            const self = this;

            self.$iframe[0].addEventListener('load', function() {
                self.waitForIframeContent(function() {
                    self.renderLabels();
                    self.bindMouseEvents();
                });
            });

            $(window).on('resize', function() {
                self.labelPositions();
            });

            self.$modal.on('hidden.bs.modal', function () {
                $(this).remove();
            });

            $('[data-toggle="heatmap-total"]').click(function(e) {
                e.preventDefault();
                if (self.mode === 'total') return;
                self.mode = 'total';
                $('[data-heatmap-clicks]').html(self.totalClicks);
                $('[data-toggle="heatmap-unique"]').removeClass('active');
                $(this).addClass('active');
                self.removeLabels();
                self.renderLabels();
            });

            $('[data-toggle="heatmap-unique"]').click(function(e) {
                e.preventDefault();
                if (self.mode === 'unique') return;
                self.mode = 'unique';
                $('[data-heatmap-clicks]').html(self.totalUniqueClicks);
                $('[data-toggle="heatmap-total"]').removeClass('active');
                $(this).addClass('active');
                self.removeLabels();
                self.renderLabels();
            });

            $('div.heatmap-legend').on('scroll mousewheel touchmove', function(e) {
                e.preventDefault();
            });
        }

        bindMouseEvents() {
            const self = this;

            const moveUp = function() {
                const $label = $(this).hasClass('heatmap-link') ? $(this).data('heatmap-label') : $(this);
                $label.css('z-index', 2050);
            }
            const moveDown = function() {
                const $label = $(this).hasClass('heatmap-link') ? $(this).data('heatmap-label') : $(this);
                $label.css('z-index', 1050);
            }

            self.$iframeBody.on('mouseenter focus', '.heatmap-label, a.heatmap-link', moveUp);
            self.$iframeBody.on('mouseleave blur', '.heatmap-label, a.heatmap-link', moveDown);
        }

        renderModal() {
            this.$modal = $("<div />").attr({"class": "modal fade heatmap-modal"});
            const $modalDialogDiv = $("<div />").attr({"class": "modal-dialog modal-dialog-heatmap"});
            const $modalContentDiv = $("<div />").attr({"class": "modal-content"});
            this.$iframe = $('<iframe class="heatmap-iframe">' + this.content + '</iframe>');
            $modalContentDiv.append(this.$iframe);

            this.$modal.append($modalDialogDiv.append($modalContentDiv));
            $('body').append(this.$modal);

            this.iframeDocument = this.$iframe[0].contentDocument || this.$iframe[0].contentWindow.document;
            this.iframeDocument.open();
            this.iframeDocument.write(this.content);

            const cssLink = document.createElement("link");
            const baseUrl = window.mauticBaseUrl || '/';
            cssLink.href = baseUrl + 'app/bundles/EmailBundle/Assets/css/heatmap.css';
            cssLink.rel = "stylesheet";
            cssLink.type = "text/css";
            this.iframeDocument.head.appendChild(cssLink);

            this.$iframeBody = $('body', this.iframeDocument);
            this.$iframeBody.addClass('heatmap-iframe-body');
            $modalContentDiv.append(this.legendTemplate);
            $modalContentDiv.append('<button type="button" class="modal-heatmap-close close" data-dismiss="modal"><span aria-hidden="true">×</span></button>');
            this.iframeDocument.close();
        }

        renderLabels() {
            const self = this;
            self.clickStats.forEach(function(link) {
                const $a = $('a[href="' + link.url + '"]', self.$iframeBody);
                $a.addClass('heatmap-link');
                $a.each(function() {
                    const $el = $(this);
                    self.links.push($el);

                    const rate = self.mode === 'total' ? link.hits_rate : link.unique_hits_rate;
                    const percent = Math.round(rate * 100);
                    const text =  (self.mode === 'total' ? link.hits_text : link.unique_hits_text) + ' (' + percent.toString() + '%)';

                    const $label = $('<div class="heatmap-label"><p>' + text + '</p></div>');
                    const bgColor = self.interpolateColor(rate);
                    const bgColorLeft = self.interpolateColor(rate - 0.1);
                    const bgColorRight = self.interpolateColor(rate + 0.1);
                    $label.css({
                        'background-color': bgColor,
                        'background': 'linear-gradient(to right, ' +bgColorLeft+ ', '+ bgColorRight +')'
                    });
                    const $border = $('<div class="heatmap-label-border"></div>');
                    $border.css({
                        'border': '1px dashed ' + bgColor,
                        'border-bottom': 'none'
                    });
                    $label.append($border);
                    $label.attr('title', link.url);

                    self.$iframeBody.append($label);
                    $el.data('heatmap-label', $label);
                    $el.data('heatmap-label-border', $border);
                    $label.data('a', $a);
                });
            });
            self.labelPositions();
        }

        removeLabels() {
            if (!this.links.length) return;

            $(this.links).each(function() {
                $(this).data('heatmap-label').remove();
            });
            this.links = [];
        }

        labelPositions() {
            const self = this;

            $(self.links).each(function() {
                const $el = $(this);
                const $label = $el.data('heatmap-label');
                const $border = $el.data('heatmap-label-border');
                const position = $el.position();
                $label.css({
                    position: 'absolute',
                    top: position.top + $el.outerHeight(),
                    left: position.left - 1,
                    'min-width': Math.max($el.outerWidth(), 60) + 2
                });
                $border.css({
                    position: 'absolute',
                    bottom: '100%',
                    left: 0,
                    width: $el.outerWidth(),
                    height: $el.outerHeight()
                });
            });
        }

        interpolateColor(rate) {
            if (rate <= 0) {
                return 'rgb(' + this.gradient[0].join(',') + ')';
            }
            if (rate >= 1) {
                const lastIndex = this.gradient.length - 1;
                return 'rgb(' + this.gradient[lastIndex].join(',') + ')';
            }

            const segmentCount = this.gradient.length - 1;
            const segmentWidth = 1 / segmentCount;
            const segmentIndex = Math.floor(rate / segmentWidth);
            const segmentPercent = (rate - segmentIndex * segmentWidth) / segmentWidth;

            const color1 = this.gradient[segmentIndex];
            const color2 = this.gradient[segmentIndex + 1];

            const r = Math.round(color1[0] + (color2[0] - color1[0]) * segmentPercent);
            const g = Math.round(color1[1] + (color2[1] - color1[1]) * segmentPercent);
            const b = Math.round(color1[2] + (color2[2] - color1[2]) * segmentPercent);

            return 'rgb(' + r + ',' + g + ',' + b + ')';
        }
    }

    $(document).ready(function() {
        $('body').on('click', '[data-toggle="email-heatmap"]', function(e) {
            const emailId = $(this).data('email');
            const heatmap = new Heatmap(emailId);
            heatmap.init();
            e.preventDefault();
        });
    });

})(window, document, Mautic, mQuery, Math);
