/*
 * Copyright (C) 2017 Vsevolod Stakhov <vsevolod@highsecure.ru>
 */

/* global FooTable */

define(["jquery", "app/common", "footable"],
    ($, common) => {
        "use strict";
        const ui = {};
        let altered = {};

        function clear_altered() {
            $("#save-alert").addClass("d-none");
            altered = {};
        }

        function saveSymbols(server) {
            $("#save-alert button").attr("disabled", true);

            const values = [];
            Object.entries(altered).forEach(([key, value]) => values.push({name: key, value: value}));

            common.query("./savesymbols", {
                success: function () {
                    clear_altered();
                    common.alertMessage("alert-modal alert-success", "Symbols successfully saved");
                },
                complete: () => $("#save-alert button").removeAttr("disabled"),
                errorMessage: "Save symbols error",
                method: "POST",
                params: {
                    data: JSON.stringify(values),
                    dataType: "json",
                },
                server: server
            });
        }

        function process_symbols_data(data) {
            const items = [];
            const lookup = {};
            const freqs = [];
            const distinct_groups = [];

            data.forEach((group) => {
                group.rules.forEach((item) => {
                    const formatter = new Intl.NumberFormat("en", {
                        minimumFractionDigits: 2,
                        maximumFractionDigits: 6,
                        useGrouping: false
                    });
                    item.group = group.group;
                    let label_class = "";
                    if (item.weight < 0) {
                        label_class = "scorebar-ham";
                    } else if (item.weight > 0) {
                        label_class = "scorebar-spam";
                    }
                    item.weight = '<input class="form-control input-sm mb-disabled scorebar ' + label_class +
                        '" autocomplete="off" type="number" step="0.01" tabindex="1" ' +
                        'value="' + formatter.format(item.weight) + '" id="_sym_' + item.symbol + '"></input>';
                    if (!item.time) {
                        item.time = 0;
                    }
                    item.time = Number(item.time).toFixed(2) + "s";
                    if (!item.frequency) {
                        item.frequency = 0;
                    }
                    freqs.push(item.frequency);
                    item.frequency = Number(item.frequency).toFixed(2);
                    if (!(item.group in lookup)) {
                        lookup[item.group] = 1;
                        distinct_groups.push(item.group);
                    }
                    items.push(item);
                });
            });

            // For better mean calculations
            const avg_freq = freqs
                .sort((a, b) => Number(a) < Number(b))
                .reduce((f1, acc) => f1 + acc) / (freqs.length !== 0 ? freqs.length : 1.0);
            let mult = 1.0;
            let exp = 0.0;

            if (avg_freq > 0.0) {
                while (mult * avg_freq < 1.0) {
                    mult *= 10;
                    exp++;
                }
            }
            $.each(items, (i, item) => {
                item.frequency = Number(item.frequency) * mult;

                if (exp > 0) {
                    item.frequency = item.frequency.toFixed(2) + "e-" + exp;
                } else {
                    item.frequency = item.frequency.toFixed(2);
                }
            });
            return [items, distinct_groups];
        }
        // @get symbols into modal form
        ui.getSymbols = function () {
            $("#refresh, #updateSymbols").attr("disabled", true);
            clear_altered();
            common.query("symbols", {
                success: function (json) {
                    const [{data}] = json;
                    const items = process_symbols_data(data);

                    /* eslint-disable consistent-this, no-underscore-dangle */
                    FooTable.groupFilter = FooTable.Filtering.extend({
                        construct: function (instance) {
                            this._super(instance);
                            [,this.groups] = items;
                            this.groups.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
                            this.def = "Any group";
                            this.$group = null;
                        },
                        $create: function () {
                            this._super();
                            const self = this;
                            const $form_grp = $("<div/>", {
                                class: "form-group"
                            }).append($("<label/>", {
                                class: "sr-only",
                                text: "Group"
                            })).prependTo(self.$form);

                            self.$group = $("<select/>", {
                                class: "form-select"
                            }).on("change", {
                                self: self
                            }, self._onStatusDropdownChanged).append(
                                $("<option/>", {
                                    text: self.def
                                })).appendTo($form_grp);

                            $.each(self.groups, (i, group) => {
                                self.$group.append($("<option/>").text(group));
                            });

                            common.appendButtonsToFtFilterDropdown(self);
                        },
                        _onStatusDropdownChanged: function (e) {
                            const {self} = e.data;
                            const selected = $(this).val();
                            if (selected !== self.def) {
                                self.addFilter("group", selected, ["group"]);
                            } else {
                                self.removeFilter("group");
                            }
                            self.filter();
                        },
                        draw: function () {
                            this._super();
                            const group = this.find("group");
                            if (group instanceof FooTable.Filter) {
                                this.$group.val(group.query.val());
                            } else {
                                this.$group.val(this.def);
                            }
                        }
                    });
                    /* eslint-enable consistent-this, no-underscore-dangle */

                    common.tables.symbols = FooTable.init("#symbolsTable", {
                        breakpoints: common.breakpoints,
                        cascade: true,
                        columns: [
                            {sorted: true, direction: "ASC", name: "group", title: "Group"},
                            {name: "symbol", title: "Symbol"},
                            {name: "description", title: "Description", breakpoints: "md"},
                            {name: "weight", title: "Score"},
                            {name: "frequency",
                                title: "Frequency",
                                breakpoints: "md",
                                sortValue: function (value) { return Number(value).toFixed(2); }},
                            {name: "time",
                                title: "Avg. time",
                                breakpoints: "md",
                                sortValue: function (value) { return parseFloat(value); }},
                        ],
                        rows: items[0],
                        paging: {
                            enabled: true,
                            limit: 5,
                            size: 25
                        },
                        filtering: {
                            enabled: true,
                            position: "left",
                            connectors: false
                        },
                        sorting: {
                            enabled: true
                        },
                        components: {
                            filtering: FooTable.groupFilter
                        },
                        on: {
                            "ready.ft.table": function () {
                                if (common.read_only) {
                                    $(".mb-disabled").attr("disabled", true);
                                }
                            },
                            "postdraw.ft.table":
                                () => $("#refresh, #updateSymbols").removeAttr("disabled")
                        }
                    });
                },
                error: () => $("#refresh, #updateSymbols").removeAttr("disabled"),
                server: common.getServer()
            });
        };


        $("#updateSymbols").on("click", (e) => {
            e.preventDefault();
            $("#refresh, #updateSymbols").attr("disabled", true);
            clear_altered();
            common.query("symbols", {
                success: function (data) {
                    const [items] = process_symbols_data(data[0].data);
                    common.tables.symbols.rows.load(items);
                },
                error: () => $("#refresh, #updateSymbols").removeAttr("disabled"),
                server: common.getServer()
            });
        });

        $("#symbolsTable")
            .on("input", ".scorebar", ({target}) => {
                const t = $(target);
                t.removeClass("scorebar-ham scorebar-spam");
                if (target.value < 0) {
                    t.addClass("scorebar-ham");
                } else if (target.value > 0) {
                    t.addClass("scorebar-spam");
                }
            })
            .on("change", ".scorebar", ({target}) => {
                altered[$(target).attr("id").substring(5)] = parseFloat(target.value);
                $("#save-alert").removeClass("d-none");
            });

        $("#save-alert button")
            .on("click", ({target}) => saveSymbols($(target).data("save")));

        return ui;
    });
