"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 getAnswerBody () {
        return getAnswerBody;
    },
    get getPatientDataFieldAssociationData () {
        return getPatientDataFieldAssociationData;
    },
    get takeMostRecentAnswers () {
        return takeMostRecentAnswers;
    },
    get transformAnswers () {
        return transformAnswers;
    }
});
const _datefns = require("date-fns");
const _lodash = require("lodash");
const _constants = require("@tamanu/constants");
const _criteria = require("@tamanu/utils/criteria");
const _dateTime = require("@tamanu/utils/dateTime");
// also update getDisplayNameForModel in /packages/mobile/App/ui/helpers/fields.ts when this changes
function getDisplayNameForModel(modelName, record) {
    let result = '';
    switch(modelName){
        case 'User':
            result = record['displayName'];
            break;
        case 'Patient':
            // follow the same format as the patient label in usePatientSuggester
            result = `${[
                record.firstName,
                record.lastName
            ].filter(Boolean).join(' ')} (${record.displayId}) - ${record.sex} - ${record.dateOfBirth ? (0, _dateTime.formatShort)((0, _dateTime.parseDate)(record.dateOfBirth)) : ''}`;
            break;
        default:
            result = record?.['name'];
            break;
    }
    return result || record.id;
}
const convertAutocompleteAnswer = async (models, componentConfig, answer)=>{
    if (!componentConfig) {
        return answer;
    }
    const model = models[componentConfig.source];
    if (!model) {
        throw new Error(`no model for componentConfig ${JSON.stringify(componentConfig)}`);
    }
    const result = await model.findByPk(answer);
    if (!result) {
        if (answer === '') {
            return answer;
        }
        if (componentConfig.source === 'ReferenceData') {
            throw new Error(`Selected answer ${componentConfig.source}[${answer}] not found (check that the surveyquestion's source isn't ReferenceData for a Location, Facility, or Department)`);
        }
        throw new Error(`Selected answer ${componentConfig.source}[${answer}] not found`);
    }
    return getDisplayNameForModel(componentConfig.source, result);
};
const convertDateAnswer = (answer, { dateFormat = 'dd-MM-yyyy', notTransformDate = false })=>{
    if (notTransformDate) return answer;
    if ((0, _dateTime.isISOString)(answer)) {
        return (0, _dateTime.format)(answer, dateFormat);
    }
    return '';
};
const getPatientDataFieldAssociationData = async ({ models, modelName, fieldName, answer })=>{
    const model = models[modelName];
    const associations = Object.values(model.associations || {});
    const foreignKeyAssociation = associations.find((association)=>association.foreignKey === fieldName);
    if (!foreignKeyAssociation) return {
        data: answer,
        targetModel: null
    };
    const targetModel = foreignKeyAssociation.target.name;
    const result = await models[targetModel].findOne({
        where: {
            id: answer
        }
    });
    return {
        data: result,
        targetModel
    };
};
const convertPatientDataAnswer = async (models, componentConfig, answer)=>{
    const [modelName, fieldName, options] = _constants.PATIENT_DATA_FIELD_LOCATIONS[componentConfig.column] || [];
    if (!modelName) {
        // If the field is a custom field, we need to display the raw value
        return answer;
    } else if (options) {
        // If the field is a standard field with options, we need to translate the value
        const label = options[answer];
        return label || answer;
    } else {
        const { data, targetModel } = await getPatientDataFieldAssociationData({
            models,
            modelName,
            fieldName,
            answer
        });
        if (!targetModel || !data) return data ?? answer;
        return getDisplayNameForModel(targetModel, data);
    }
};
const getAnswerBody = async (models, componentConfig, originalType, answer, transformConfig)=>{
    let parsedComponentConfig = {};
    let type = originalType;
    let sourceType, sourceConfig;
    try {
        if (componentConfig) {
            parsedComponentConfig = JSON.parse(componentConfig);
        }
        if (type === _constants.PROGRAM_DATA_ELEMENT_TYPES.SURVEY_ANSWER) {
            const ssc = await models.SurveyScreenComponent.findOne({
                include: [
                    {
                        model: models.ProgramDataElement,
                        as: 'dataElement',
                        where: {
                            code: parsedComponentConfig.source || parsedComponentConfig.Source
                        }
                    }
                ]
            });
            type = ssc.dataElement.dataValues.type;
            parsedComponentConfig = ssc.config ? JSON.parse(ssc.config) : {};
            sourceType = type;
            sourceConfig = ssc.config;
        }
    } catch (error) {
        console.error('Error parsing componentConfig', error);
    }
    let result;
    switch(type){
        case _constants.PROGRAM_DATA_ELEMENT_TYPES.DATE:
        case _constants.PROGRAM_DATA_ELEMENT_TYPES.SUBMISSION_DATE:
            result = convertDateAnswer(answer, transformConfig);
            break;
        case _constants.PROGRAM_DATA_ELEMENT_TYPES.BINARY:
        case _constants.PROGRAM_DATA_ELEMENT_TYPES.CHECKBOX:
            result = (0, _criteria.convertBinaryToYesNo)(answer);
            break;
        case _constants.PROGRAM_DATA_ELEMENT_TYPES.AUTOCOMPLETE:
            result = await convertAutocompleteAnswer(models, parsedComponentConfig, answer);
            break;
        case _constants.PROGRAM_DATA_ELEMENT_TYPES.PATIENT_DATA:
            result = await convertPatientDataAnswer(models, parsedComponentConfig, answer);
            break;
        default:
            result = answer;
    }
    return {
        body: result,
        sourceType,
        sourceConfig
    };
};
const transformAnswers = async (models, surveyResponseAnswers, surveyComponents, transformConfig = {})=>{
    const dataElementIdToComponent = (0, _lodash.keyBy)(surveyComponents, (component)=>component.dataElementId);
    // Some questions in the front end are not answered but still record the answer as empty string in the database
    // So we should filter any answers that are empty.
    const nonEmptyAnswers = surveyResponseAnswers.filter((answer)=>answer.body !== null && answer.body !== undefined && answer.body !== '');
    const transformedAnswers = [];
    // Transform Autocomplete answers from: ReferenceData.id to ReferenceData.name
    for (const answer of nonEmptyAnswers){
        const surveyId = answer.surveyResponse?.surveyId;
        const surveyResponseId = answer.surveyResponse?.id;
        const patientId = answer.surveyResponse?.encounter?.patientId;
        const responseEndTime = answer.surveyResponse?.endTime;
        const { dataElementId } = answer;
        const surveyComponent = dataElementIdToComponent[dataElementId];
        let type = surveyComponent?.dataElement?.dataValues?.type;
        const componentConfig = surveyComponent?.config;
        const { body, sourceType, sourceConfig } = await getAnswerBody(models, componentConfig, type, answer.body, transformConfig);
        const answerObject = {
            id: answer.id,
            surveyId,
            surveyResponseId,
            patientId,
            responseEndTime,
            dataElementId,
            body,
            sourceType,
            sourceConfig
        };
        transformedAnswers.push(answerObject);
    }
    return transformedAnswers;
};
const takeMostRecentAnswers = (answers)=>{
    const answersPerElement = (0, _lodash.groupBy)(answers, (a)=>`${a.patientId}|${a.surveyId}|${a.dataElementId}`);
    const results = [];
    for (const groupedAnswers of Object.values(answersPerElement)){
        const sortedLatestToOldestAnswers = groupedAnswers.sort((a1, a2)=>(0, _dateTime.differenceInMilliseconds)((0, _datefns.parseISO)(a2.responseEndTime), (0, _datefns.parseISO)(a1.responseEndTime)));
        results.push(sortedLatestToOldestAnswers[0]);
    }
    return results;
};

//# sourceMappingURL=transformAnswers.js.map