$(function () {
    function AnnouncementsViewModel(parameters) {
        var self = this;

        self.loginState = parameters[0];
        self.settings = parameters[1];
        self.access = parameters[2];

        self.channels = new ItemListHelper(
            "plugin.announcements.channels",
            {
                channel: function (a, b) {
                    // sorts ascending
                    if (
                        a["channel"].toLocaleLowerCase() <
                        b["channel"].toLocaleLowerCase()
                    )
                        return -1;
                    if (
                        a["channel"].toLocaleLowerCase() >
                        b["channel"].toLocaleLowerCase()
                    )
                        return 1;
                    return 0;
                }
            },
            {},
            "name",
            [],
            [],
            5
        );
        self.unreadArticles = ko.observableArray([]);
        self.markingAllAsRead = ko.observable(false);

        self.unread = ko.observable(0);
        self.unreadText = ko.pureComputed(() =>
            self.unread() ? (self.unread() > 9 ? "∞" : "" + self.unread()) : ""
        );
        self.unreadSuffix = ko.pureComputed(() =>
            self.unread() ? "(" + self.unread() + ")" : ""
        );
        self.hiddenChannels = [];
        self.channelNotifications = {};

        self.announcementDialog = undefined;
        self.announcementDialogContent = undefined;
        self.announcementDialogTabs = undefined;

        self.setupTabLink = function (item) {
            $("a[data-toggle='tab']", item).on("show", self.resetContentScroll);
        };

        self.resetContentScroll = function () {
            self.announcementDialogContent.scrollTop(0);
        };

        self.toggleButtonCss = function (data) {
            var icon = data.enabled ? "fa fa-toggle-on" : "fa fa-toggle-off";
            var disabled = self.enableToggle(data) ? "" : " disabled";

            return icon + disabled;
        };

        self.toggleButtonTitle = function (data) {
            return data.forced
                ? gettext("Cannot be toggled")
                : data.enabled
                ? gettext("Disable Channel")
                : gettext("Enable Channel");
        };

        self.enableToggle = function (data) {
            return !data.forced;
        };

        self.cleanedLink = function (data) {
            // Strips any query parameters from the link and returns it
            var link = data.link;
            if (!link) return link;

            var queryPos = link.indexOf("?");
            if (queryPos !== -1) {
                link = link.substr(0, queryPos);
            }
            return link;
        };

        self.markRead = function (channel, until, reload) {
            if (
                !self.loginState.hasPermission(
                    self.access.permissions.PLUGIN_ANNOUNCEMENTS_READ
                )
            )
                return;

            reload = !!reload;

            var url = PLUGIN_BASEURL + "announcements/channels/" + channel;

            var payload = {
                command: "read",
                until: until
            };

            $.ajax({
                url: url,
                type: "POST",
                dataType: "json",
                data: JSON.stringify(payload),
                contentType: "application/json; charset=UTF-8",
                success: function () {
                    if (reload) {
                        self.retrieveData();
                    }
                }
            });
        };

        self.markAllRead = function (reload) {
            if (
                !self.loginState.hasPermission(
                    self.access.permissions.PLUGIN_ANNOUNCEMENTS_READ
                )
            )
                return;

            reload = !!reload;

            var url = PLUGIN_BASEURL + "announcements/channels";

            var payload = {
                command: "read"
            };

            self.markingAllAsRead(true);
            $.ajax({
                url: url,
                type: "POST",
                dataType: "json",
                data: JSON.stringify(payload),
                contentType: "application/json; charset=UTF-8",
                success: function () {
                    if (reload) {
                        self.retrieveData();
                    }
                }
            }).always(() => {
                self.markingAllAsRead(false);
            });
        };

        self.toggleChannel = function (channel) {
            if (
                !self.loginState.hasPermission(
                    self.access.permissions.PLUGIN_ANNOUNCEMENTS_MANAGE
                )
            )
                return;

            var url = PLUGIN_BASEURL + "announcements/channels/" + channel;

            var payload = {
                command: "toggle"
            };

            $.ajax({
                url: url,
                type: "POST",
                dataType: "json",
                data: JSON.stringify(payload),
                contentType: "application/json; charset=UTF-8",
                success: function () {
                    self.retrieveData();
                }
            });
        };

        self.refreshAnnouncements = function () {
            self.retrieveData(true);
        };

        self.retrieveData = function (force) {
            if (
                !self.loginState.hasPermission(
                    self.access.permissions.PLUGIN_ANNOUNCEMENTS_READ
                )
            )
                return;

            var url = PLUGIN_BASEURL + "announcements/channels";
            if (force) {
                url += "?force=true";
            }

            $.ajax({
                url: url,
                type: "GET",
                dataType: "json",
                success: function (data) {
                    self.fromResponse(data);
                }
            });
        };

        self.fromResponse = function (data) {
            if (
                !self.loginState.hasPermission(
                    self.access.permissions.PLUGIN_ANNOUNCEMENTS_READ
                )
            )
                return;

            var currentTab = $("li.active a", self.announcementDialogTabs).attr("href");

            var unread = 0;
            var channels = [];
            var unreadArticles = [];
            _.each(data.channels, function (value) {
                value.last = value.data.length ? value.data[0].published : undefined;
                value.count = value.data.length;
                value.title =
                    value.channel + (value.unread ? " (" + value.unread + ")" : "");
                unread += value.unread;
                if (value.unread) {
                    _.each(
                        _.filter(value.data, (entry) => !entry.read),
                        (entry) => {
                            const extended = {...entry};
                            extended.channel = value.channel;
                            unreadArticles.push(extended);
                        }
                    );
                }
                channels.push(value);
            });
            self.channels.updateItems(channels);
            self.unread(unread);

            unreadArticles.sort((a, b) => a.published < b.published);
            self.unreadArticles(unreadArticles);

            self.displayAnnouncements(channels);

            self.selectTab(currentTab);
        };

        self.showAnnouncementDialog = function (channel) {
            if (
                !self.loginState.hasPermission(
                    self.access.permissions.PLUGIN_ANNOUNCEMENTS_READ
                )
            )
                return;

            // lazy load images that still need lazy-loading
            $("#plugin_announcements_dialog_content article img").lazyload();

            self.announcementDialogContent.scrollTop(0);

            if (!self.announcementDialog.hasClass("in")) {
                self.announcementDialog
                    .modal({
                        minHeight: function () {
                            return Math.max($.fn.modal.defaults.maxHeight() - 80, 250);
                        }
                    })
                    .css({
                        "margin-left": function () {
                            return -($(this).width() / 2);
                        }
                    });
            }

            var tab = undefined;
            if (channel) {
                tab = "#plugin_announcements_dialog_channel_" + channel;
            }
            self.selectTab(tab);

            return false;
        };

        self.selectTab = function (tab) {
            if (tab != undefined) {
                if (!_.startsWith(tab, "#")) {
                    tab = "#" + tab;
                }
                $('a[href="' + tab + '"]', self.announcementDialogTabs).tab("show");
            } else {
                $("a:first", self.announcementDialogTabs).tab("show");
            }
        };

        self.displayAnnouncements = function (channels) {
            if (
                !self.loginState.hasPermission(
                    self.access.permissions.PLUGIN_ANNOUNCEMENTS_READ
                )
            )
                return;

            var displayLimit =
                self.settings.settings.plugins.announcements.display_limit();
            var maxLength = self.settings.settings.plugins.announcements.summary_limit();

            var cutAfterNewline = function (text) {
                text = text.trim();

                var firstNewlinePos = text.indexOf("\n");
                if (firstNewlinePos > 0) {
                    text = text.substr(0, firstNewlinePos).trim();
                }

                return text;
            };

            var stripParagraphs = function (text) {
                if (_.startsWith(text, "<p>")) {
                    text = text.substr("<p>".length);
                }
                if (_.endsWith(text, "</p>")) {
                    text = text.substr(0, text.length - "</p>".length);
                }

                return text.replace(/<\/p>\s*<p>/gi, "<br>");
            };

            _.each(channels, function (value) {
                var key = value.key;
                var channel = value.channel;
                var priority = value.priority;
                var items = value.data;

                if (value.priority !== 1) {
                    // channel not priority and not manually set to popup, ignore
                    return;
                }

                if ($.inArray(key, self.hiddenChannels) > -1) {
                    // channel currently ignored
                    return;
                }

                var newItems = _.filter(items, (entry) => !entry.read);
                if (newItems.length == 0) {
                    // no new items at all, we don't display anything for this channel
                    return;
                }

                var displayedItems;
                if (newItems.length > displayLimit) {
                    displayedItems = newItems.slice(0, displayLimit);
                } else {
                    displayedItems = newItems;
                }
                var rest = newItems.length - displayedItems.length;

                var text = "<ul style='margin-top: 10px; margin-bottom: 10px'>";
                _.each(displayedItems, function (item) {
                    var limitedSummary = stripParagraphs(
                        item.summary_without_images.trim()
                    );
                    if (limitedSummary.length > maxLength) {
                        limitedSummary = limitedSummary.substr(0, maxLength);
                        limitedSummary = limitedSummary.substr(
                            0,
                            Math.min(
                                limitedSummary.length,
                                limitedSummary.lastIndexOf(" ")
                            )
                        );
                        limitedSummary += "...";
                    }

                    text +=
                        "<li><a href='" +
                        item.link +
                        "' target='_blank' rel='noreferrer noopener'>" +
                        cutAfterNewline(item.title) +
                        "</a><br><small>" +
                        formatTimeAgo(item.published) +
                        "</small><p>" +
                        limitedSummary +
                        "</p></li>";
                });
                text += "</ul>";

                if (rest) {
                    text +=
                        "<p>" +
                        gettext(_.sprintf("... and %(rest)d more.", {rest: rest})) +
                        "</p>";
                }

                text +=
                    "<small>" +
                    gettext(
                        "You can edit your announcement subscriptions under Settings > Announcements."
                    ) +
                    "</small>";

                var options = {
                    title: channel,
                    text: text,
                    hide: false,
                    confirm: {
                        confirm: true,
                        buttons: [
                            {
                                text: gettext("Later"),
                                click: function (notice) {
                                    notice.remove();
                                    self.hiddenChannels.push(key);
                                }
                            },
                            {
                                text: gettext("Mark read"),
                                click: function (notice) {
                                    notice.remove();
                                    self.markRead(key, value.last);
                                }
                            },
                            {
                                text: gettext("Read..."),
                                addClass: "btn-primary",
                                click: function (notice) {
                                    notice.remove();
                                    self.showAnnouncementDialog(key);
                                    self.markRead(key, value.last);
                                }
                            }
                        ]
                    },
                    buttons: {
                        sticker: false,
                        closer: false
                    }
                };

                if (priority === 1) {
                    options.type = "error";
                }

                if (self.channelNotifications[key]) {
                    self.channelNotifications[key].remove();
                }
                self.channelNotifications[key] = new PNotify(options);
            });
        };

        self.hideAnnouncements = function () {
            _.each(self.channelNotifications, function (notification, key) {
                notification.remove();
            });
            self.channelNotifications = {};
        };

        self.configureAnnouncements = function () {
            self.settings.show("settings_plugin_announcements");
        };

        self.onUserPermissionsChanged =
            self.onUserLoggedIn =
            self.onUserLoggedOut =
                function () {
                    if (
                        !self.loginState.hasPermission(
                            self.access.permissions.PLUGIN_ANNOUNCEMENTS_READ
                        )
                    ) {
                        self.hideAnnouncements();
                    } else {
                        self.retrieveData();
                    }
                };

        self.onStartup = function () {
            self.announcementDialog = $("#plugin_announcements_dialog");
            self.announcementDialogContent = $("#plugin_announcements_dialog_content");
            self.announcementDialogTabs = $("#plugin_announcements_dialog_tabs");
        };

        self.onEventConnectivityChanged = function (payload) {
            if (!payload || !payload.new) return;
            self.retrieveData();
        };
    }

    OCTOPRINT_VIEWMODELS.push({
        construct: AnnouncementsViewModel,
        dependencies: ["loginStateViewModel", "settingsViewModel", "accessViewModel"],
        elements: [
            "#plugin_announcements_dialog",
            "#settings_plugin_announcements",
            "#navbar_plugin_announcements"
        ]
    });
});
