"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findAppointmentsWithAI = void 0;
const extensions_core_1 = require("@awell-health/extensions-core");
const date_fns_1 = require("date-fns");
const lodash_1 = require("lodash");
const addEventLog_1 = require("../../../../src/lib/awell/addEventLog");
const constants_1 = require("../../../../src/lib/llm/openai/constants");
const createOpenAIModel_1 = require("../../../../src/lib/llm/openai/createOpenAIModel");
const utils_1 = require("../../../../src/utils");
const client_1 = require("../../client");
const extractDatesFromInstructions_1 = require("../../lib/extractDatesFromInstructions/extractDatesFromInstructions");
const findAppointmentsWithLLM_1 = require("../../lib/findAppointmentsWithLLM/findAppointmentsWithLLM");
const config_1 = require("./config");
const getAppointmentCountByStatus_1 = require("./getAppointmentCountByStatus");
exports.findAppointmentsWithAI = {
    key: 'findAppointmentsWithAI',
    category: extensions_core_1.Category.EHR_INTEGRATIONS,
    title: '✨ Find Appointments',
    description: 'Find all appointments for a patient using natural language.',
    fields: config_1.fields,
    previewable: false,
    supports_automated_retries: true,
    dataPoints: config_1.dataPoints,
    onEvent: async ({ payload, onComplete, onError, helpers }) => {
        const { prompt, patientId } = config_1.FieldsValidationSchema.parse(payload.fields);
        const api = (0, client_1.makeAPIClient)(payload.settings);
        try {
            // Initialize OpenAI model for natural language processing
            const { model, metadata, callbacks } = await (0, createOpenAIModel_1.createOpenAIModel)({
                modelType: constants_1.OPENAI_MODELS.GPT4o,
                settings: {},
                helpers,
                payload,
            });
            const { from, to, instructions } = await (0, extractDatesFromInstructions_1.extractDatesFromInstructions)({
                model,
                prompt,
                metadata,
                callbacks,
            });
            // First fetch all appointments for the patient
            const appointments = await api.findAppointments({
                patient: patientId,
            });
            // Early return if no appointments found
            if ((0, lodash_1.isNil)(appointments) || appointments.length === 0) {
                await onComplete({
                    data_points: {
                        explanation: 'No appointments found for the given patient',
                        appointmentsFound: 'false',
                        appointments: JSON.stringify([]),
                        appointmentCountsByStatus: JSON.stringify({}),
                    },
                });
                return;
            }
            // Use LLM to find appointments matching the user's natural language prompt
            const { appointmentIds, explanation } = await (0, findAppointmentsWithLLM_1.findAppointmentsWithLLM)({
                model,
                appointments,
                prompt: (0, lodash_1.defaultTo)(instructions, 'Find all appointments'),
                metadata,
                callbacks,
            });
            const htmlExplanation = await (0, utils_1.markdownToHtml)(explanation);
            // Filter appointments based on LLM's selection.
            // Use inclusive comparison for dates to ensure we don't filter out appointments that are exactly the same as the from or to date.
            const filter = (appointment) => appointmentIds.includes(appointment.id) &&
                ((0, lodash_1.isNil)(from) ||
                    (0, date_fns_1.isAfter)((0, date_fns_1.parseISO)(appointment.scheduled_date), (0, date_fns_1.parseISO)(from)) ||
                    (0, date_fns_1.isEqual)((0, date_fns_1.parseISO)(appointment.scheduled_date), (0, date_fns_1.parseISO)(from))) &&
                ((0, lodash_1.isNil)(to) ||
                    (0, date_fns_1.isBefore)((0, date_fns_1.parseISO)(appointment.scheduled_date), (0, date_fns_1.parseISO)(to)) ||
                    (0, date_fns_1.isEqual)((0, date_fns_1.parseISO)(appointment.scheduled_date), (0, date_fns_1.parseISO)(to)));
            const selectedAppointments = appointments.filter((appointment) => filter(appointment));
            const appointmentsFilteredOut = appointments
                .filter((appointment) => !filter(appointment))
                .map((appointment) => ({
                id: appointment.id,
                date: appointment.scheduled_date,
            }));
            const appointmentCountsByStatus = (0, getAppointmentCountByStatus_1.getAppointmentCountsByStatus)(selectedAppointments);
            const events = [
                (0, addEventLog_1.addActivityEventLog)({
                    message: `Found ${appointmentIds.length} appointments for patient ${patientId} that match the search instructions.`,
                }),
            ];
            if (!(0, lodash_1.isNil)(from) && !(0, lodash_1.isNil)(to)) {
                events.push((0, addEventLog_1.addActivityEventLog)({
                    message: `Narrowed down to ${selectedAppointments.length} appointments scheduled between ${from} and ${to}. Excluded ${appointmentsFilteredOut.length} appointments: ${JSON.stringify(appointmentsFilteredOut)}`,
                }));
            }
            else if (!(0, lodash_1.isNil)(from)) {
                events.push((0, addEventLog_1.addActivityEventLog)({
                    message: `Narrowed down to ${selectedAppointments.length} appointments scheduled after ${from}.`,
                }));
            }
            else if (!(0, lodash_1.isNil)(to)) {
                events.push((0, addEventLog_1.addActivityEventLog)({
                    message: `Narrowed down to ${selectedAppointments.length} appointments scheduled before ${to}.`,
                }));
            }
            await onComplete({
                data_points: {
                    appointments: JSON.stringify(selectedAppointments),
                    explanation: htmlExplanation,
                    appointmentsFound: selectedAppointments.length > 0 ? 'true' : 'false',
                    appointmentCountsByStatus: JSON.stringify(appointmentCountsByStatus),
                },
                events,
            });
        }
        catch (error) {
            await onError({
                events: [
                    {
                        date: new Date().toISOString(),
                        text: { en: 'Failed to find appointments' },
                        error: {
                            category: 'SERVER_ERROR',
                            message: error instanceof Error ? error.message : 'Unknown error',
                        },
                    },
                ],
            });
        }
    },
};
//# sourceMappingURL=findAppointmentsWithAI.js.map