function createDataset(fields, constraints, sortFields) {
    var dataset = DatasetBuilder.newDataset();

    dataset.addColumn("PDV");
    dataset.addColumn("LOJA");
    dataset.addColumn("RESPONSAVEL_LOJA");
    dataset.addColumn("REGIONAL");
    dataset.addColumn("UF");
    dataset.addColumn("CIDADE");
    dataset.addColumn("STATUS");
    dataset.addColumn("CANAL");
    dataset.addColumn("ID");
    dataset.addColumn("PROTHEUS");
    dataset.addColumn("LOGIN_LOJA");
    dataset.addColumn("COLLEAGUE_ID");
    dataset.addColumn("USER_CREATE");

    try {
        var clientService = fluigAPI.getAuthorizeClientService();
        var data = {
            companyId: String(getValue("WKCompany") || "1"),
            serviceCode: "GINSENG API", // ajuste para o codigo do servico cadastrado no Fluig
            endpoint: "/base_pdvs",
            method: "get",
            timeoutService: "60000",
            params: {}
        };

        var vo = clientService.invoke(JSON.stringify(data));
        var statusHttp = vo ? String(vo.getHttpStatusResult() || "") : "";
        var retorno = vo ? String(vo.getResult() || "") : "";

        if (!retorno) {
            dataset.addRow(["", "Sem resposta da API (HTTP " + statusHttp + ")", "", "", "", "", "", "", "", "", "", "", ""]);
            return dataset;
        }

        var objData = JSON.parse(retorno);
        var success = !!objData.success;
        var itens = objData.data || [];

        if (!success || !itens.length) {
            var msg = trim(objData.message) || trim(objData.error) || "Sem lojas retornadas";
            dataset.addRow(["", msg + " (HTTP " + statusHttp + ")", "", "", "", "", "", "", "", "", "", "", ""]);
            return dataset;
        }

        var filtros = parseConstraints(constraints);
        var colleagueCache = {};

        for (var i = 0; i < itens.length; i++) {
            var item = itens[i] || {};

            var pdv = trim(item["PDV"]);
            var loja = trim(item["PDV DESC"]);
            var responsavel = trim(item["GESTAO"]) || trim(item["GESTAO"]);
            var regional = trim(item["SUPERVISOR"]) || trim(item["SUPERVISOR"]);
            var uf = trim(item["UF"]);
            var cidade = trim(item["CIDADE"]);
            var status = trim(item["STATUS"]);
            var canal = trim(item["CANAL"]);
            var id = trim(item["id"]);
            var protheus = trim(item["PROTHEUS"] || item["protheus"] || item["Protheus"]);
            var loginLoja = pdv ? (pdv + ".ginseng") : "";
            var colleagueId = resolveColleagueIdByLogin(loginLoja);
            var userCreate = getUserCreateStatus(loginLoja, colleagueCache);

            if (filtros.onlyAtivo && status.toUpperCase() !== "ATIVO") {
                continue;
            }
            if (filtros.pdv && pdv !== filtros.pdv) {
                continue;
            }
            if (filtros.loja && normalize(loja).indexOf(normalize(filtros.loja)) === -1) {
                continue;
            }
            if (filtros.termoLivre) {
                var blob = normalize([
                    pdv,
                    loja,
                    responsavel,
                    regional,
                    uf,
                    cidade
                ].join(" "));
                if (blob.indexOf(normalize(filtros.termoLivre)) === -1) {
                    continue;
                }
            }

            dataset.addRow([
                pdv,
                loja,
                responsavel,
                regional,
                uf,
                cidade,
                status,
                canal,
                id,
                protheus,
                loginLoja,
                colleagueId,
                userCreate
            ]);
        }

        if (dataset.rowsCount === 0) {
            dataset.addRow(["", "Sem lojas apos filtros (HTTP " + statusHttp + ")", "", "", "", "", "", "", "", "", "", "", ""]);
        }

    } catch (e) {
        dataset = DatasetBuilder.newDataset();
        dataset.addColumn("ERRO");
        dataset.addRow([String(e)]);
    }

    return dataset;
}

function parseConstraints(constraints) {
    var out = {
        pdv: "",
        loja: "",
        onlyAtivo: false,
        termoLivre: ""
    };

    if (!constraints) return out;

    for (var i = 0; i < constraints.length; i++) {
        var c = constraints[i];
        if (!c || !c.fieldName) continue;

        var name = String(c.fieldName);
        var value = trim(c.initialValue);

        if (name === "PDV" && value) out.pdv = value;
        if (name === "LOJA" && value) out.loja = value;
        if (name === "onlyAtivo" && value.toLowerCase() === "false") out.onlyAtivo = false;

        // Zoom costuma enviar constraints variadas de busca; capturamos termo livre.
        if (
            value &&
            name !== "onlyAtivo" &&
            name !== "metadata#id" &&
            name !== "metadata#active" &&
            name !== "sqlLimit"
        ) {
            var cleaned = cleanSearchValue(value);
            if (cleaned && (!out.termoLivre || cleaned.length > out.termoLivre.length)) {
                out.termoLivre = cleaned;
            }
        }
    }

    return out;
}

function trim(v) {
    return String(v == null ? "" : v).trim();
}

function normalize(v) {
    return trim(v).toLowerCase();
}

function cleanSearchValue(v) {
    var s = trim(v);
    // remove curingas comuns de busca do Zoom/like
    s = s.replace(/[%*_]/g, "");
    return trim(s);
}

function getUserCreateStatus(loginLoja, cache) {
    var login = trim(loginLoja);
    if (!login) return "NAO";
    if (cache.hasOwnProperty(login)) return cache[login];
    try {
        var cLogin = DatasetFactory.createConstraint("login", login, login, ConstraintType.MUST);
        var cActive = DatasetFactory.createConstraint("active", "true", "true", ConstraintType.MUST);
        var ds = DatasetFactory.getDataset("colleague", null, [cLogin, cActive], null);
        var exists = !!(ds && ds.rowsCount > 0);

        // fallback para ambientes onde o identificador esta em colleagueId
        if (!exists) {
            var cId = DatasetFactory.createConstraint("colleaguePK.colleagueId", login, login, ConstraintType.MUST);
            ds = DatasetFactory.getDataset("colleague", null, [cId, cActive], null);
            exists = !!(ds && ds.rowsCount > 0);
        }

        cache[login] = exists ? "OK" : "NAO";
        return cache[login];
    } catch (e) {
        cache[login] = "NAO";
        return "NAO";
    }
}

function resolveColleagueIdByLogin(loginLoja) {
    var login = trim(loginLoja);
    if (!login) return "";
    try {
        var cLogin = DatasetFactory.createConstraint("login", login, login, ConstraintType.MUST);
        var cActive = DatasetFactory.createConstraint("active", "true", "true", ConstraintType.MUST);
        var ds = DatasetFactory.getDataset("colleague", null, [cLogin, cActive], null);
        if (ds && ds.rowsCount > 0) {
            return trim(ds.getValue(0, "colleaguePK.colleagueId"));
        }
    } catch (e) {}
    return "";
}
