"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "reportsRouter", {
    enumerable: true,
    get: function() {
        return reportsRouter;
    }
});
const _express = /*#__PURE__*/ _interop_require_default(require("express"));
const _config = /*#__PURE__*/ _interop_require_default(require("config"));
const _fs = require("fs");
const _expressasynchandler = /*#__PURE__*/ _interop_require_default(require("express-async-handler"));
const _sequelize = require("sequelize");
const _getUploadedData = require("@tamanu/shared/utils/getUploadedData");
const _errors = require("@tamanu/errors");
const _lodash = require("lodash");
const _constants = require("@tamanu/constants");
const _utils = require("./utils");
const _createReportDefinitionVersion = require("./createReportDefinitionVersion");
const _errors1 = require("../errors");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
const reportsRouter = _express.default.Router();
reportsRouter.get('/', (0, _expressasynchandler.default)(async (req, res)=>{
    const { store } = req;
    req.checkPermission('read', 'ReportDefinition');
    req.checkPermission('read', 'ReportDefinitionVersion');
    const canEditSchema = req.ability.can('write', 'ReportDbSchema');
    const isReportingSchemaEnabled = _config.default.db.reportSchemas.enabled;
    const result = await store.sequelize.query(`SELECT rd.id,
        rd.name,
        rd.created_at AS "createdAt",
        rd.db_schema AS "dbSchema",
        max(rdv.updated_at) AS "lastUpdated",
        max(rdv.version_number) AS "versionCount"
    FROM report_definitions rd
        LEFT JOIN report_definition_versions rdv ON rd.id = rdv.report_definition_id
          AND rdv.deleted_at IS NULL
    WHERE rd.deleted_at IS NULL
    ${isReportingSchemaEnabled && !canEditSchema ? `AND rd.db_schema = '${_constants.REPORT_DB_CONNECTIONS.REPORTING}'` : ''}
    GROUP BY rd.id
    HAVING max(rdv.version_number) > 0
    ORDER BY rd.name
        `, {
        type: _sequelize.QueryTypes.SELECT
    });
    res.send(result);
}));
reportsRouter.get('/:reportId/versions', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('read', 'ReportDefinition');
    req.checkPermission('read', 'ReportDefinitionVersion');
    const { store, params } = req;
    const { models: { ReportDefinitionVersion } } = store;
    const { reportId } = params;
    const versions = await ReportDefinitionVersion.findAll({
        where: {
            reportDefinitionId: reportId
        },
        attributes: [
            'id',
            'versionNumber',
            'query',
            'createdAt',
            'updatedAt',
            'status',
            'notes',
            'queryOptions',
            [
                store.sequelize.literal(`version_number = (
            SELECT MAX(version_number)
            FROM report_definition_versions AS rdv
            WHERE rdv.report_definition_id = "ReportDefinitionVersion".report_definition_id
            AND rdv.status = '${_constants.REPORT_STATUSES.PUBLISHED}'
          )`),
                'active'
            ]
        ],
        order: [
            [
                'versionNumber',
                'DESC'
            ]
        ],
        include: [
            {
                model: store.models.User,
                as: 'createdBy',
                attributes: [
                    'displayName'
                ]
            }
        ]
    });
    res.send(versions);
}));
reportsRouter.post('/', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('create', 'ReportDefinition');
    req.checkPermission('create', 'ReportDefinitionVersion');
    const { store, body, user, reportSchemaStores } = req;
    const isReportingSchemaEnabled = _config.default.db.reportSchemas.enabled;
    const defaultReportingSchema = isReportingSchemaEnabled ? _constants.REPORT_DB_CONNECTIONS.REPORTING : _constants.REPORT_DB_CONNECTIONS.RAW;
    const transformedBody = !body.dbSchema ? {
        ...body,
        dbSchema: defaultReportingSchema
    } : body;
    const version = await (0, _createReportDefinitionVersion.createReportDefinitionVersion)({
        store,
        reportSchemaStores
    }, null, transformedBody, user.id);
    res.send(version);
}));
reportsRouter.post('/:reportId/versions', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('create', 'ReportDefinition');
    req.checkPermission('create', 'ReportDefinitionVersion');
    const { store, params, body, user, reportSchemaStores } = req;
    const { reportId } = params;
    const version = await (0, _createReportDefinitionVersion.createReportDefinitionVersion)({
        store,
        reportSchemaStores
    }, reportId, body, user.id);
    res.send(version);
}));
reportsRouter.get('/:reportId/versions/:versionId/export/:format', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('read', 'ReportDefinition');
    req.checkPermission('read', 'ReportDefinitionVersion');
    const { store, params } = req;
    const { ReportDefinition, ReportDefinitionVersion } = store.models;
    const { reportId, versionId, format } = params;
    const reportDefinition = await ReportDefinition.findOne({
        where: {
            id: reportId
        },
        include: [
            {
                model: ReportDefinitionVersion,
                as: 'versions',
                where: {
                    id: versionId
                }
            }
        ]
    });
    if (!reportDefinition) {
        throw new _errors.NotFoundError(`No report found with id ${reportId}`);
    }
    const version = reportDefinition.versions[0];
    if (!version) {
        throw new _errors.NotFoundError(`No version found with id ${versionId}`);
    }
    const versionWithoutMetadata = {
        ...version.forResponse(true),
        dbSchema: reportDefinition.dbSchema
    };
    const filename = (0, _utils.sanitizeFilename)(reportDefinition.name, versionWithoutMetadata.versionNumber, format);
    let data;
    if (format === _constants.REPORT_VERSION_EXPORT_FORMATS.JSON) {
        data = JSON.stringify(versionWithoutMetadata, null, 2);
    } else if (format === _constants.REPORT_VERSION_EXPORT_FORMATS.SQL) {
        data = versionWithoutMetadata.query;
    }
    res.send({
        filename,
        data
    });
}));
reportsRouter.post('/import', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('create', 'ReportDefinition');
    req.checkPermission('create', 'ReportDefinitionVersion');
    const { store, user, reportSchemaStores } = req;
    const { models: { ReportDefinition, ReportDefinitionVersion }, sequelize } = store;
    const { reportSchemas } = _config.default.db;
    const canEditSchema = req.ability.can('write', 'ReportDbSchema');
    const { name, file, dryRun, deleteFileAfterImport = true } = await (0, _getUploadedData.getUploadedData)(req);
    const versionData = await (0, _utils.readJSON)(file);
    if (versionData.versionNumber) throw new _errors.InvalidOperationError('Cannot import a report with a version number');
    if (reportSchemas.enabled && !canEditSchema && versionData.dbSchema === _constants.REPORT_DB_CONNECTIONS.RAW) {
        throw new _errors.InvalidOperationError('You do not have permission to import reports using the raw schema');
    }
    const existingDefinition = await ReportDefinition.findOne({
        where: {
            name
        }
    });
    if (existingDefinition && existingDefinition.dbSchema !== versionData.dbSchema) {
        throw new _errors.InvalidOperationError('Cannot change a reporting schema for existing report');
    }
    await (0, _utils.verifyQuery)(versionData.query, versionData.queryOptions, {
        store,
        reportSchemaStores
    }, versionData.dbSchema);
    const feedback = {};
    try {
        await sequelize.transaction({
            // Prevents race condition when determining the next version number
            isolationLevel: _sequelize.Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE
        }, async ()=>{
            const [definition, createdDefinition] = await ReportDefinition.findOrCreate({
                where: {
                    name,
                    dbSchema: reportSchemas.enabled ? versionData.dbSchema : _constants.REPORT_DB_CONNECTIONS.RAW
                },
                include: [
                    {
                        model: ReportDefinitionVersion,
                        as: 'versions',
                        attributes: [
                            'versionNumber'
                        ],
                        order: [
                            [
                                'versionNumber',
                                'DESC'
                            ]
                        ],
                        limit: 1
                    }
                ]
            });
            const versionNumber = createdDefinition ? 1 : (definition.versions?.[0]?.versionNumber || 0) + 1;
            await ReportDefinitionVersion.create({
                ...versionData,
                userId: user.id,
                versionNumber,
                reportDefinitionId: definition.id
            });
            feedback.createdDefinition = createdDefinition;
            feedback.versionNumber = versionNumber;
            if (dryRun) {
                throw new _errors1.DryRun();
            }
            feedback.reportDefinitionId = definition.id;
        });
    } catch (err) {
        if (!(err instanceof _errors1.DryRun)) {
            throw err;
        }
    }
    if (deleteFileAfterImport) {
        // eslint-disable-next-line no-unused-vars
        await _fs.promises.unlink(file).catch((ignore)=>{});
    }
    res.send(feedback);
}));
reportsRouter.get('/:reportId/versions/:versionId', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('read', 'ReportDefinition');
    req.checkPermission('read', 'ReportDefinitionVersion');
    const { store, params, models: { ReportDefinitionVersion } } = req;
    const { reportId, versionId } = params;
    const version = await ReportDefinitionVersion.findOne({
        where: {
            id: versionId,
            reportDefinitionId: reportId
        },
        include: [
            {
                model: store.models.User,
                as: 'createdBy',
                attributes: [
                    'displayName'
                ]
            },
            {
                model: store.models.ReportDefinition,
                as: 'reportDefinition',
                attributes: [
                    'name',
                    'id',
                    'dbSchema'
                ]
            }
        ]
    });
    res.send(version);
}));
reportsRouter.get('/dbSchemaOptions', (0, _expressasynchandler.default)(async (req, res)=>{
    req.flagPermissionChecked();
    if (!_config.default.db.reportSchemas.enabled) return res.send([]);
    const DB_SCHEMA_OPTIONS = Object.values(_constants.REPORT_DB_CONNECTIONS).map((value)=>({
            label: (0, _lodash.capitalize)(value),
            value
        }));
    return res.send(DB_SCHEMA_OPTIONS);
}));

//# sourceMappingURL=reportRoutes.js.map