"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());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.IccDataOwnerXApi = void 0;
const utils_1 = require("./crypto/utils");
const CryptoActorStub_1 = require("../icc-api/model/CryptoActorStub");
const AuthenticationProvider_1 = require("./auth/AuthenticationProvider");
const IccDataownerApi_1 = require("../icc-api/api/IccDataownerApi");
/**
 * Extended API for managing data owners (healthcare parties, patients, and devices).
 * Provides methods to retrieve data owner information, manage hierarchies, and handle cryptographic keys.
 */
class IccDataOwnerXApi extends IccDataownerApi_1.IccDataownerApi {
    get selfDataOwnerId() {
        if (!this.currentDataOwnerHierarchyIds)
            return undefined;
        return this.currentDataOwnerHierarchyIds[this.currentDataOwnerHierarchyIds.length - 1];
    }
    constructor(host, headers, authenticationProvider = new AuthenticationProvider_1.NoAuthenticationProvider(), fetchImpl = typeof window !== 'undefined'
        ? window.fetch
        : typeof self !== 'undefined'
            ? self.fetch
            : fetch) {
        super(host, headers, authenticationProvider, fetchImpl);
    }
    /**
     * Gets the public keys of a data owner to be used for encryption with RSA-OAEP+SHA-1, in hex format.
     * @param dataOwner a data owner.
     * @return the public keys for the data owner in hex format.
     */
    getHexPublicKeysWithSha1Of(dataOwner) {
        return (0, utils_1.hexPublicKeysWithSha1Of)(dataOwner);
    }
    /**
     * Gets the public keys of a data owner to be used for encryption with RSA-OAEP+SHA-256, in hex format.
     * @param dataOwner a data owner.
     * @return the public keys for the data owner in hex format.
     */
    getHexPublicKeysWithSha256Of(dataOwner) {
        return (0, utils_1.hexPublicKeysWithSha256Of)(dataOwner);
    }
    /**
     * Gets all public keys of a data owner to be used for encryption, in hex format. Note that this may include keys that should be used for different
     * encryption algorithms.
     */
    getHexPublicKeysOf(dataOwner) {
        return new Set([...this.getHexPublicKeysWithSha1Of(dataOwner), ...this.getHexPublicKeysWithSha256Of(dataOwner)]);
    }
    /**
     * Gets the crypto actor stub for the current data owner. This is a lightweight representation containing only
     * cryptographic information without full data owner details.
     * @return the crypto actor stub of the current data owner.
     * @throws if the current user is not a data owner.
     */
    getCurrentDataOwnerStub() {
        return __awaiter(this, void 0, void 0, function* () {
            return CryptoActorStub_1.CryptoActorStubWithType.fromDataOwner(yield this.getCurrentDataOwner());
        });
    }
    /**
     * If the logged user is a data owner get the current data owner. This information is cached without expiration, and will only be updated in case
     * of forced refresh.
     * @throws if the current user is not a data owner.
     */
    getCurrentDataOwnerId() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.currentDataOwnerHierarchyIds) {
                yield this.getCurrentDataOwnerHierarchyIds();
            }
            return this.currentDataOwnerHierarchyIds[this.currentDataOwnerHierarchyIds.length - 1];
        });
    }
    /**
     * If the logged user is a data owner get its parent hierarchy. This information is cached without expiration, and will only be updated in case
     * of forced refresh.
     * The resulting array starts with the topmost parent (the only ancestor without a parent) and ends with the data owner itself.
     * @throws if the current user is not a data owner.
     */
    getCurrentDataOwnerHierarchyIds() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.currentDataOwnerHierarchyIds) {
                yield this.forceLoadCurrentDataOwnerHierarchyAndCacheIds();
            }
            return [...this.currentDataOwnerHierarchyIds];
        });
    }
    /**
     * Get the hierarchy for the current data owner starting from the specified parent.
     * @param parentId the id of a parent in the current data owner hierarchy.
     * @return an array starting at the topmost parent and ending at the provided parent id.
     * @throws if the provided id is not part of the data owner hierarchy.
     */
    getCurrentDataOwnerHierarchyIdsFrom(parentId) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.currentDataOwnerHierarchyIds) {
                yield this.getCurrentDataOwnerHierarchyIds();
            }
            const res = [];
            for (const dataOwnerId of this.currentDataOwnerHierarchyIds) {
                res.push(dataOwnerId);
                if (dataOwnerId === parentId)
                    return res;
            }
            throw new Error(`${parentId} is not part of the data owner hierarchy for the current user`);
        });
    }
    /**
     * If the logged user is a data owner get the current data owner and all of his parents.
     * @throws if the current user is not a data owner.
     * @return the current data owner hierarchy, starting from the topmost parent to the current data owner.
     */
    getCurrentDataOwnerHierarchy() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.currentDataOwnerHierarchyIds) {
                return yield this.forceLoadCurrentDataOwnerHierarchyAndCacheIds();
            }
            else
                return Promise.all(this.currentDataOwnerHierarchyIds.map((id) => this.getDataOwner(id)));
        });
    }
    /**
     * If the logged user is a data owner get the type of the current data owner. This information is cached.
     * @throws if the current user is not a data owner
     */
    getCurrentDataOwnerType() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.currentDataOwnerHierarchyIds) {
                yield this.forceLoadCurrentDataOwnerHierarchyAndCacheIds();
            }
            return this.currentDataOwnerType;
        });
    }
    /**
     * Get the id of the data owner entity for a user.
     * @param user a user that is also a data owner.
     * @return the id of the data owner corresponding to the provided user.
     * @throws if the user is not a data owner.
     */
    getDataOwnerIdOf(user) {
        var _a, _b;
        const dataOwnerId = (_b = (_a = user.healthcarePartyId) !== null && _a !== void 0 ? _a : user.patientId) !== null && _b !== void 0 ? _b : user.deviceId;
        if (dataOwnerId == undefined) {
            throw Error(`User ${user.id} is not a data owner`);
        }
        return dataOwnerId;
    }
    /**
     * Get a data owner. Note that this does not decrypt patient data owners.
     * @param ownerId id of the data owner to retrieve (patient, medical device, hcp, ...)
     * @return the data owner with the provided id
     * @throws if you have no access to the data owner. Use {@link getCryptoActorStub}.
     */
    getDataOwner(ownerId) {
        const _super = Object.create(null, {
            getDataOwner: { get: () => super.getDataOwner }
        });
        return __awaiter(this, void 0, void 0, function* () {
            return _super.getDataOwner.call(this, ownerId).then((dowt) => {
                if (dowt.dataOwner.id === this.selfDataOwnerId)
                    this.checkDataOwnerIntegrity(dowt.dataOwner);
                return dowt;
            });
        });
    }
    /**
     * Get a crypto actor stub for a data owner.
     * @param ownerId id of the data owner for which you want to retrieve the stub (patient, medical device, hcp, ...)
     * @return the crypto actor stub of the data owner with the provided id
     */
    getCryptoActorStub(ownerId) {
        const _super = Object.create(null, {
            getCryptoActorStub: { get: () => super.getCryptoActorStub }
        });
        return __awaiter(this, void 0, void 0, function* () {
            return _super.getCryptoActorStub.call(this, ownerId).then((dowt) => {
                if (dowt.stub.id === this.selfDataOwnerId)
                    this.checkDataOwnerIntegrity(dowt.stub);
                return dowt;
            });
        });
    }
    /**
     * Clears the cache of current data owner id and parent hierarchy ids. The hierarchy of a data owner should not normally change over time, so this
     * method should be rarely needed.
     */
    clearCurrentDataOwnerIdsCache() {
        this.currentDataOwnerHierarchyIds = undefined;
    }
    checkDataOwnerIntegrity(dataOwner) {
        const keys = new Set([...this.getHexPublicKeysWithSha1Of(dataOwner), ...this.getHexPublicKeysWithSha256Of(dataOwner)]);
        if (new Set(Array.from(keys).map((x) => (0, utils_1.fingerprintV2)(x))).size != keys.size)
            throw new Error(`Different public keys for ${dataOwner.id} have the same fingerprint; this should not happen in normal circumstances. Please report this error to iCure.`);
    }
    forceLoadCurrentDataOwnerHierarchyAndCacheIds() {
        return __awaiter(this, void 0, void 0, function* () {
            let curr = yield this.getCurrentDataOwner();
            this.checkDataOwnerIntegrity(curr.dataOwner);
            this.currentDataOwnerType = curr.type;
            let res = [curr];
            while (curr.dataOwner.parentId) {
                curr = yield this.getDataOwner(curr.dataOwner.parentId);
                res = [curr, ...res];
            }
            this.currentDataOwnerHierarchyIds = res.map((x) => x.dataOwner.id);
            return res;
        });
    }
}
exports.IccDataOwnerXApi = IccDataOwnerXApi;
//# sourceMappingURL=icc-data-owner-x-api.js.map