"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeAPIClient = exports.ElationAPIClient = exports.ElationDataWrapper = void 0;
const extensions_core_1 = require("@awell-health/extensions-core");
const settings_1 = require("./settings");
const types_1 = require("./types");
const cache_1 = require("./cache");
const lodash_1 = require("lodash");
class ElationDataWrapper extends extensions_core_1.DataWrapper {
    async findAppointments(params) {
        const req = this.Request({
            method: 'GET',
            url: `/appointments/`,
            params,
        });
        const res = await req;
        return res.results;
    }
    async getAppointment(id) {
        const req = this.Request({
            method: 'GET',
            url: `/appointments/${id}`,
        });
        const res = await req;
        return res;
    }
    async createAppointment(obj) {
        const req = this.Request({
            method: 'POST',
            url: `/appointments`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    async updateAppointment(id, obj) {
        const req = this.Request({
            method: 'PATCH',
            url: `/appointments/${id}`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    async getPatient(id) {
        const req = this.Request({
            method: 'GET',
            url: `/patients/${id}`,
        });
        const res = await req;
        return res;
    }
    async createPatient(obj) {
        const req = this.RequestRaw({
            method: 'POST',
            url: `/patients`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    async updatePatient(id, obj) {
        const req = this.Request({
            method: 'PATCH',
            url: `/patients/${id}`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    async findSubscriptions() {
        const req = this.Request({
            method: 'GET',
            url: '/app/subscriptions/',
        });
        const res = await req;
        return res.results;
    }
    async createSubscription(obj) {
        const req = this.Request({
            method: 'POST',
            url: '/app/subscriptions/',
            data: obj,
        });
        const res = await req;
        return res;
    }
    async deleteSubscription(id) {
        const req = this.Request({
            method: 'DELETE',
            url: `/app/subscriptions/${id}/`,
        });
        await req;
    }
    async getPhysician(id) {
        const req = this.Request({
            method: 'GET',
            url: `/physicians/${id}`,
        });
        const res = await req;
        return res;
    }
    async getLetter(id) {
        const req = this.Request({
            method: 'GET',
            url: `/letters/${id}`,
        });
        const res = await req;
        return res;
    }
    async getReferralOrder(id) {
        const req = this.Request({
            method: 'GET',
            url: `/referral_orders/${id}`,
        });
        const res = await req;
        return res;
    }
    async findPhysicians({ params, }) {
        return await this.Request({
            method: 'GET',
            url: '/physicians/',
            params,
        });
    }
    async getNonVisitNote(id) {
        return await this.Request({
            method: 'GET',
            url: `/non_visit_notes/${id}`,
        });
    }
    async createNonVisitNote(obj) {
        return await this.RequestRaw({
            method: 'POST',
            url: '/non_visit_notes/',
            data: obj,
        });
    }
    async updateNonVisitNote(id, obj) {
        return await this.Request({
            // PATCH - makes all fields optional in Elation (PUT requires all fields)
            method: 'PATCH',
            url: `/non_visit_notes/${id}`,
            data: obj,
        });
    }
    async updateReferralOrder(id, obj) {
        return await this.Request({
            // PATCH - makes all fields optional in Elation (PUT requires all fields)
            method: 'PATCH',
            url: `/referral_orders/${id}`,
            data: obj,
        });
    }
    async deleteNonVisitNote(id) {
        await this.Request({
            method: 'DELETE',
            url: `/non_visit_notes/${id}`,
        });
    }
    async postLetter(obj) {
        return await this.Request({
            method: 'POST',
            url: '/letters',
            data: obj,
        });
    }
    async listContacts(obj) {
        return await this.Request({
            method: 'GET',
            url: `/contacts?npi=${obj.npi}`,
        });
    }
    async searchContacts(obj) {
        return await this.Request({
            method: 'GET',
            url: `/contacts?name=${obj.name}`,
        });
    }
    async createLabOrder(obj) {
        return await this.Request({
            method: 'POST',
            url: '/lab_orders',
            data: obj,
        });
    }
    async createMessageThread(obj) {
        const req = this.Request({
            method: 'POST',
            url: `/message_threads`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    // A bit confusing, but in Elation, 'Message Thread' is the 'main object'
    // and you add thread messages to main Message Thread.
    // see https://docs.elationhealth.com/reference/create-thread-message
    async addMessageToThread(obj) {
        const req = this.Request({
            method: 'POST',
            url: `/thread_messages`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    async addHistory(obj) {
        const req = this.Request({
            method: 'POST',
            url: `/histories`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    async addAllergy(obj) {
        const req = this.Request({
            method: 'POST',
            url: `/allergies`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    async createVisitNote(obj) {
        const req = this.Request({
            method: 'POST',
            url: `/visit_notes`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    async updateVisitNote(id, obj) {
        return await this.Request({
            // PATCH - makes all fields optional in Elation (PUT requires all fields)
            method: 'PATCH',
            url: `/visit_notes/${id}`,
            data: obj,
        });
    }
    async addVitals(obj) {
        const req = this.Request({
            method: 'POST',
            url: `/vitals`,
            data: obj,
        });
        const res = await req;
        return res;
    }
    async getPharmacy(ncpdpId) {
        return types_1.PharmacySchema.parse(await this.Request({
            method: 'GET',
            url: `/pharmacies/${ncpdpId}`,
        }));
    }
    async createReferralOrder(obj) {
        return await this.Request({
            method: 'POST',
            url: '/referral_orders',
            data: obj,
        });
    }
    async findPractices() {
        return await this.Request({
            method: 'GET',
            url: '/practices',
        });
    }
    async createCareGap(obj) {
        const { quality_program, ...data } = obj;
        return await this.Request({
            method: 'POST',
            url: `/${quality_program}/caregap/`,
            data,
        });
    }
    async closeCareGap(obj) {
        const { quality_program, caregap_id, status } = obj;
        return await this.Request({
            method: 'POST',
            url: `/${quality_program}/caregap/${caregap_id}/`,
            data: {
                status,
            },
        });
    }
}
exports.ElationDataWrapper = ElationDataWrapper;
class ElationAPIClient extends extensions_core_1.APIClient {
    constructor({ authUrl, requestConfig, ...opts }) {
        const getAuth = () => {
            if ('username' in requestConfig && 'password' in requestConfig) {
                return new extensions_core_1.OAuthPassword({
                    auth_url: authUrl,
                    request_config: requestConfig,
                    cacheService: cache_1.elationCacheService,
                    useHeaderInAuthorization: true,
                });
            }
            return new extensions_core_1.OAuthClientCredentials({
                auth_url: authUrl,
                request_config: requestConfig,
                cacheService: cache_1.elationCacheService,
            });
        };
        super({
            ...opts,
            auth: getAuth(),
        });
        this.ctor = (token, baseUrl) => new ElationDataWrapper(token, baseUrl);
    }
    async findAppointments(params) {
        return await this.FetchData(async (dw) => await dw.findAppointments(params));
    }
    async getAppointment(id) {
        return await this.FetchData(async (dw) => await dw.getAppointment(id));
    }
    async createAppointment(obj) {
        return await this.FetchData(async (dw) => await dw.createAppointment(obj));
    }
    async updateAppointment(id, obj) {
        return await this.FetchData(async (dw) => await dw.updateAppointment(id, obj));
    }
    async getPatient(id) {
        return await this.FetchData(async (dw) => await dw.getPatient(id));
    }
    async createPatient(obj) {
        return await this.FetchData(async (dw) => await dw.createPatient(obj));
    }
    async updatePatient(id, obj) {
        return await this.FetchData(async (dw) => await dw.updatePatient(id, obj));
    }
    async findSubscriptions() {
        return await this.FetchData(async (dw) => await dw.findSubscriptions());
    }
    async createSubscription(obj) {
        return await this.FetchData(async (dw) => await dw.createSubscription(obj));
    }
    async deleteSubscription(id) {
        await this.FetchData(async (dw) => {
            await dw.deleteSubscription(id);
        });
    }
    async getPhysician(id) {
        return await this.FetchData(async (dw) => await dw.getPhysician(id));
    }
    async getLetter(id) {
        return await this.FetchData(async (dw) => await dw.getLetter(id));
    }
    async getReferralOrder(id) {
        return await this.FetchData(async (dw) => await dw.getReferralOrder(id));
    }
    async findPhysicians({ params, }) {
        return await this.FetchData(async (dw) => await dw.findPhysicians({ params }));
    }
    async getNonVisitNote(id) {
        return await this.FetchData(async (dw) => await dw.getNonVisitNote(id));
    }
    async createNonVisitNote(obj) {
        return await this.FetchData(async (dw) => await dw.createNonVisitNote(obj));
    }
    async updateNonVisitNote(id, obj) {
        return await this.FetchData(async (dw) => await dw.updateNonVisitNote(id, obj));
    }
    async updateReferralOrder(id, obj) {
        return await this.FetchData(async (dw) => await dw.updateReferralOrder(id, obj));
    }
    async deleteNonVisitNote(id) {
        await this.FetchData(async (dw) => {
            await dw.deleteNonVisitNote(id);
        });
    }
    async postNewLetter(obj) {
        return await this.FetchData(async (dw) => await dw.postLetter(obj));
    }
    async searchContactsByNpi(obj) {
        return await this.FetchData(async (dw) => await dw.listContacts(obj));
    }
    async searchContactsByName(obj) {
        return await this.FetchData(async (dw) => await dw.searchContacts(obj));
    }
    async createLabOrder(obj) {
        return await this.FetchData(async (dw) => await dw.createLabOrder(obj));
    }
    async addHistory(obj) {
        return await this.FetchData(async (dw) => await dw.addHistory(obj));
    }
    async createMessageThread(obj) {
        return await this.FetchData(async (dw) => await dw.createMessageThread(obj));
    }
    async addMessageToThread(obj) {
        return await this.FetchData(async (dw) => await dw.addMessageToThread(obj));
    }
    async addAllergy(obj) {
        return await this.FetchData(async (dw) => await dw.addAllergy(obj));
    }
    async createVisitNote(obj) {
        return await this.FetchData(async (dw) => await dw.createVisitNote(obj));
    }
    async updateVisitNote(id, obj) {
        return await this.FetchData(async (dw) => await dw.updateVisitNote(id, obj));
    }
    async addVitals(obj) {
        return await this.FetchData(async (dw) => await dw.addVitals(obj));
    }
    async getPharmacy(ncpdpId) {
        return await this.FetchData(async (dw) => await dw.getPharmacy(ncpdpId));
    }
    async createReferralOrder(obj) {
        return await this.FetchData(async (dw) => await dw.createReferralOrder(obj));
    }
    async findPractices() {
        return await this.FetchData(async (dw) => await dw.findPractices());
    }
    async createCareGap(obj) {
        return await this.FetchData(async (dw) => await dw.createCareGap(obj));
    }
    async closeCareGap(obj) {
        return await this.FetchData(async (dw) => await dw.closeCareGap(obj));
    }
}
exports.ElationAPIClient = ElationAPIClient;
const makeAPIClient = (settings) => {
    const { base_url, auth_url, ...auth_request_settings } = settings_1.SettingsValidationSchema.parse(settings);
    /**
     * Determines the OAuth grant type based on the provided settings.
     * Currently, we support both the "password" and "client_credentials" grant types for backward compatibility.
     * - "password" grant is still supported to avoid breaking existing care flows that rely on it.
     * - "client_credentials" grant is the preferred method for authentication as per the latest Elation API guidance.
     * Once all existing care flows are migrated, support for the "password" grant can be deprecated.
     */
    const getGrantType = () => {
        if ((0, lodash_1.isEmpty)(auth_request_settings.username) ||
            (0, lodash_1.isEmpty)(auth_request_settings.password))
            return 'client_credentials';
        return 'password';
    };
    const grantType = getGrantType();
    /**
     * Builds the appropriate request configuration based on the selected grant type.
     * - For "client_credentials", only the client ID and client secret are required.
     * - For "password", username and password are included for compatibility with older flows.
     */
    const getRequestConfig = () => {
        if (grantType === 'client_credentials')
            return {
                client_id: auth_request_settings.client_id,
                client_secret: auth_request_settings.client_secret,
            };
        return {
            client_id: auth_request_settings.client_id,
            client_secret: auth_request_settings.client_secret,
            username: auth_request_settings.username,
            password: auth_request_settings.password,
        };
    };
    return new ElationAPIClient({
        authUrl: auth_url,
        baseUrl: base_url,
        requestConfig: getRequestConfig(),
    });
};
exports.makeAPIClient = makeAPIClient;
//# sourceMappingURL=client.js.map