"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.ExchangeKeysManager = void 0;
/**
 * @internal This class is meant only for internal use and may be changed without notice.
 * More powerful version of {@link BaseExchangeKeysManager} with a simplified interface. Has the following functionalities:
 * - Caches results
 * - Automatically creates new exchange keys if none is available
 * - Automatically choose the public keys to use during the creation of new exchange keys
 * - Automatically retrieves the private keys to use during decryption.
 */
class ExchangeKeysManager {
    get base() {
        return this.baseExchangeKeysManager;
    }
    constructor(keyManager, baseExchangeKeysManager, dataOwnerApi) {
        this.keyManager = keyManager;
        this.baseExchangeKeysManager = baseExchangeKeysManager;
        this.dataOwnerApi = dataOwnerApi;
        this.cache = this.doGetCache(); // Intentionally not awaited to make login feel faster
    }
    /**
     * Get all keys currently available for a delegator-delegate pair. At least one of the two data owners must be part of the hierarchy for the current
     * data owner.
     * @param delegatorId id of a delegator
     * @param delegateId id of a delegate
     * @throws if neither the delegator nor the delegate is part of the hierarchy of the current data owner.
     * @return all available exchange keys from the delegator-delegate pair.
     */
    getDecryptionExchangeKeysFor(delegatorId, delegateId) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const cache = yield this.cache;
            const entry = (_a = cache[delegatorId]) === null || _a === void 0 ? void 0 : _a[delegateId];
            if (entry != undefined) {
                if ('decrypted' in entry) {
                    return yield entry.decrypted;
                }
                else {
                    const decryptedPromise = this.decryptChunk(entry.encrypted);
                    cache[delegatorId][delegateId] = { decrypted: decryptedPromise };
                    return yield decryptedPromise;
                }
            }
            else {
                return [];
            }
        });
    }
    decryptChunk(encryptedKeys) {
        return __awaiter(this, void 0, void 0, function* () {
            const decryptionKeys = this.keyManager.getDecryptionKeys();
            return (yield this.base.tryDecryptExchangeKeys(encryptedKeys, decryptionKeys)).successfulDecryptions;
        });
    }
    /**
     * Reloads all exchange keys for the cache.
     */
    reloadCache() {
        this.cache = this.doGetCache(); // Intentionally not awaited to make reload feel faster
    }
    doGetCache() {
        return __awaiter(this, void 0, void 0, function* () {
            const hierarchy = yield this.dataOwnerApi.getCurrentDataOwnerHierarchyIds();
            const encryptedKeysDataByHierarchyMember = Object.fromEntries(yield Promise.all(hierarchy.map((doId) => this.base.getAllExchangeKeysWith(doId, null).then((res) => [doId, res]))));
            const encryptedKeys = {};
            for (const [dataOwner, info] of Object.entries(encryptedKeysDataByHierarchyMember)) {
                for (const [delegator, encryptedByDelegatorFp] of Object.entries(info.keysToOwner)) {
                    if (!encryptedKeys[delegator]) {
                        encryptedKeys[delegator] = {};
                    }
                    if (!encryptedKeys[delegator][dataOwner]) {
                        encryptedKeys[delegator][dataOwner] = { encrypted: [] };
                    }
                    const keysForDelegatorDelegate = encryptedKeys[delegator][dataOwner];
                    for (const encryptedEntries of Object.values(encryptedByDelegatorFp)) {
                        keysForDelegatorDelegate.encrypted.push(encryptedEntries);
                    }
                }
                for (const encryptedByDelegateId of Object.values(info.keysFromOwner)) {
                    for (const [delegate, encryptedEntries] of Object.entries(encryptedByDelegateId)) {
                        if (!encryptedKeys[dataOwner]) {
                            encryptedKeys[dataOwner] = {};
                        }
                        if (!encryptedKeys[dataOwner][delegate]) {
                            encryptedKeys[dataOwner][delegate] = { encrypted: [] };
                        }
                        encryptedKeys[dataOwner][delegate].encrypted.push(encryptedEntries);
                    }
                }
            }
            return encryptedKeys;
        });
    }
}
exports.ExchangeKeysManager = ExchangeKeysManager;
//# sourceMappingURL=ExchangeKeysManager.js.map