"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.IccMaintenanceTaskXApi = void 0;
const IccMaintenanceTaskApi_1 = require("../icc-api/api/IccMaintenanceTaskApi");
const models = require("../icc-api/model/models");
const collection_utils_1 = require("./utils/collection-utils");
const models_1 = require("../icc-api/model/models");
const AuthenticationProvider_1 = require("./auth/AuthenticationProvider");
const SecureDelegation_1 = require("../icc-api/model/SecureDelegation");
var AccessLevelEnum = SecureDelegation_1.SecureDelegation.AccessLevelEnum;
const ShareMetadataBehaviour_1 = require("./crypto/ShareMetadataBehaviour");
const utils_1 = require("./utils");
const Connection_1 = require("../icc-api/model/Connection");
class IccMaintenanceTaskXApi extends IccMaintenanceTaskApi_1.IccMaintenanceTaskApi {
    get headers() {
        return super.headers.then((h) => this.crypto.accessControlKeysHeaders.addAccessControlKeysHeaders(h, utils_1.EntityWithDelegationTypeName.MaintenanceTask));
    }
    constructor(host, headers, crypto, hcPartyApi, dataOwnerApi, userApi, authApi, autofillAuthor, encryptedKeys = [], authenticationProvider = new AuthenticationProvider_1.NoAuthenticationProvider(), fetchImpl = typeof window !== 'undefined'
        ? window.fetch
        : typeof self !== 'undefined'
            ? self.fetch
            : fetch) {
        super(host, headers, authenticationProvider, fetchImpl);
        this.crypto = crypto;
        this.hcPartyApi = hcPartyApi;
        this.dataOwnerApi = dataOwnerApi;
        this.userApi = userApi;
        this.authApi = authApi;
        this.autofillAuthor = autofillAuthor;
        this.encryptedFields = (0, utils_1.parseEncryptedFields)(encryptedKeys, 'MaintenanceTask.');
    }
    /**
     * Creates a new instance of maintenance task with initialised encryption metadata (not in the database).
     * @param user the current user.
     * @param m initialised data for the maintenance task. Metadata such as id, creation data, etc. will be automatically initialised, but you can specify
     * other kinds of data or overwrite generated metadata with this. You can't specify encryption metadata.
     * @param options optional parameters:
     * - additionalDelegates: delegates which will have access to the entity in addition to the current data owner and delegates from the
     * auto-delegations. Must be an object which associates each data owner id with the access level to give to that data owner. May overlap with
     * auto-delegations, in such case the access level specified here will be used.
     * - ignoreAutoDelegations: if true the data won't be shared with the autodelegations of the user, but only with additional delegates
     * - alternateRootDelegation: by default a new entity is created with a root delegation from self to self. In keyless mode this is not possible,
     * and instead the root delegation will be from self to another. You have to specify which delegate will be part of the root delegation.
     * @return a new instance of maintenance task.
     */
    newInstance(user_1, m_1) {
        return __awaiter(this, arguments, void 0, function* (user, m, options = {}) {
            var _a, _b, _c, _d, _e, _f, _g, _h;
            const dataOwnerId = this.dataOwnerApi.getDataOwnerIdOf(user);
            const maintenanceTask = Object.assign(Object.assign({}, (m !== null && m !== void 0 ? m : {})), { _type: 'org.taktik.icure.entities.MaintenanceTask', id: (_a = m === null || m === void 0 ? void 0 : m.id) !== null && _a !== void 0 ? _a : this.crypto.primitives.randomUuid(), created: (_b = m === null || m === void 0 ? void 0 : m.created) !== null && _b !== void 0 ? _b : new Date().getTime(), modified: (_c = m === null || m === void 0 ? void 0 : m.modified) !== null && _c !== void 0 ? _c : new Date().getTime(), responsible: (_d = m === null || m === void 0 ? void 0 : m.responsible) !== null && _d !== void 0 ? _d : (this.autofillAuthor ? dataOwnerId : undefined), author: (_e = m === null || m === void 0 ? void 0 : m.author) !== null && _e !== void 0 ? _e : (this.autofillAuthor ? user.id : undefined) });
            const extraDelegations = Object.assign(Object.assign({}, (options.ignoreAutoDelegations == true ? {} : Object.fromEntries(((_g = (_f = user.autoDelegations) === null || _f === void 0 ? void 0 : _f.all) !== null && _g !== void 0 ? _g : []).map((d) => [d, AccessLevelEnum.WRITE])))), ((_h = options === null || options === void 0 ? void 0 : options.additionalDelegates) !== null && _h !== void 0 ? _h : {}));
            return new models.MaintenanceTask(yield this.crypto.xapi
                .entityWithInitialisedEncryptedMetadata(maintenanceTask, utils_1.EntityWithDelegationTypeName.MaintenanceTask, undefined, undefined, true, extraDelegations, options.alternateRootDelegation)
                .then((x) => x.updatedEntity));
        });
    }
    createMaintenanceTask(body) {
        throw new Error('Cannot call a method that returns maintenance tasks without providing a user for de/encryption');
    }
    createMaintenanceTaskWithUser(user, body) {
        return body
            ? this.encrypt(user, [(0, collection_utils_1.cloneDeep)(body)])
                .then((tasks) => super.createMaintenanceTask(tasks[0]))
                .then((mt) => this.decrypt(user, [mt]))
                .then((tasks) => tasks[0])
            : Promise.resolve(null);
    }
    filterMaintenanceTasksBy(startDocumentId, limit, body) {
        throw new Error('Cannot call a method that returns maintenance tasks without providing a user for de/encryption');
    }
    deleteMaintenanceTask(_maintenanceTaskId) {
        throw new Error('Cannot call a method that returns maintenance tasks without providing a user for de/encryption');
    }
    deleteMaintenanceTaskWithUser(user, maintenanceTaskId) {
        return super.deleteMaintenanceTask(maintenanceTaskId);
    }
    deleteMaintenanceTasks(_maintenanceTaskIds) {
        throw new Error('Cannot call a method that returns maintenance tasks without providing a user for de/encryption');
    }
    deleteMaintenanceTasksWithUser(user, maintenanceTaskIds) {
        return super.deleteMaintenanceTasks(maintenanceTaskIds);
    }
    filterMaintenanceTasksByWithUser(user, startDocumentId, limit, body, collectTiming = false) {
        return super
            .filterMaintenanceTasksBy(startDocumentId, limit, body, collectTiming)
            .then((pl) => this.decrypt(user, pl.rows).then((dr) => Object.assign(pl, { rows: dr })));
    }
    getMaintenanceTask(maintenanceTaskId) {
        throw new Error('Cannot call a method that returns maintenance tasks without providing a user for de/encryption');
    }
    getMaintenanceTaskWithUser(user, maintenanceTaskId) {
        return super
            .getMaintenanceTask(maintenanceTaskId)
            .then((mt) => this.decrypt(user, [mt]))
            .then((mts) => mts[0]);
    }
    modifyMaintenanceTask(body) {
        throw new Error('Cannot call a method that returns maintenance tasks without providing a user for de/encryption');
    }
    modifyMaintenanceTaskWithUser(user, body) {
        return body ? this.modifyMaintenanceTaskAs(this.dataOwnerApi.getDataOwnerIdOf(user), body) : Promise.resolve(null);
    }
    modifyMaintenanceTaskAs(dataOwner, body) {
        return this.encryptAs(dataOwner, [(0, collection_utils_1.cloneDeep)(body)])
            .then((encTasks) => super.modifyMaintenanceTask(encTasks[0]))
            .then((mt) => this.decryptAs(dataOwner, [mt]))
            .then((mts) => mts[0]);
    }
    encrypt(user, maintenanceTasks) {
        const dataOwnerId = this.dataOwnerApi.getDataOwnerIdOf(user);
        return this.encryptAs(dataOwnerId, maintenanceTasks);
    }
    encryptAs(dataOwner, maintenanceTasks) {
        return this.crypto.xapi.tryEncryptEntities(maintenanceTasks, utils_1.EntityWithDelegationTypeName.MaintenanceTask, this.encryptedFields, true, false, (x) => new models.MaintenanceTask(x));
    }
    decrypt(user, maintenanceTasks) {
        const dataOwnerId = this.dataOwnerApi.getDataOwnerIdOf(user);
        return this.decryptAs(dataOwnerId, maintenanceTasks);
    }
    decryptAs(dataOwner, maintenanceTasks) {
        return __awaiter(this, void 0, void 0, function* () {
            return (yield this.crypto.xapi.tryDecryptEntities(maintenanceTasks, utils_1.EntityWithDelegationTypeName.MaintenanceTask, (x) => new models_1.MaintenanceTask(x))).map(({ entity }) => entity);
        });
    }
    /**
     * @return if the logged data owner has write access to the content of the given maintenance task
     */
    hasWriteAccess(maintenanceTask) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.crypto.xapi.hasWriteAccess({ entity: maintenanceTask, type: utils_1.EntityWithDelegationTypeName.MaintenanceTask });
        });
    }
    /**
     * Share an existing maintenance task with other data owners, allowing them to access the non-encrypted data of the maintenance task and optionally also
     * the encrypted content, with read-only or read-write permissions.
     * @param delegateId the id of the data owner which will be granted access to the maintenance task.
     * @param maintenanceTask the maintenance task to share.
     * @param options optional parameters to customize the sharing behaviour:
     * - shareSecretIds: specifies which secret ids of the entity should be shared. If not provided all secret ids available to the current user will be shared
     * - shareEncryptionKey: specifies if the encryption key of the access log should be shared with the delegate, giving access to all encrypted
     * content of the entity, excluding other encrypted metadata (defaults to {@link ShareMetadataBehaviour.IF_AVAILABLE}). Note that by default a
     * maintenance task does not have encrypted content.
     * - requestedPermissions: the requested permissions for the delegate, defaults to {@link RequestedPermissionEnum.MAX_WRITE}.
     * @return the updated entity
     */
    shareWith(delegateId_1, maintenanceTask_1) {
        return __awaiter(this, arguments, void 0, function* (delegateId, maintenanceTask, options = {}) {
            return this.shareWithMany(maintenanceTask, { [delegateId]: options });
        });
    }
    /**
     * Share an existing maintenance task with other data owners, allowing them to access the non-encrypted data of the maintenance task and optionally also
     * the encrypted content, with read-only or read-write permissions.
     * @param maintenanceTask the maintenance task to share.
     * @param delegates associates the id of data owners which will be granted access to the entity, to the following sharing options:
     * - shareSecretIds: specifies which secret ids of the entity should be shared. If not provided all secret ids available to the current user will be shared
     * - shareEncryptionKey: specifies if the encryption key of the access log should be shared with the delegate, giving access to all encrypted
     * content of the entity, excluding other encrypted metadata (defaults to {@link ShareMetadataBehaviour.IF_AVAILABLE}). Note that by default a
     * maintenance task does not have encrypted content.
     * - requestedPermissions: the requested permissions for the delegate, defaults to {@link RequestedPermissionEnum.MAX_WRITE}.
     * @return the updated entity.
     */
    shareWithMany(maintenanceTask, delegates) {
        return __awaiter(this, void 0, void 0, function* () {
            return (yield this.tryShareWithMany(maintenanceTask, delegates)).updatedEntityOrThrow;
        });
    }
    /**
     * Share an existing maintenance task with other data owners, allowing them to access the non-encrypted data of the maintenance task and optionally also
     * the encrypted content, with read-only or read-write permissions.
     * @param maintenanceTask the maintenance task to share.
     * @param delegates associates the id of data owners which will be granted access to the entity, to the following sharing options:
     * - shareSecretIds: specifies which secret ids of the entity should be shared. If not provided all secret ids available to the current user will be shared
     * - shareEncryptionKey: specifies if the encryption key of the access log should be shared with the delegate, giving access to all encrypted
     * content of the entity, excluding other encrypted metadata (defaults to {@link ShareMetadataBehaviour.IF_AVAILABLE}). Note that by default a
     * maintenance task does not have encrypted content.
     * - requestedPermissions: the requested permissions for the delegate, defaults to {@link RequestedPermissionEnum.MAX_WRITE}.
     * @return a promise which will contain the result of the operation: the updated entity if the operation was successful or details of the error if
     * the operation failed.
     */
    tryShareWithMany(maintenanceTask, delegates) {
        return __awaiter(this, void 0, void 0, function* () {
            const self = yield this.dataOwnerApi.getCurrentDataOwnerId();
            // All entities should have an encryption key.
            const entityWithEncryptionKey = yield this.crypto.xapi.ensureEncryptionKeysInitialised(maintenanceTask, utils_1.EntityWithDelegationTypeName.MaintenanceTask);
            const updatedEntity = entityWithEncryptionKey ? yield this.modifyMaintenanceTaskAs(self, entityWithEncryptionKey) : maintenanceTask;
            return this.crypto.xapi
                .simpleShareOrUpdateEncryptedEntityMetadata({
                entity: updatedEntity,
                type: utils_1.EntityWithDelegationTypeName.MaintenanceTask,
            }, Object.fromEntries(Object.entries(delegates).map(([delegateId, options]) => [
                delegateId,
                {
                    requestedPermissions: options.requestedPermissions,
                    shareEncryptionKeys: options.shareEncryptionKey,
                    shareOwningEntityIds: ShareMetadataBehaviour_1.ShareMetadataBehaviour.NEVER,
                    shareSecretIds: options.shareSecretIds,
                },
            ])), (x) => this.bulkShareMaintenanceTask(x))
                .then((r) => r.mapSuccessAsync((e) => this.decryptAs(self, [e]).then((es) => es[0])));
        });
    }
    getDataOwnersWithAccessTo(entity) {
        return this.crypto.delegationsDeAnonymization.getDataOwnersWithAccessTo({ entity, type: utils_1.EntityWithDelegationTypeName.MaintenanceTask });
    }
    getEncryptionKeysOf(entity) {
        return this.crypto.xapi.encryptionKeysOf({ entity, type: utils_1.EntityWithDelegationTypeName.MaintenanceTask }, undefined);
    }
    subscribeToMaintenanceTaskEvents(eventTypes_1, filter_1, eventFired_1) {
        return __awaiter(this, arguments, void 0, function* (eventTypes, filter, eventFired, options = {}) {
            const currentUser = yield this.userApi.getCurrentUser();
            return (0, utils_1.subscribeToEntityEvents)(this.host, this.authApi, utils_1.EntityWithDelegationTypeName.MaintenanceTask, eventTypes, filter, eventFired, options, (encrypted) => __awaiter(this, void 0, void 0, function* () { return (yield this.decrypt(currentUser, [encrypted]))[0]; })).then((rs) => new Connection_1.ConnectionImpl(rs));
        });
    }
    createDelegationDeAnonymizationMetadata(entity, delegates) {
        return this.crypto.delegationsDeAnonymization.createOrUpdateDeAnonymizationInfo({ entity, type: utils_1.EntityWithDelegationTypeName.MaintenanceTask }, delegates);
    }
}
exports.IccMaintenanceTaskXApi = IccMaintenanceTaskXApi;
//# sourceMappingURL=icc-maintenance-task-x-api.js.map