var WdTransfWidget = SuperWidget.extend({
    datasetName: "transferenciav2",
    pageSize: 10,
    batchSize: 1000,
    currentPage: 1,
    rowsCache: [],
    isIncrementalLoading: false,
    loadOffset: 0,
    batchToken: 0,
    lastChunkMarker: "",
    noPagingMode: false,

    stageDefs: [
        { label: "Solicitacao", activities: ["0", "1"] },
        { label: "Aprovacao", activities: ["4"] },
        { label: "Emissao NFe", activities: ["6"] },
        { label: "Coleta", activities: ["31"] },
        { label: "Entrega", activities: ["57"] },
        { label: "Recebimento", activities: ["18"] },
        { label: "Consultar Entrada", activities: ["99"] },
        { label: "Verificar Problema", activities: ["24", "104"] },
        { label: "Finalizada", activities: ["96", "101"] },
        { label: "Cancelada", activities: ["39", "60"] }
    ],

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

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

    bindEvents: function() {
        var self = this;

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

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

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

        self.$widget.on("click", "[data-action='prevPage']", function() {
            self.setPage(self.currentPage - 1);
        });

        self.$widget.on("click", "[data-action='nextPage']", function() {
            self.setPage(self.currentPage + 1);
        });
    },

    populateActivityFilter: function() {
        var added = {};
        var options = ["<option value=''>Todas</option>"];

        for (var i = 0; i < this.stageDefs.length; i++) {
            var stage = this.stageDefs[i];
            for (var j = 0; j < stage.activities.length; j++) {
                var code = String(stage.activities[j]);
                if (added[code]) continue;
                added[code] = true;
                options.push(
                    "<option value='" + this.escapeHtml(code) + "'>" +
                    this.escapeHtml(code + " - " + this.getActivityLabel(code)) +
                    "</option>"
                );
            }
        }

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

    loadData: function() {
        this.batchToken++;
        this.rowsCache = [];
        this.currentPage = 1;
        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 : [];

                // Fallback para datasets (card/form) que nao suportam sqlLimit/sqlStart como MUST.
                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 rows = this.getFilteredRows(this.rowsCache);
        this.renderKpis(rows);
        this.renderStageBars(rows);
        this.renderTable(rows);
        this.renderUpdatedAt();
    },

    getFilteredRows: function(rows) {
        var out = [];
        var search = $.trim(String(this.$widget.find("[data-role='search']").val() || "")).toLowerCase();
        var activityFilter = $.trim(String(this.$widget.find("[data-role='activityFilter']").val() || ""));

        for (var i = 0; i < (rows || []).length; i++) {
            var row = rows[i] || {};
            var activityCode = this.getActivityCode(row);

            if (activityFilter && activityCode !== activityFilter) {
                continue;
            }

            if (search) {
                var base = this.extractRow(row);
                var blob = [
                    base.processo,
                    base.solicitante,
                    base.origem,
                    base.destino,
                    base.dataAbertura,
                    base.atividadeCode
                ].join(" ").toLowerCase();

                if (blob.indexOf(search) === -1) {
                    continue;
                }
            }

            out.push(row);
        }

        return out;
    },

    renderKpis: function(rows) {
        var total = rows.length;
        var transit = this.countByActivities(rows, ["31", "57"]);
        var pendingReceipt = this.countByActivities(rows, ["18"]);
        var problem = this.countByActivities(rows, ["24", "104"]);
        var done = this.countByActivities(rows, ["96", "101"]);

        this.$widget.find("[data-role='kpiTotal']").text(this.formatNumber(total));
        this.$widget.find("[data-role='kpiTransit']").text(this.formatNumber(transit));
        this.$widget.find("[data-role='kpiPendingReceipt']").text(this.formatNumber(pendingReceipt));
        this.$widget.find("[data-role='kpiProblem']").text(this.formatNumber(problem));
        this.$widget.find("[data-role='kpiDone']").text(this.formatNumber(done));
    },

    renderStageBars: function(rows) {
        var total = rows.length;
        var html = [];

        for (var i = 0; i < this.stageDefs.length; i++) {
            var stage = this.stageDefs[i];
            var count = this.countByActivities(rows, stage.activities);
            var percent = total > 0 ? ((count * 100) / total) : 0;

            html.push(
                "<div class='wdtransf-stage-item'>" +
                    "<span class='wdtransf-stage-label'>" + this.escapeHtml(stage.label) + "</span>" +
                    "<div class='wdtransf-stage-bar-wrap'>" +
                        "<div class='wdtransf-stage-bar' style='width:" + percent.toFixed(2) + "%;'></div>" +
                    "</div>" +
                    "<span class='wdtransf-stage-value'>" + this.formatNumber(count) + "</span>" +
                "</div>"
            );
        }

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

    renderTable: function(rows) {
        var html = [];
        var totalRows = rows.length;
        var totalPages = totalRows > 0 ? Math.ceil(totalRows / this.pageSize) : 1;

        if (this.currentPage > totalPages) {
            this.currentPage = totalPages;
        }
        if (this.currentPage < 1) {
            this.currentPage = 1;
        }

        var startIndex = totalRows > 0 ? ((this.currentPage - 1) * this.pageSize) : 0;
        var endIndex = totalRows > 0 ? Math.min(startIndex + this.pageSize, totalRows) : 0;
        var pageRows = rows.slice(startIndex, endIndex);

        if (!totalRows) {
            var emptyMsg = this.isIncrementalLoading ?
                "Carregando dados..." :
                "Nenhum registro para os filtros informados.";
            html.push("<tr><td colspan='6'>" + this.escapeHtml(emptyMsg) + "</td></tr>");
            this.$widget.find("[data-role='tableBody']").html(html.join(""));
            this.renderPagination(0, 0, 0, 0);
            return;
        }

        for (var i = 0; i < pageRows.length; i++) {
            var base = this.extractRow(pageRows[i]);
            html.push(
                "<tr>" +
                    "<td>" + this.escapeHtml(base.processo) + "</td>" +
                    "<td>" + this.escapeHtml(base.solicitante) + "</td>" +
                    "<td>" + this.escapeHtml(base.origem) + "</td>" +
                    "<td>" + this.escapeHtml(base.destino) + "</td>" +
                    "<td>" + this.escapeHtml(base.dataAbertura) + "</td>" +
                    "<td>" + this.escapeHtml(base.atividadeCode) + "</td>" +
                "</tr>"
            );
        }

        this.$widget.find("[data-role='tableBody']").html(html.join(""));
        this.renderPagination(totalRows, totalPages, startIndex + 1, endIndex);
    },

    renderPagination: function(totalRows, totalPages, firstRow, lastRow) {
        var info = "Exibindo " + this.formatNumber(firstRow) + "-" + this.formatNumber(lastRow) +
            " de " + this.formatNumber(totalRows);
        if (totalRows === 0) {
            info = "Exibindo 0-0 de 0";
        }

        this.$widget.find("[data-role='pageInfo']").text(info);
        this.$widget.find("[data-role='pageStatus']").text(
            "Pagina " + this.formatNumber(this.currentPage) + " de " +
            this.formatNumber(totalPages || 1) +
            (this.isIncrementalLoading ? " (carregando...)" : "")
        );

        var disablePrev = (this.currentPage <= 1 || totalRows === 0);
        var disableNext = (this.currentPage >= (totalPages || 1) && !this.isIncrementalLoading) || totalRows === 0;
        this.$widget.find("[data-action='prevPage']").prop("disabled", disablePrev);
        this.$widget.find("[data-action='nextPage']").prop("disabled", disableNext);
    },

    setPage: function(page) {
        var n = parseInt(page, 10);
        if (isNaN(n)) return;
        if (n < 1) n = 1;
        var totalPages = Math.ceil(this.getFilteredRows(this.rowsCache).length / this.pageSize) || 1;
        if (n > totalPages) {
            if (this.isIncrementalLoading) {
                this.setMessage("Aguarde: ainda carregando mais registros...", "info");
                return;
            }
            n = totalPages;
        }
        this.currentPage = n;
        this.render();
    },

    extractRow: function(row) {
        var activityCode = this.getActivityCode(row);
        var solicitante = this.pick(row, ["requesterName"]) || "-";
        var origem = this.pick(row, ["ufOrigem"]) || "-";
        var destino = this.pick(row, ["ufDestino"]) || "-";
        return {
            processo: this.pick(row, ["WKNumProces"]) || "-",
            solicitante: solicitante,
            origem: origem,
            destino: destino,
            dataAbertura: this.formatDate(this.pick(row, ["dataAbertura"])) || "-",
            atividadeCode: activityCode || "-",
            atividadeLabel: this.getActivityLabel(activityCode)
        };
    },

    getActivityCode: function(row) {
        var raw = this.pick(row, ["Activity", "activity", "WKNumState", "state", "statusAtividade"]);
        var text = $.trim(String(raw || ""));
        if (!text) return "";
        var parsed = parseInt(text, 10);
        return isNaN(parsed) ? text : String(parsed);
    },

    getActivityLabel: function(code) {
        var map = {
            "0": "Solicitacao",
            "1": "Solicitacao",
            "4": "Aprovacao",
            "6": "Emissao NFe",
            "18": "Recebimento",
            "24": "Verificar Problema",
            "31": "Coleta",
            "39": "Cancelada",
            "57": "Entrega",
            "60": "Cancelada",
            "99": "Consultar Entrada",
            "96": "Finalizada",
            "101": "Finalizada",
            "104": "Problema de Lancamento"
        };

        return map[String(code || "")] || "Nao mapeada";
    },

    countByActivities: function(rows, activities) {
        var set = {};
        for (var i = 0; i < activities.length; i++) {
            set[String(activities[i])] = true;
        }

        var count = 0;
        for (var j = 0; j < rows.length; j++) {
            var code = this.getActivityCode(rows[j]);
            if (set[String(code)]) count++;
        }
        return count;
    },

    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 "";
    },

    formatDate: function(value) {
        var text = $.trim(String(value || ""));
        if (!text) return "";

        var iso = /^(\d{4})-(\d{2})-(\d{2})/.exec(text);
        if (iso) {
            return iso[3] + "/" + iso[2] + "/" + iso[1];
        }
        return text;
    },

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

    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;");
    }
});


