"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "patientRelations", {
    enumerable: true,
    get: function() {
        return patientRelations;
    }
});
const _expressasynchandler = /*#__PURE__*/ _interop_require_default(require("express-async-handler"));
const _sequelize = require("sequelize");
const _importable = require("@tamanu/constants/importable");
const _renameObjectKeys = require("@tamanu/utils/renameObjectKeys");
const _crudHelpers = require("@tamanu/shared/utils/crudHelpers");
const _constants = require("@tamanu/constants");
const _patientSecondaryId = require("./patientSecondaryId");
const _patientDeath = require("./patientDeath");
const _patientProfilePicture = require("./patientProfilePicture");
const _deleteModel = require("../../../routeHandlers/deleteModel");
const _getPermittedSurveyIds = require("../../../utils/getPermittedSurveyIds");
const _query = require("../../../utils/query");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
const patientRelations = (0, _crudHelpers.permissionCheckingRouter)('read', 'Patient');
patientRelations.get('/:id/encounters', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('list', 'Encounter');
    const { db, models: { Encounter }, params, query } = req;
    const { order = 'ASC', orderBy, open = false, encounterType, facilityId, dischargingClinicianId } = query;
    const ENCOUNTER_SORT_KEYS = {
        startDate: 'start_date',
        encounterType: `
        CASE
          ${_constants.ENCOUNTER_TYPE_VALUES.map((value)=>`WHEN encounter_type = '${value}' THEN '${_constants.ENCOUNTER_TYPE_LABELS[value]}'`).join(' ')}
        END
      `,
        endDate: 'end_date',
        facilityName: 'facility_name',
        locationGroupName: 'location_group_name',
        dischargingClinicianName: 'discharging_clinician_name'
    };
    const sortKey = orderBy && ENCOUNTER_SORT_KEYS[orderBy];
    const sortDirection = order.toLowerCase() === 'asc' ? 'ASC' : 'DESC';
    const sortExpression = sortKey && (orderBy === 'dischargingClinicianName' ? `${sortKey} ${sortDirection} NULLS LAST` : `${sortKey} ${sortDirection}`);
    const searchFilters = [
        (0, _query.makeFilter)(encounterType, 'encounters.encounter_type = :encounterType'),
        (0, _query.makeFilter)(facilityId, 'locations.facility_id = :facilityId'),
        (0, _query.makeFilter)(dischargingClinicianId, 'dischargingClinician.id = :dischargingClinicianId')
    ];
    const { whereClauses, filterReplacements } = (0, _query.getWhereClausesAndReplacementsFromFilters)(searchFilters, {
        encounterType,
        facilityId,
        dischargingClinicianId
    });
    const searchWhereClause = whereClauses ? `AND ${whereClauses}` : '';
    const fromClause = `
      FROM
        encounters
        INNER JOIN locations
          ON encounters.location_id = locations.id
        INNER JOIN facilities
          ON locations.facility_id = facilities.id
        LEFT JOIN location_groups
          ON location_groups.id = locations.location_group_id
        LEFT JOIN LATERAL (
          SELECT discharger_id
          FROM discharges
          WHERE discharges.encounter_id = encounters.id
            AND deleted_at IS NULL
          ORDER BY (discharger_id IS NULL), discharger_id
          LIMIT 1
        ) AS discharge ON true
        LEFT JOIN users AS dischargingClinician
          ON dischargingClinician.id = discharge.discharger_id`;
    const whereClause = `
      WHERE
        patient_id = :patientId
        AND encounters.deleted_at IS NULL
        AND locations.deleted_at IS NULL
        AND facilities.deleted_at IS NULL
        AND location_groups.deleted_at IS NULL
        ${open ? 'AND encounters.end_date IS NULL' : ''}
        ${searchWhereClause}`;
    const { count, data } = await (0, _crudHelpers.runPaginatedQuery)(db, Encounter, `
        SELECT COUNT(1) as count
        ${fromClause}
        ${whereClause}
      `, `
        SELECT
          encounters.*,
          locations.facility_id AS facility_id,
          facilities.name AS facility_name,
          location_groups.name AS location_group_name,
          location_groups.id AS location_group_id,
          dischargingClinician.display_name AS discharging_clinician_name
        ${fromClause}
        ${whereClause}
        ${sortExpression ? `ORDER BY ${sortExpression}` : ''}
      `, {
        patientId: params.id,
        ...filterReplacements
    }, query);
    res.send({
        count: parseInt(count, 10),
        data
    });
}));
patientRelations.get('/:id/issues', (0, _crudHelpers.simpleGetList)('PatientIssue', 'patientId'));
patientRelations.get('/:id/conditions', (0, _crudHelpers.simpleGetList)('PatientCondition', 'patientId'));
patientRelations.get('/:id/allergies', (0, _crudHelpers.simpleGetList)('PatientAllergy', 'patientId'));
patientRelations.get('/:id/familyHistory', (0, _crudHelpers.simpleGetList)('PatientFamilyHistory', 'patientId'));
patientRelations.get('/:id/carePlans', (0, _crudHelpers.simpleGetList)('PatientCarePlan', 'patientId'));
patientRelations.get('/:id/additionalData', (0, _expressasynchandler.default)(async (req, res)=>{
    const { models, params, query: { facilityId } } = req;
    req.checkPermission('read', 'Patient');
    const additionalDataRecord = await models.PatientAdditionalData.findOne({
        where: {
            patientId: params.id
        },
        include: models.PatientAdditionalData.getFullReferenceAssociations()
    });
    const recordData = additionalDataRecord ? additionalDataRecord.toJSON() : {};
    if (additionalDataRecord) {
        await req.audit.access({
            recordId: additionalDataRecord.id,
            frontEndContext: params,
            model: models.PatientAdditionalData,
            facilityId
        });
    }
    res.send(recordData);
}));
patientRelations.get('/:id/fields', (0, _expressasynchandler.default)(async (req, res)=>{
    const { params } = req;
    req.checkPermission('read', 'Patient');
    const values = await req.db.query(`
        SELECT
          d.id AS "definitionId",
          v.value
        FROM patient_field_definitions d
        JOIN patient_field_values v
        ON v.definition_id = d.id
        WHERE v.patient_id = :patientId
        AND d.visibility_status NOT IN (:hiddenStatuses)
        AND d.deleted_at IS NULL
        AND v.deleted_at IS NULL;
      `, {
        replacements: {
            patientId: params.id,
            hiddenStatuses: _importable.HIDDEN_VISIBILITY_STATUSES
        },
        type: _sequelize.QueryTypes.SELECT
    });
    res.send({
        data: values.reduce((memo, { definitionId, value })=>({
                ...memo,
                [definitionId]: value
            }), {})
    });
}));
const REFERRAL_SORT_KEYS = {
    date: _sequelize.Sequelize.literal('"surveyResponse.submissionDate"'),
    referralType: _sequelize.Sequelize.col('surveyResponse.survey.name'),
    status: _sequelize.Sequelize.col('status')
};
patientRelations.get('/:id/referrals', (0, _expressasynchandler.default)(async (req, res)=>{
    const { models, params, query } = req;
    const { order = 'asc', orderBy = 'date' } = query;
    req.checkPermission('list', 'SurveyResponse');
    const sortKey = REFERRAL_SORT_KEYS[orderBy] || REFERRAL_SORT_KEYS.date;
    const sortDirection = order.toLowerCase() === 'asc' ? 'ASC' : 'DESC';
    const permittedSurveyIds = await (0, _getPermittedSurveyIds.getPermittedSurveyIds)(req, models);
    if (!permittedSurveyIds.length) {
        res.send({
            data: [],
            count: 0
        });
    }
    const patientReferrals = await models.Referral.findAll({
        include: [
            {
                association: 'initiatingEncounter',
                where: {
                    '$initiatingEncounter.patient_id$': params.id
                }
            },
            {
                association: 'surveyResponse',
                attributes: {
                    include: [
                        [
                            _sequelize.Sequelize.literal(`COALESCE((SELECT
                    sra.body
                  FROM survey_response_answers sra
                   LEFT JOIN program_data_elements pde ON sra.data_element_id = pde.id
                  WHERE "surveyResponse".id = sra.response_id
                    AND pde.type = 'SubmissionDate'), "surveyResponse".end_time)`),
                            'submissionDate'
                        ]
                    ]
                },
                include: [
                    {
                        association: 'answers'
                    },
                    {
                        association: 'survey',
                        include: [
                            {
                                association: 'components',
                                include: [
                                    {
                                        association: 'dataElement'
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ],
        where: {
            '$surveyResponse.survey_id$': {
                [_sequelize.Op.in]: permittedSurveyIds
            }
        },
        order: [
            [
                sortKey,
                sortDirection
            ]
        ]
    });
    res.send({
        count: patientReferrals.length,
        data: patientReferrals
    });
}));
patientRelations.delete('/:id/referrals/:referralId', _deleteModel.deleteReferral);
const PROGRAM_RESPONSE_SORT_KEYS = {
    endTime: 'end_time',
    submittedBy: 'submitted_by',
    programName: 'program_name',
    surveyName: 'survey_name',
    resultText: 'result_text'
};
patientRelations.get('/:id/programResponses', (0, _expressasynchandler.default)(async (req, res)=>{
    const { db, models, params, query } = req;
    req.checkPermission('list', 'SurveyResponse');
    const patientId = params.id;
    const { surveyId, programId, procedureId, surveyType = 'programs', order = 'asc', orderBy = 'endTime' } = query;
    const sortKey = PROGRAM_RESPONSE_SORT_KEYS[orderBy] || PROGRAM_RESPONSE_SORT_KEYS.endTime;
    const sortDirection = order.toLowerCase() === 'asc' ? 'ASC' : 'DESC';
    const permittedSurveyIds = await (0, _getPermittedSurveyIds.getPermittedSurveyIds)(req, models);
    if (!permittedSurveyIds.length) {
        res.send({
            data: [],
            count: 0
        });
    }
    const { count, data } = await (0, _crudHelpers.runPaginatedQuery)(db, models.SurveyResponse, `
        SELECT COUNT(1) as count
        FROM
          survey_responses
          LEFT JOIN encounters
            ON (survey_responses.encounter_id = encounters.id)
          LEFT JOIN surveys
            ON (survey_responses.survey_id = surveys.id)
          ${procedureId ? 'LEFT JOIN procedure_survey_responses ON (survey_responses.id = procedure_survey_responses.survey_response_id)' : ''}
        WHERE
          encounters.patient_id = :patientId
          AND surveys.survey_type = :surveyType
          AND survey_responses.deleted_at IS NULL
          ${surveyId ? 'AND surveys.id = :surveyId' : 'AND surveys.id IN (:surveyIds)'}
          ${procedureId ? 'AND procedure_survey_responses.procedure_id = :procedureId' : 'AND survey_responses.id NOT IN (SELECT survey_response_id FROM procedure_survey_responses WHERE deleted_at IS NULL)'}
      `, `
        SELECT
          survey_responses.*,
          surveys.id as survey_id,
          surveys.name as survey_name,
          encounters.examiner_id,
          COALESCE(survey_user.display_name, encounter_user.display_name) as submitted_by,
          programs.name as program_name
        FROM
          survey_responses
          LEFT JOIN encounters
            ON (survey_responses.encounter_id = encounters.id)
          LEFT JOIN surveys
            ON (survey_responses.survey_id = surveys.id)
          LEFT JOIN users encounter_user
            ON (encounter_user.id = encounters.examiner_id)
          LEFT JOIN users survey_user
            ON (survey_user.id = survey_responses.user_id)
          LEFT JOIN programs
            ON (programs.id = surveys.program_id)
          ${procedureId ? 'LEFT JOIN procedure_survey_responses ON (survey_responses.id = procedure_survey_responses.survey_response_id)' : ''}
        WHERE encounters.patient_id = :patientId
          AND encounters.deleted_at is null
          AND surveys.survey_type = :surveyType
          AND survey_responses.deleted_at IS NULL
          ${surveyId ? 'AND surveys.id = :surveyId' : 'AND surveys.id IN (:surveyIds)'}
          ${programId ? 'AND programs.id = :programId' : ''}
          ${procedureId ? 'AND procedure_survey_responses.procedure_id = :procedureId' : 'AND survey_responses.id NOT IN (SELECT survey_response_id FROM procedure_survey_responses)'}
        ORDER BY ${sortKey} ${sortDirection}
      `, {
        patientId,
        surveyId,
        surveyIds: permittedSurveyIds,
        programId,
        procedureId,
        surveyType
    }, query);
    res.send({
        count: parseInt(count, 10),
        data
    });
}));
patientRelations.get('/:id/labTestResults', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('list', 'LabTest');
    const canListSensitive = req.ability.can('list', 'SensitiveLabRequest');
    const { db, models: { LabTest }, params, query } = req;
    const { categoryId, panelId, status = 'published' } = query;
    const results = await db.query(`SELECT
    reference_data.name AS test_category,
    lab_test_types.name AS test_type,
    lab_test_types.options AS test_options,
    lab_test_types.id AS test_type_id,
    FIRST(lab_test_types.unit) AS unit,
    JSONB_BUILD_OBJECT(
      'male', JSONB_BUILD_OBJECT(
        'min', MIN(lab_test_types.male_min),
        'max', MAX(lab_test_types.male_max)
      ),
      'female', JSONB_BUILD_OBJECT(
        'min', MIN(lab_test_types.female_min),
        'max', MAX(lab_test_types.female_max)
      )
    ) AS normal_ranges,
    JSONB_OBJECT_AGG(
      lab_requests.sample_time, JSONB_BUILD_OBJECT(
        'result', lab_tests.result,
        'id', lab_tests.id,
        'referenceRangeMin', lab_tests.reference_range_min,
        'referenceRangeMax', lab_tests.reference_range_max
      )
    ) AS results
    ${panelId ? ', panel_join."order" AS panel_order' : ''}
  FROM
    lab_tests
  INNER JOIN
    lab_requests
  ON
    lab_tests.lab_request_id = lab_requests.id
  INNER JOIN
    lab_test_types
  ON
    lab_tests.lab_test_type_id = lab_test_types.id
  INNER JOIN
    reference_data
  ON
    lab_test_types.lab_test_category_id = reference_data.id
  ${panelId ? `LEFT JOIN
    lab_test_panel_lab_test_types AS panel_join
  ON
    panel_join.lab_test_type_id = lab_test_types.id
    AND panel_join.lab_test_panel_id = :panelId` : ''}
  WHERE
  encounter_id IN (
      SELECT id
      FROM
        encounters
      WHERE
        patient_id = :patientId
    )
  AND lab_requests.status = :status
  AND lab_requests.sample_time IS NOT NULL
  AND lab_requests.deleted_at IS NULL
  AND CASE WHEN :canListSensitive IS TRUE
    THEN TRUE
    ELSE lab_test_types.is_sensitive IS FALSE
    END
  ${categoryId ? 'AND lab_requests.lab_test_category_id = :categoryId' : ''}
  ${panelId ? `AND lab_test_types.id IN (
         SELECT lab_test_type_id
         FROM
           lab_test_panel_lab_test_types
         WHERE
           lab_test_panel_id = :panelId
       )` : ''}
  GROUP BY
    test_category, test_type, test_options, test_type_id ${panelId ? ', panel_order' : ''}
  ORDER BY
    ${panelId ? 'panel_order ASC,' : ''} test_category`, {
        replacements: {
            patientId: params.id,
            status,
            categoryId,
            panelId,
            canListSensitive
        },
        model: LabTest,
        type: _sequelize.QueryTypes.SELECT,
        mapToModel: true
    });
    const formattedData = results.map((x)=>(0, _renameObjectKeys.renameObjectKeys)(x.forResponse()));
    res.send({
        count: results.length,
        data: formattedData
    });
}));
patientRelations.delete('/:id/programResponses/:surveyResponseId', _deleteModel.deleteSurveyResponse);
patientRelations.use(_patientProfilePicture.patientProfilePicture);
patientRelations.use(_patientDeath.patientDeath);
patientRelations.use(_patientSecondaryId.patientSecondaryIdRoutes);

//# sourceMappingURL=patientRelations.js.map