var WdTransfLojaWidget = SuperWidget.extend({
    datasetName: "transferenciav2",
    batchSize: 1000,
    rowsCache: [],
    isIncrementalLoading: false,
    loadOffset: 0,
    batchToken: 0,
    lastChunkMarker: "",
    noPagingMode: false,
    groupKeyCandidates: ["estabelecimento", "filialOrigem", "lojaOrigem", "centroCusto", "filialDestino", "lojaDestino"],
    emptyLabel: "Nao informado",

    bindings: {
        local: {},
        global: {}
    },

    init: function() {
        this.$widget = $("#MyWidget_" + this.instanceId);
        this.bindEvents();
        this.loadData();
    },

    bindEvents: function() {
        var self = this;

        self.$widget.on("click", "[data-action='reload']", function() {
            self.loadData();
        });

        self.$widget.on("change", "[data-role='topN']", function() {
            self.render();
        });

        self.$widget.on("input", "[data-role='search']", function() {
            self.render();
        });

        self.$widget.on("keypress", "[data-role='search']", function(e) {
            if (e.which === 13) {
                e.preventDefault();
                self.render();
            }
        });
    },

    loadData: function() {
        this.batchToken++;
        this.rowsCache = [];
        this.loadOffset = 0;
        this.lastChunkMarker = "";
        this.noPagingMode = false;
        this.isIncrementalLoading = true;

        this.setLoading(true);
        this.setMessage("Carregando solicitacoes...", "info");
        this.render();
        this.loadNextBatch(this.batchToken);
    },

    loadNextBatch: function(token) {
        var self = this;
        if (token !== self.batchToken) return;

        self.fetchDatasetBatch(self.batchSize, self.loadOffset, function(err, rows) {
            if (token !== self.batchToken) return;

            if (err) {
                self.isIncrementalLoading = false;
                self.setLoading(false);
                self.render();
                self.setMessage("Erro ao carregar dataset: " + err, "danger");
                return;
            }

            rows = rows || [];
            if (!rows.length) {
                self.isIncrementalLoading = false;
                self.setLoading(false);
                self.render();
                self.setMessage("Dados carregados: " + self.formatNumber(self.rowsCache.length) + " registro(s).", "success");
                return;
            }

            var chunkMarker = self.buildChunkMarker(rows[0]);
            if (self.loadOffset > 0 && chunkMarker && chunkMarker === self.lastChunkMarker) {
                self.isIncrementalLoading = false;
                self.setLoading(false);
                self.render();
                self.setMessage("Paginacao do dataset nao evoluiu (sqlStart/offset). Verifique suporte no ambiente.", "warning");
                return;
            }

            self.lastChunkMarker = chunkMarker;
            self.rowsCache = self.rowsCache.concat(rows);
            self.loadOffset += rows.length;
            self.render();
            self.setMessage("Carregando solicitacoes... " + self.formatNumber(self.rowsCache.length) + " registro(s).", "info");

            if (self.noPagingMode) {
                self.isIncrementalLoading = false;
                self.setLoading(false);
                self.render();
                self.setMessage("Dados carregados: " + self.formatNumber(self.rowsCache.length) + " registro(s).", "success");
                return;
            }

            if (rows.length < self.batchSize) {
                self.isIncrementalLoading = false;
                self.setLoading(false);
                self.render();
                self.setMessage("Dados carregados: " + self.formatNumber(self.rowsCache.length) + " registro(s).", "success");
                return;
            }

            setTimeout(function() {
                self.loadNextBatch(token);
            }, 0);
        });
    },

    fetchDatasetBatch: function(limit, offset, callback) {
        var self = this;
        if (self.noPagingMode && offset > 0) {
            callback(null, []);
            return;
        }

        try {
            if (typeof DatasetFactory !== "undefined" && typeof DatasetFactory.getDataset === "function" &&
                typeof ConstraintType !== "undefined" && typeof DatasetFactory.createConstraint === "function") {
                var constraints = self.noPagingMode ? null : self.buildFactoryPagingConstraints(limit, offset);
                var ds = DatasetFactory.getDataset(self.datasetName, null, constraints, null);
                var rows = (ds && ds.values) ? ds.values : [];

                if (!rows.length && offset === 0 && !self.noPagingMode) {
                    var dsNoPaging = DatasetFactory.getDataset(self.datasetName, null, null, null);
                    var rowsNoPaging = (dsNoPaging && dsNoPaging.values) ? dsNoPaging.values : [];
                    if (rowsNoPaging.length) {
                        self.noPagingMode = true;
                        callback(null, rowsNoPaging);
                        return;
                    }
                }

                callback(null, rows);
                return;
            }
        } catch (e) {
            // fallback REST
        }

        this.fetchDatasetBatchViaRest(limit, offset, callback);
    },

    buildFactoryPagingConstraints: function(limit, offset) {
        var constraints = [];
        constraints.push(DatasetFactory.createConstraint("sqlLimit", String(limit), String(limit), ConstraintType.MUST));
        constraints.push(DatasetFactory.createConstraint("sqlStart", String(offset), String(offset), ConstraintType.MUST));
        constraints.push(DatasetFactory.createConstraint("offset", String(offset), String(offset), ConstraintType.MUST));
        constraints.push(DatasetFactory.createConstraint("sqlOffset", String(offset), String(offset), ConstraintType.MUST));
        return constraints;
    },

    fetchDatasetBatchViaRest: function(limit, offset, callback) {
        var self = this;
        if (self.noPagingMode && offset > 0) {
            callback(null, []);
            return;
        }

        function readRows(resp) {
            if (resp && resp.content && resp.content.values) return resp.content.values;
            if (resp && resp.values) return resp.values;
            return [];
        }

        function request(usePaging, done) {
            var constraints = usePaging ? self.buildRestPagingConstraints(limit, offset) : [];
            $.ajax({
                url: "/api/public/ecm/dataset/datasets",
                type: "POST",
                contentType: "application/json; charset=UTF-8",
                dataType: "json",
                data: JSON.stringify({
                    name: self.datasetName,
                    fields: [],
                    constraints: constraints,
                    order: []
                })
            }).done(function(resp) {
                done(null, readRows(resp) || []);
            }).fail(function(xhr) {
                var detail = xhr && (xhr.responseText || xhr.statusText || xhr.status);
                done(detail || "falha na API REST de datasets", []);
            });
        }

        request(!self.noPagingMode, function(err, rows) {
            if (err) {
                callback(err);
                return;
            }

            if (!rows.length && offset === 0 && !self.noPagingMode) {
                request(false, function(err2, rows2) {
                    if (err2) {
                        callback(err2);
                        return;
                    }
                    if (rows2.length) {
                        self.noPagingMode = true;
                    }
                    callback(null, rows2 || []);
                });
                return;
            }

            callback(null, rows || []);
        });
    },

    buildRestPagingConstraints: function(limit, offset) {
        return [
            { _field: "sqlLimit", _initialValue: String(limit), _finalValue: String(limit), _type: 1 },
            { _field: "sqlStart", _initialValue: String(offset), _finalValue: String(offset), _type: 1 },
            { _field: "offset", _initialValue: String(offset), _finalValue: String(offset), _type: 1 },
            { _field: "sqlOffset", _initialValue: String(offset), _finalValue: String(offset), _type: 1 }
        ];
    },

    buildChunkMarker: function(row) {
        if (!row) return "";
        var id = this.pick(row, ["metadata#id", "id", "WKNumProces", "processInstanceId"]);
        var state = this.pick(row, ["activity", "WKNumState", "state"]);
        return (id || "-") + "|" + (state || "-");
    },

    render: function() {
        var grouped = this.aggregateRows(this.rowsCache);
        var filteredGroups = this.filterGroups(grouped);
        var shownGroups = this.applyTopN(filteredGroups);

        this.renderChart(shownGroups, this.rowsCache.length);
    },

    aggregateRows: function(rows) {
        var map = {};
        var key;

        for (var i = 0; i < (rows || []).length; i++) {
            key = this.resolveGroupValue(rows[i]) || this.emptyLabel;

            if (!map[key]) {
                map[key] = {
                    name: key,
                    count: 0
                };
            }
            map[key].count++;
        }

        var list = [];
        for (var name in map) {
            if (map.hasOwnProperty(name)) {
                list.push(map[name]);
            }
        }

        list.sort(function(a, b) {
            if (b.count !== a.count) return b.count - a.count;
            return String(a.name).localeCompare(String(b.name));
        });

        return list;
    },

    filterGroups: function(groups) {
        var $search = this.$widget.find("[data-role='search']");
        if (!$search.length) return groups.slice(0);

        var search = $.trim(String($search.val() || "")).toLowerCase();
        if (!search) return groups.slice(0);

        var out = [];
        for (var i = 0; i < groups.length; i++) {
            var g = groups[i];
            if (String(g.name || "").toLowerCase().indexOf(search) !== -1) {
                out.push(g);
            }
        }
        return out;
    },

    applyTopN: function(groups) {
        var $top = this.$widget.find("[data-role='topN']");
        if (!$top.length) return groups.slice(0);

        var raw = $.trim(String($top.val() || "0"));
        var topN = parseInt(raw, 10);

        if (isNaN(topN) || topN < 0) topN = 0;
        if (topN === 0) return groups.slice(0);

        return groups.slice(0, topN);
    },

    renderKpis: function(allGroups, shownGroups) {
        var totalSolicitacoes = this.rowsCache.length;
        var totalGrupos = allGroups.length;
        var solicitacoesExibidas = 0;

        for (var i = 0; i < shownGroups.length; i++) {
            solicitacoesExibidas += Number(shownGroups[i].count || 0);
        }

        this.$widget.find("[data-role='kpiTotalSolicitacoes']").text(this.formatNumber(totalSolicitacoes));
        this.$widget.find("[data-role='kpiTotalGrupos']").text(this.formatNumber(totalGrupos));
        this.$widget.find("[data-role='kpiSolicitacoesExibidas']").text(this.formatNumber(solicitacoesExibidas));
    },

    renderChart: function(groups, totalRows) {
        var html = [];

        if (!groups.length) {
            var emptyMsg = this.isIncrementalLoading ?
                "Carregando dados..." :
                "Nenhum registro para os filtros informados.";
            html.push("<div class='wdtransf-agg-chart-empty'>" + this.escapeHtml(emptyMsg) + "</div>");
            this.$widget.find("[data-role='chartBars']").html(html.join(""));
            return;
        }
        var bars = [];
        for (var i = 0; i < groups.length; i++) {
            var item = groups[i];
            var count = Number(item.count || 0);
            var percentTotal = totalRows > 0 ? (count * 100 / totalRows) : 0;

            bars.push(
                "<div class='wdtransf-agg-vchart-item'>" +
                    "<div class='wdtransf-agg-vchart-value'>" + this.escapeHtml(this.formatPercent(percentTotal)) + "</div>" +
                    "<div class='wdtransf-agg-vchart-bar-wrap'>" +
                        "<div class='wdtransf-agg-vchart-bar' style='height:" + percentTotal.toFixed(2) + "%;'></div>" +
                    "</div>" +
                    "<div class='wdtransf-agg-vchart-label' title='" + this.escapeHtml(item.name) + "'>" + this.escapeHtml(item.name) + "</div>" +
                "</div>"
            );
        }

        var minWidth = Math.max(groups.length * 86, 360);

        html.push(
            "<div class='wdtransf-agg-vchart-legend'>" +
                "<span class='wdtransf-agg-vchart-legend-item'>" +
                    "<span class='wdtransf-agg-vchart-legend-swatch'></span>Participacao (%)" +
                "</span>" +
            "</div>" +
            "<div class='wdtransf-agg-vchart'>" +
                "<div class='wdtransf-agg-vchart-axis'>" +
                    "<span>100%</span><span>50%</span><span>0%</span>" +
                "</div>" +
                "<div class='wdtransf-agg-vchart-scroll'>" +
                    "<div class='wdtransf-agg-vchart-plot' style='min-width:" + minWidth + "px;'>" +
                        "<div class='wdtransf-agg-vchart-grid grid-100'></div>" +
                        "<div class='wdtransf-agg-vchart-grid grid-50'></div>" +
                        "<div class='wdtransf-agg-vchart-grid grid-0'></div>" +
                        "<div class='wdtransf-agg-vchart-bars'>" + bars.join("") + "</div>" +
                    "</div>" +
                "</div>" +
            "</div>"
        );

        this.$widget.find("[data-role='chartBars']").html(html.join(""));
    },

    resolveGroupValue: function(row) {
        return this.pick(row || {}, this.groupKeyCandidates);
    },

    pick: function(row, keys) {
        for (var i = 0; i < keys.length; i++) {
            var value = row[keys[i]];
            if (value !== null && value !== undefined && String(value).trim() !== "") {
                return String(value).trim();
            }
        }
        return "";
    },

    formatNumber: function(value) {
        var n = Number(value || 0);
        if (isNaN(n)) return "0";
        return n.toLocaleString("pt-BR");
    },

    formatPercent: function(value) {
        var n = Number(value || 0);
        if (isNaN(n)) n = 0;
        return n.toLocaleString("pt-BR", { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + "%";
    },

    renderUpdatedAt: function() {
        var now = new Date();
        var stamp = now.toLocaleDateString("pt-BR") + " " + now.toLocaleTimeString("pt-BR");
        this.$widget.find("[data-role='updatedAt']").text("Atualizado em: " + stamp);
    },

    setLoading: function(isLoading) {
        this.$widget.toggleClass("is-loading", !!isLoading);
        if (isLoading) {
            this.setMessage("Carregando dados...", "info");
        }
    },

    setMessage: function(text, type) {
        var $msg = this.$widget.find("[data-role='message']");
        $msg.removeClass("is-info is-success is-warning is-danger");

        if (!text) {
            $msg.hide().text("");
            return;
        }

        var className = "is-info";
        if (type === "success") className = "is-success";
        if (type === "warning") className = "is-warning";
        if (type === "danger") className = "is-danger";

        $msg.addClass(className).text(text).show();
    },

    escapeHtml: function(text) {
        return String(text == null ? "" : text)
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/\"/g, "&quot;")
            .replace(/'/g, "&#39;");
    }
});







