"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 __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.consumeAuthorizationRequests = exports.getAuthorization = exports.prepareConsumeAuthorizationRequests = void 0;
const bluebird_1 = __importDefault(require("bluebird"));
const lodash_1 = require("lodash");
const internal_1 = require("../../internal");
const types_1 = require("../../types");
const utils_1 = require("../../types/utils");
const conversion_1 = require("../../utils/conversion");
const internal_2 = require("../../utils/internal");
/**
 * @hidden
 */
function prepareConsumeAuthorizationRequests(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context: { polymeshApi: { tx }, }, context, } = this;
        const { accept, authRequests } = args;
        const liveRequests = authRequests.filter(request => !request.isExpired());
        if (accept) {
            // auth types not present in this object should not be possible in this procedure
            const typesToExtrinsics = {
                [types_1.AuthorizationType.AddRelayerPayingKey]: tx.relayer.acceptPayingKey,
                [types_1.AuthorizationType.BecomeAgent]: tx.externalAgents.acceptBecomeAgent,
                [types_1.AuthorizationType.PortfolioCustody]: tx.portfolio.acceptPortfolioCustody,
                [types_1.AuthorizationType.RotatePrimaryKey]: tx.identity.acceptPrimaryKey,
                [types_1.AuthorizationType.TransferAssetOwnership]: tx.asset.acceptAssetOwnershipTransfer,
                [types_1.AuthorizationType.TransferTicker]: tx.asset.acceptTickerTransfer,
            };
            const idsPerType = lodash_1.mapValues(typesToExtrinsics, () => []);
            liveRequests.forEach(({ authId, data: { type } }) => {
                const id = utils_1.tuple(conversion_1.numberToU64(authId, context));
                idsPerType[type].push(id);
            });
            lodash_1.forEach(idsPerType, (ids, key) => {
                const type = key;
                // TODO @monitz87: include the attestation auth in the mix (should probably be a different procedure)
                if (type === types_1.AuthorizationType.RotatePrimaryKey) {
                    this.addBatchTransaction(typesToExtrinsics[type], {}, ids.map(([id]) => utils_1.tuple(id, null)));
                }
                else {
                    this.addBatchTransaction(typesToExtrinsics[type], {}, ids);
                }
            });
        }
        else {
            const falseBool = conversion_1.booleanToBool(false, context);
            const authIdentifiers = liveRequests.map(({ authId, target }) => utils_1.tuple(conversion_1.signerValueToSignatory(conversion_1.signerToSignerValue(target), context), conversion_1.numberToU64(authId, context), falseBool));
            this.addBatchTransaction(tx.identity.removeAuthorization, {}, authIdentifiers);
        }
    });
}
exports.prepareConsumeAuthorizationRequests = prepareConsumeAuthorizationRequests;
/**
 * @hidden
 */
function getAuthorization({ authRequests, accept }) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context } = this;
        let did;
        const unexpiredRequests = authRequests.filter(request => !request.isExpired());
        const fetchDid = () => __awaiter(this, void 0, void 0, function* () { return internal_2.getDid(did, context); });
        const authorized = yield bluebird_1.default.mapSeries(unexpiredRequests, ({ target, issuer }) => __awaiter(this, void 0, void 0, function* () {
            let condition;
            if (target instanceof internal_1.Account) {
                const { address } = context.getCurrentAccount();
                condition = address === target.address;
            }
            else {
                did = yield fetchDid();
                condition = did === target.did;
            }
            if (!accept) {
                did = yield fetchDid();
                condition = condition || did === issuer.did;
            }
            return condition;
        }));
        let transactions = [types_1.TxTags.identity.RemoveAuthorization];
        if (accept) {
            const typesToTags = {
                [types_1.AuthorizationType.AddRelayerPayingKey]: types_1.TxTags.relayer.AcceptPayingKey,
                [types_1.AuthorizationType.BecomeAgent]: types_1.TxTags.externalAgents.AcceptBecomeAgent,
                [types_1.AuthorizationType.PortfolioCustody]: types_1.TxTags.portfolio.AcceptPortfolioCustody,
                [types_1.AuthorizationType.RotatePrimaryKey]: types_1.TxTags.identity.AcceptPrimaryKey,
                [types_1.AuthorizationType.TransferAssetOwnership]: types_1.TxTags.asset.AcceptAssetOwnershipTransfer,
                [types_1.AuthorizationType.TransferTicker]: types_1.TxTags.asset.AcceptTickerTransfer,
            };
            transactions = authRequests.map(({ data: { type } }) => typesToTags[type]);
        }
        return {
            roles: authorized.every(res => res) ||
                'Authorization Requests can only be accepted by the target Account/Identity. They can only be rejected by the target Account/Identity or the issuing Identity',
            permissions: {
                transactions,
                tokens: [],
                portfolios: [],
            },
        };
    });
}
exports.getAuthorization = getAuthorization;
/**
 * @hidden
 */
const consumeAuthorizationRequests = () => new internal_1.Procedure(prepareConsumeAuthorizationRequests, getAuthorization);
exports.consumeAuthorizationRequests = consumeAuthorizationRequests;
//# sourceMappingURL=consumeAuthorizationRequests.js.map