"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get COLUMNS_TO_DATA_ELEMENT_ID () {
        return COLUMNS_TO_DATA_ELEMENT_ID;
    },
    get migrateVitals () {
        return migrateVitals;
    },
    get migrateVitalsCommand () {
        return migrateVitalsCommand;
    }
});
const _commander = require("commander");
const _sequelize = require("sequelize");
const _constants = require("@tamanu/constants");
const _logging = require("@tamanu/shared/services/logging");
const _config = /*#__PURE__*/ _interop_require_default(require("config"));
const _crypto = /*#__PURE__*/ _interop_require_default(require("crypto"));
const _database = require("../../database");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
const BATCH_COUNT = 100;
const COLUMNS_TO_DATA_ELEMENT_ID = {
    dateRecorded: 'pde-PatientVitalsDate',
    temperature: 'pde-PatientVitalsTemperature',
    weight: 'pde-PatientVitalsWeight',
    height: 'pde-PatientVitalsHeight',
    sbp: 'pde-PatientVitalsSBP',
    dbp: 'pde-PatientVitalsDBP',
    heartRate: 'pde-PatientVitalsHeartRate',
    respiratoryRate: 'pde-PatientVitalsRespiratoryRate',
    spo2: 'pde-PatientVitalsSPO2',
    avpu: 'pde-PatientVitalsAVPU'
};
const conversionFunctions = {
    temperature: (value)=>{
        if (value && _config.default.localisation.data.units.temperature === 'fahrenheit') {
            // Do this the hard way so we don't need to add a conversion lib to central
            return (value * (9 / 5) + 32).toFixed(1);
        }
        return value;
    }
};
async function migrateVitals() {
    const store = await (0, _database.initDatabase)({
        testMode: false
    });
    const { models, sequelize } = store;
    const vitalsSurvey = await models.Survey.findOne({
        where: {
            surveyType: _constants.SURVEY_TYPES.VITALS
        }
    });
    if (!vitalsSurvey) {
        _logging.log.error('Vitals migration failed: no vitals survey found');
        process.exit(1);
    }
    let toProcess = await models.Vitals.count({
        where: {
            migrated_record: null
        }
    });
    _logging.log.info(`Found ${toProcess} vitals records to migrate`);
    while(toProcess > 0){
        // Slightly inaccurate, but editing the loop var inside the transaction callback is unsafe
        toProcess -= BATCH_COUNT;
        _logging.log.debug('Starting transaction');
        await sequelize.transaction({
            // strongest level to be sure to read/write good data
            isolationLevel: _sequelize.Sequelize.Transaction.ISOLATION_LEVELS.REPEATABLE_READ
        }, async ()=>{
            const vitalsChunk = await models.Vitals.findAll({
                where: {
                    migrated_record: null
                },
                limit: BATCH_COUNT
            });
            _logging.log.info(`Processing batch of ${vitalsChunk.length} vitals records`);
            // Map the new ids so we can look them up when generating the answer records
            const idMap = new Map(vitalsChunk.map((vital)=>[
                    vital.dataValues.id,
                    _crypto.default.randomUUID()
                ]));
            const newResponses = vitalsChunk.map((vital)=>({
                    id: idMap.get(vital.dataValues.id),
                    encounterId: vital.dataValues.encounterId,
                    updatedAt: vital.dataValues.updatedAt,
                    createdAt: vital.dataValues.createdAt,
                    startTime: vital.dataValues.dateRecorded,
                    endTime: vital.dataValues.dateRecorded,
                    surveyId: vitalsSurvey.dataValues.id
                }));
            await models.SurveyResponse.bulkCreate(newResponses);
            // Each survey response generates many answer, map them to an array of arrays then flatten
            const answerData = vitalsChunk.map((vital)=>Object.entries(vital.dataValues).filter(([key, value])=>value && COLUMNS_TO_DATA_ELEMENT_ID[key]).map(([key, value])=>({
                        dataElementId: COLUMNS_TO_DATA_ELEMENT_ID[key],
                        responseId: idMap.get(vital.dataValues.id),
                        body: conversionFunctions[key] ? conversionFunctions[key](value) : value
                    })));
            await models.SurveyResponseAnswer.bulkCreate(answerData.flat());
            // models.Vitals.update will error if you don't update the encounterId because the validation triggers against the updated field list
            await sequelize.query(`
          UPDATE vitals SET migrated_record = response_id
          FROM (SELECT unnest(ARRAY[:keys]) AS vital_id,
                unnest(ARRAY[:values]) AS response_id) map
          WHERE map.vital_id = vitals.id
        `, {
                replacements: {
                    keys: [
                        ...idMap.keys()
                    ],
                    values: [
                        ...idMap.values()
                    ]
                }
            });
        });
    }
}
const migrateVitalsCommand = new _commander.Command('migrateVitals').description('Migrates vitals from legacy format to new format as survey responses').action(migrateVitals);

//# sourceMappingURL=index.js.map