"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "ReportDefinitionVersion", {
    enumerable: true,
    get: function() {
        return ReportDefinitionVersion;
    }
});
const _sequelize = require("sequelize");
const _yup = /*#__PURE__*/ _interop_require_wildcard(require("yup"));
const _constants = require("@tamanu/constants");
const _getReportQueryReplacements = require("@tamanu/shared/utils/reports/getReportQueryReplacements");
const _Model = require("./Model");
function _getRequireWildcardCache(nodeInterop) {
    if (typeof WeakMap !== "function") return null;
    var cacheBabelInterop = new WeakMap();
    var cacheNodeInterop = new WeakMap();
    return (_getRequireWildcardCache = function(nodeInterop) {
        return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
    })(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
    if (!nodeInterop && obj && obj.__esModule) {
        return obj;
    }
    if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
        return {
            default: obj
        };
    }
    var cache = _getRequireWildcardCache(nodeInterop);
    if (cache && cache.has(obj)) {
        return cache.get(obj);
    }
    var newObj = {
        __proto__: null
    };
    var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
    for(var key in obj){
        if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
            var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
            if (desc && (desc.get || desc.set)) {
                Object.defineProperty(newObj, key, desc);
            } else {
                newObj[key] = obj[key];
            }
        }
    }
    newObj.default = obj;
    if (cache) {
        cache.set(obj, newObj);
    }
    return newObj;
}
const optionsValidator = _yup.object({
    parameters: _yup.array().required().of(_yup.object({
        parameterField: _yup.string().required(),
        name: _yup.string().required()
    })),
    dataSources: _yup.array(),
    dateRangeLabel: _yup.string(),
    defaultDateRange: _yup.string().oneOf(_constants.REPORT_DEFAULT_DATE_RANGES_VALUES).required()
});
const generateReportFromQueryData = (queryData)=>{
    if (queryData.length === 0) {
        return [];
    }
    return [
        Object.keys(queryData[0]),
        ...queryData.map(Object.values)
    ];
};
let ReportDefinitionVersion = class ReportDefinitionVersion extends _Model.Model {
    static initModel({ primaryKey, ...options }) {
        super.init({
            id: primaryKey,
            versionNumber: {
                type: _sequelize.DataTypes.INTEGER,
                allowNull: false
            },
            notes: {
                // Justify changes, link to card requesting changes, etc.
                type: _sequelize.DataTypes.STRING,
                allowNull: true
            },
            status: {
                type: _sequelize.DataTypes.STRING,
                defaultValue: _constants.REPORT_STATUSES.DRAFT,
                validate: {
                    isIn: [
                        _constants.REPORT_STATUSES_VALUES
                    ]
                }
            },
            query: {
                // SQL query
                type: _sequelize.DataTypes.TEXT,
                allowNull: false
            },
            queryOptions: {
                /**
           * See optionsValidator for exact schema
           * e.g.
           * {
           *   "parameters": [
           *     { "parameterField": "VillageField" },
           *     {
           *       "parameterField": "ParameterAutocompleteField",
           *       "label": "Nursing Zone",
           *       "name": "nursingZone",
           *       "suggesterEndpoint": "nursingZone"
           *     }
           *   ],
           *   "dataSources": [],
           * }
           */ type: _sequelize.DataTypes.JSON,
                allowNull: false,
                validate: {
                    matchesSchema: (value)=>optionsValidator.validate(value)
                }
            }
        }, {
            ...options,
            syncDirection: _constants.SYNC_DIRECTIONS.BIDIRECTIONAL
        });
    }
    static initRelations(models) {
        this.belongsTo(models.ReportDefinition, {
            foreignKey: 'reportDefinitionId',
            as: 'reportDefinition'
        });
        this.belongsTo(models.User, {
            foreignKey: {
                name: 'userId',
                allowNull: false
            },
            as: 'createdBy'
        });
        this.hasMany(models.ReportRequest);
    }
    getQueryOptions() {
        // Make sure that query options is being returned as an object. It seems to come back sometimes
        // as a string and sometimes as an object otherwise.
        return typeof this.queryOptions === 'string' ? JSON.parse(this.queryOptions) : this.queryOptions;
    }
    getParameters() {
        const options = this.getQueryOptions();
        return options.parameters;
    }
    async dataGenerator({ sequelize, reportSchemaStores, facilityId }, parameters) {
        const reportQuery = this.get('query');
        const queryOptions = this.getQueryOptions();
        const replacements = await (0, _getReportQueryReplacements.getReportQueryReplacements)(queryOptions.parameters, facilityId, parameters, queryOptions.defaultDateRange);
        const definition = await this.getReportDefinition();
        const instance = reportSchemaStores ? reportSchemaStores[definition.dbSchema]?.sequelize : sequelize;
        if (!instance) {
            throw new Error(`No reporting instance found for ${definition.dbSchema}`);
        }
        const queryResults = await instance.query(reportQuery, {
            type: _sequelize.QueryTypes.SELECT,
            replacements
        });
        return generateReportFromQueryData(queryResults);
    }
    forResponse(includeRelationIds = false) {
        const { reportDefinitionId, userId, ...rest } = this.get();
        delete rest.updatedAtSyncTick;
        delete rest.ReportDefinitionId;
        return {
            ...rest,
            ...includeRelationIds && {
                reportDefinitionId,
                userId
            }
        };
    }
    static buildSyncFilter() {
        return null; // syncs everywhere
    }
    static async buildSyncLookupQueryDetails() {
        return null; // syncs everywhere
    }
};

//# sourceMappingURL=ReportDefinitionVersion.js.map