"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "surveyResponseAnswer", {
    enumerable: true,
    get: function() {
        return surveyResponseAnswer;
    }
});
const _express = /*#__PURE__*/ _interop_require_default(require("express"));
const _expressasynchandler = /*#__PURE__*/ _interop_require_default(require("express-async-handler"));
const _sequelize = require("sequelize");
const _ability = require("@casl/ability");
const _errors = require("@tamanu/errors");
const _constants = require("@tamanu/constants");
const _transformAnswers = require("@tamanu/shared/reports/utilities/transformAnswers");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
const surveyResponseAnswer = _express.default.Router();
surveyResponseAnswer.get('/latest-answer/:dataElementCode', (0, _expressasynchandler.default)(async (req, res)=>{
    const { models, query, params } = req;
    const { patientId, facilityId } = query;
    const { dataElementCode } = params;
    req.checkPermission('read', 'SurveyResponse');
    const answer = await models.SurveyResponseAnswer.findOne({
        include: [
            {
                model: models.SurveyResponse,
                as: 'surveyResponse',
                required: true,
                include: [
                    {
                        model: models.Encounter,
                        as: 'encounter',
                        where: {
                            patientId
                        }
                    }
                ]
            },
            {
                model: models.ProgramDataElement,
                where: {
                    code: dataElementCode
                },
                include: [
                    {
                        model: models.SurveyScreenComponent,
                        as: 'surveyScreenComponent',
                        include: models.SurveyScreenComponent.getListReferenceAssociations(true)
                    }
                ]
            }
        ],
        order: [
            [
                'surveyResponse',
                'startTime',
                'DESC'
            ]
        ]
    });
    if (!answer) {
        throw new _errors.NotFoundError('No answer found');
    }
    const transformedAnswers = await (0, _transformAnswers.transformAnswers)(models, [
        answer
    ], [
        answer.ProgramDataElement.surveyScreenComponent
    ], {
        notTransformDate: true
    });
    answer.dataValues.displayAnswer = transformedAnswers[0]?.body;
    await req.audit.access({
        recordId: answer.id,
        frontEndContext: params,
        model: models.SurveyResponseAnswer,
        facilityId
    });
    res.send(answer);
}));
async function putSurveyResponseAnswer(req, isVital = false) {
    const { db, models, user, params, body } = req;
    const { SurveyResponseAnswer, SurveyResponse, Survey, VitalLog, ProgramDataElement } = models;
    const { id } = params;
    const surveyWhereClause = isVital ? {
        surveyType: _constants.SURVEY_TYPES.VITALS
    } : {
        id: body.surveyId
    };
    const answerObject = await SurveyResponseAnswer.findByPk(id, {
        include: [
            {
                required: true,
                model: SurveyResponse,
                as: 'surveyResponse',
                include: [
                    {
                        required: true,
                        model: Survey,
                        as: 'survey',
                        where: surveyWhereClause
                    }
                ]
            },
            {
                required: true,
                model: ProgramDataElement,
                where: {
                    type: {
                        [_sequelize.Op.not]: _constants.PROGRAM_DATA_ELEMENT_TYPES.CALCULATED
                    }
                }
            }
        ]
    });
    if (!answerObject) throw new _errors.NotFoundError();
    if (answerObject.body === body.newValue) {
        throw new _errors.InvalidParameterError('New value is the same as previous value.');
    }
    await db.transaction(async ()=>{
        const { newValue = '', reasonForChange, date } = body;
        if (isVital) {
            const previousValue = answerObject.body;
            await answerObject.update({
                body: newValue
            });
            await VitalLog.create({
                date,
                reasonForChange,
                previousValue,
                newValue,
                recordedById: user.id,
                answerId: id
            });
        } else {
            await answerObject.updateWithReasonForChange(newValue, reasonForChange);
        }
        await answerObject.upsertCalculatedQuestions({
            date,
            reasonForChange,
            user,
            isVital
        });
    });
    return answerObject;
}
async function postSurveyResponseAnswer(req, isVital = false) {
    const { db, models, user, body } = req;
    const { SurveyResponseAnswer, SurveyResponse, Survey, VitalLog, ProgramDataElement } = models;
    // Ensure data element exists and it's not a calculated question
    const dataElement = await ProgramDataElement.findOne({
        where: {
            id: body.dataElementId
        }
    });
    if (!dataElement || dataElement.type === _constants.PROGRAM_DATA_ELEMENT_TYPES.CALCULATED) {
        throw new _errors.InvalidOperationError('Invalid data element.');
    }
    const surveyWhereClause = isVital ? {
        surveyType: _constants.SURVEY_TYPES.VITALS
    } : {
        id: body.surveyId
    };
    const dateDataElementId = isVital ? _constants.VITALS_DATA_ELEMENT_IDS.dateRecorded : _constants.CHARTING_DATA_ELEMENT_IDS.dateRecorded;
    const responseObject = await SurveyResponse.findAll({
        where: {
            encounterId: body.encounterId
        },
        include: [
            {
                required: true,
                model: Survey,
                as: 'survey',
                where: surveyWhereClause
            },
            {
                required: true,
                model: SurveyResponseAnswer,
                as: 'answers',
                where: {
                    body: body.recordedDate,
                    dataElementId: dateDataElementId
                }
            }
        ]
    });
    // Can't do magic here, it's impossible to tell where
    // it should be created without guessing.
    if (responseObject.length !== 1) {
        throw new _errors.InvalidOperationError('Unable to complete action, please contact support.');
    }
    let newAnswer;
    await db.transaction(async ()=>{
        const { newValue = '', reasonForChange, date, dataElementId } = body;
        newAnswer = await models.SurveyResponseAnswer.create({
            dataElementId,
            body: newValue,
            responseId: responseObject[0].id
        });
        if (isVital) {
            await VitalLog.create({
                date,
                reasonForChange,
                newValue,
                recordedById: user.id,
                answerId: newAnswer.id
            });
        }
        await newAnswer.upsertCalculatedQuestions({
            date,
            reasonForChange,
            user,
            isVital
        });
    });
    return newAnswer;
}
surveyResponseAnswer.put('/vital/:id', (0, _expressasynchandler.default)(async (req, res)=>{
    const { settings, body: { facilityId } } = req;
    req.checkPermission('write', 'Vitals');
    const enableVitalEdit = await settings[facilityId].get(_constants.SETTING_KEYS.FEATURES_ENABLE_VITAL_EDIT);
    if (!enableVitalEdit) {
        throw new _errors.InvalidOperationError('Editing vitals is disabled.');
    }
    const answerObject = await putSurveyResponseAnswer(req, true);
    res.send(answerObject);
}));
surveyResponseAnswer.post('/vital', (0, _expressasynchandler.default)(async (req, res)=>{
    const { settings, body: { facilityId } } = req;
    req.checkPermission('create', 'Vitals');
    // Even though this wouldn't technically be editing a vital
    // we will not allow the creation of a single vital answer if its not enabled
    const enableVitalEdit = await settings[facilityId].get(_constants.SETTING_KEYS.FEATURES_ENABLE_VITAL_EDIT);
    if (!enableVitalEdit) {
        throw new _errors.InvalidOperationError('Editing vitals is disabled.');
    }
    const newAnswer = await postSurveyResponseAnswer(req, true);
    res.send(newAnswer);
}));
surveyResponseAnswer.put('/chart/:id', (0, _expressasynchandler.default)(async (req, res)=>{
    const { settings, body: { facilityId, surveyId } } = req;
    req.checkPermission('write', (0, _ability.subject)('Charting', {
        id: surveyId
    }));
    const enableChartEdit = await settings[facilityId].get(_constants.SETTING_KEYS.FEATURES_ENABLE_CHARTING_EDIT);
    if (!enableChartEdit) {
        throw new _errors.InvalidOperationError('Editing charts is disabled.');
    }
    const answerObject = await putSurveyResponseAnswer(req);
    res.send(answerObject);
}));
surveyResponseAnswer.post('/chart', (0, _expressasynchandler.default)(async (req, res)=>{
    const { settings, body: { facilityId, surveyId } } = req;
    req.checkPermission('create', (0, _ability.subject)('Charting', {
        id: surveyId
    }));
    // Even though this wouldn't technically be editing a chart
    // we will not allow the creation of a single chart answer if its not enabled
    const enableChartEdit = await settings[facilityId].get(_constants.SETTING_KEYS.FEATURES_ENABLE_CHARTING_EDIT);
    if (!enableChartEdit) {
        throw new _errors.InvalidOperationError('Editing charts is disabled.');
    }
    const newAnswer = await postSurveyResponseAnswer(req);
    res.send(newAnswer);
}));
surveyResponseAnswer.put('/photo/:id', (0, _expressasynchandler.default)(async (req, res)=>{
    const { db, models, params } = req;
    const { SurveyResponseAnswer, Attachment } = models;
    const { id } = params;
    // Find answer
    const answerObject = await SurveyResponseAnswer.findByPk(id, {
        include: [
            {
                // Ensure answer is photo type
                required: true,
                model: models.ProgramDataElement,
                where: {
                    type: _constants.PROGRAM_DATA_ELEMENT_TYPES.PHOTO
                }
            },
            {
                required: true,
                model: models.SurveyResponse,
                as: 'surveyResponse'
            }
        ]
    });
    if (!answerObject) {
        throw new _errors.InvalidParameterError('Invalid answer ID.');
    }
    req.checkPermission('delete', (0, _ability.subject)('Charting', {
        id: answerObject.surveyResponse.surveyId
    }));
    await db.transaction(async ()=>{
        // Blank out the attachment. We need to upsert because the record
        // might not exist on facility server.
        await Attachment.upsert({
            id: answerObject.body,
            data: Buffer.from([]),
            type: 'image/jpeg',
            size: 0
        });
        // Update answer to empty string (needed for logs and table display)
        await answerObject.update({
            body: ''
        });
    });
    res.send(answerObject);
}));

//# sourceMappingURL=surveyResponseAnswer.js.map