"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.IccBekmehrXApi = void 0;
const icc_api_1 = require("../icc-api");
const binary_utils_1 = require("./utils/binary-utils");
const models_1 = require("../icc-api/model/models");
const AuthenticationProvider_1 = require("./auth/AuthenticationProvider");
class IccBekmehrXApi extends icc_api_1.IccBekmehrApi {
    constructor(host, headers, ctcApi, helementApi, documentApi, authenticationProvider = new AuthenticationProvider_1.NoAuthenticationProvider(), fetchImpl = typeof window !== 'undefined'
        ? window.fetch
        : typeof self !== 'undefined'
            ? self.fetch
            : fetch) {
        super(host, headers, authenticationProvider, fetchImpl);
        this.ctcApi = ctcApi;
        this.helementApi = helementApi;
        this.documentApi = documentApi;
        this.wssHost = new URL(this.host, typeof window !== 'undefined' ? window.location.href : undefined).href
            .replace(/^http/, 'ws')
            .replace(/\/rest\/v.+/, '/ws');
    }
    getJwt() {
        return __awaiter(this, void 0, void 0, function* () {
            const authService = this.authenticationProvider.getAuthService();
            if (!!authService.jwtGetter) {
                const tokens = yield authService.jwtGetter();
                if (!tokens) {
                    throw new Error('Missing JWT');
                }
                return tokens.token;
            }
            else {
                throw new Error('The existing provider is not a JWT provider');
            }
        });
    }
    socketEventListener(socket, healthcarePartyId, resolve, reject, patchers, progressCallback) {
        const that = this;
        const send = (command, uuid, body) => {
            const data = JSON.stringify({ command, uuid, body });
            socket.send(data.length > 65000 ? (0, binary_utils_1.utf8_2ua)(data).buffer : data);
        };
        const messageHandler = (msg, event) => {
            if (msg.command === 'decrypt') {
                if (msg.type === 'ContactDto') {
                    that.ctcApi
                        .decrypt(healthcarePartyId, msg.body)
                        .then((res) => patchers
                        .filter((p) => p.type === 'ContactDto')
                        .reduce((p, patcher) => __awaiter(this, void 0, void 0, function* () { return patcher.patch(yield p); }), Promise.resolve(res)))
                        .then((res) => send('decryptResponse', msg.uuid, res));
                }
                else if (msg.type === 'HealthElementDto') {
                    that.helementApi
                        .decrypt(healthcarePartyId, msg.body)
                        .then((res) => patchers
                        .filter((p) => p.type === 'HealthElementDto')
                        .reduce((p, patcher) => __awaiter(this, void 0, void 0, function* () { return patcher.patch(yield p); }), Promise.resolve(res)))
                        .then((res) => send('decryptResponse', msg.uuid, res));
                }
                else if (msg.type === 'DocumentDto') {
                    that.documentApi
                        .decrypt(msg.body.map((d) => new models_1.Document(d)))
                        .then((res) => res.map((x) => x.entity))
                        .then((res) => patchers
                        .filter((p) => p.type === 'DocumentDto')
                        .reduce((p, patcher) => __awaiter(this, void 0, void 0, function* () { return patcher.patch(yield p); }), Promise.resolve(res)))
                        .then((res) => __awaiter(this, void 0, void 0, function* () {
                        return send('decryptResponse', msg.uuid, yield Promise.all(res === null || res === void 0 ? void 0 : res.map((d) => __awaiter(this, void 0, void 0, function* () {
                            const { encryptedAttachment } = d, stripped = __rest(d, ["encryptedAttachment"]);
                            let de = d.decryptedAttachment;
                            if (de) {
                                return Object.assign(Object.assign({}, stripped), { decryptedAttachment: btoa((0, binary_utils_1.ua2string)(de)) });
                            }
                            const possiblyDecryptedAttachment = yield this.documentApi.getAndTryDecryptDocumentAttachment(d);
                            if (possiblyDecryptedAttachment.wasDecrypted) {
                                return Object.assign(Object.assign({}, stripped), { decryptedAttachment: btoa((0, binary_utils_1.ua2string)(possiblyDecryptedAttachment.data)) });
                            }
                            return stripped;
                        }))));
                    }));
                }
                else if (msg.type === 'ServiceDto') {
                    that.ctcApi
                        .decryptServices(healthcarePartyId, msg.body)
                        .then((res) => patchers
                        .filter((p) => p.type === 'ServiceDto')
                        .reduce((p, patcher) => __awaiter(this, void 0, void 0, function* () { return patcher.patch(yield p); }), Promise.resolve(res)))
                        .then((res) => send('decryptResponse', msg.uuid, res));
                }
            }
            else if (msg.command === 'progress') {
                if (progressCallback && msg.body && msg.body[0]) {
                    progressCallback(msg.body[0].progress);
                }
            }
            else {
                console.error('error received from backend:' + event.data);
                reject('websocket error: ' + event.data);
                socket.close(4000, 'backend error');
            }
        };
        return (event) => {
            if (typeof event.data === 'string') {
                const msg = JSON.parse(event.data);
                messageHandler(msg, event);
            }
            else {
                const blob = event.data;
                const subBlob = blob.slice(0, 1);
                const br = new FileReader();
                br.onload = function (e) {
                    const firstChar = e.target && new Uint8Array(e.target.result)[0];
                    if (firstChar === 0x7b) {
                        const tr = new FileReader();
                        tr.onload = function (e) {
                            const msg = e.target && JSON.parse(e.target.result);
                            messageHandler(msg, event);
                        };
                        tr.readAsBinaryString(blob);
                    }
                    else {
                        resolve(blob);
                        socket.close(1000, 'Ok');
                    }
                };
                br.readAsArrayBuffer(subBlob);
            }
        };
    }
    generateSmfExportWithEncryptionSupport(patientId, healthcarePartyId, language, body, progressCallback, patchers = []) {
        return this.getJwt().then((jwt) => new Promise((resolve, reject) => {
            const socket = new WebSocket(`${this.wssHost}/be_kmehr/generateSmf?jwt=${jwt}`);
            socket.addEventListener('open', function () {
                socket.send(JSON.stringify({
                    parameters: { patientId: patientId, language: language, info: body },
                }));
            });
            // Listen for messages
            socket.addEventListener('message', this.socketEventListener(socket, healthcarePartyId, resolve, reject, patchers, progressCallback));
        }));
    }
    generateSumehrExportWithEncryptionSupport(patientId, healthcarePartyId, language, body, patchers = []) {
        return this.getJwt().then((jwt) => new Promise((resolve, reject) => {
            const socket = new WebSocket(`${this.wssHost}/be_kmehr/generateSumehr?jwt=${jwt}`);
            socket.addEventListener('open', function () {
                socket.send(JSON.stringify({
                    parameters: { patientId: patientId, language: language, info: body },
                }));
            });
            // Listen for messages
            socket.addEventListener('message', this.socketEventListener(socket, healthcarePartyId, resolve, reject, patchers));
        }));
    }
    generateSumehrV2ExportWithEncryptionSupport(patientId, healthcarePartyId, language, body, patchers = []) {
        return this.getJwt().then((jwt) => new Promise((resolve, reject) => {
            const socket = new WebSocket(`${this.wssHost}/be_kmehr/generateSumehrV2?jwt=${jwt}`);
            socket.addEventListener('open', function () {
                socket.send(JSON.stringify({
                    parameters: { patientId: patientId, language: language, info: body },
                }));
            });
            // Listen for messages
            socket.addEventListener('message', this.socketEventListener(socket, healthcarePartyId, resolve, reject, patchers));
        }));
    }
    generateDiaryNoteExportWithEncryptionSupport(patientId, healthcarePartyId, language, body, patchers = []) {
        return this.getJwt().then((jwt) => new Promise((resolve, reject) => {
            const socket = new WebSocket(`${this.wssHost}/be_kmehr/generateDiaryNote?jwt=${jwt}`);
            socket.addEventListener('open', function () {
                socket.send(JSON.stringify({
                    parameters: { patientId: patientId, language: language, info: body },
                }));
            });
            // Listen for messages
            socket.addEventListener('message', this.socketEventListener(socket, healthcarePartyId, resolve, reject, patchers));
        }));
    }
    generateMedicationSchemeWithEncryptionSupport(patientId, healthcarePartyId, language, recipientSafe, version, body, patchers = []) {
        return this.getJwt().then((jwt) => new Promise((resolve, reject) => {
            const socket = new WebSocket(`${this.wssHost}/be_kmehr/generateMedicationScheme?jwt=${jwt}`);
            socket.addEventListener('open', function () {
                socket.send(JSON.stringify({
                    parameters: {
                        patientId: patientId,
                        language: language,
                        recipientSafe: recipientSafe,
                        version: version,
                        info: body,
                    },
                }));
            });
            // Listen for messages
            socket.addEventListener('message', this.socketEventListener(socket, healthcarePartyId, resolve, reject, patchers));
        }));
    }
}
exports.IccBekmehrXApi = IccBekmehrXApi;
//# sourceMappingURL=icc-bekmehr-x-api.js.map