"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.modifyAssetTrustedClaimIssuers = exports.getAuthorization = exports.prepareModifyAssetTrustedClaimIssuers = void 0;
const lodash_1 = require("lodash");
const types_1 = require("../../polkadot/types");
const internal_1 = require("../../internal");
const types_2 = require("../../types");
const internal_2 = require("../../types/internal");
const utils_1 = require("../../types/utils");
const conversion_1 = require("../../utils/conversion");
const internal_3 = require("../../utils/internal");
const convertArgsToRaw = (claimIssuers, rawTicker, context) => {
    const claimIssuersToAdd = [];
    const inputDids = [];
    claimIssuers.forEach(({ identity, trustedFor }) => {
        let issuerIdentity;
        if (typeof identity === 'string') {
            issuerIdentity = new internal_1.Identity({ did: identity }, context);
        }
        else {
            issuerIdentity = identity;
        }
        claimIssuersToAdd.push(utils_1.tuple(rawTicker, conversion_1.trustedClaimIssuerToTrustedIssuer({ identity: issuerIdentity, trustedFor }, context)));
        inputDids.push(issuerIdentity.did);
    });
    return {
        claimIssuersToAdd,
        inputDids,
    };
};
const areSameClaimIssuers = (currentClaimIssuers, claimIssuers) => internal_3.hasSameElements(currentClaimIssuers, claimIssuers, ({ identity: aIdentity, trustedFor: aTrustedFor }, { identity: bIdentity, trustedFor: bTrustedFor }) => {
    const sameClaimTypes = (aTrustedFor === null && bTrustedFor === null) ||
        (aTrustedFor && bTrustedFor && lodash_1.isEqual(lodash_1.sortBy(aTrustedFor), lodash_1.sortBy(bTrustedFor)));
    return conversion_1.signerToString(aIdentity) === conversion_1.signerToString(bIdentity) && !!sameClaimTypes;
});
/**
 * @hidden
 */
function prepareModifyAssetTrustedClaimIssuers(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context: { polymeshApi: { query, tx }, }, context, } = this;
        const { ticker } = args;
        const rawTicker = conversion_1.stringToTicker(ticker, context);
        let claimIssuersToDelete = [];
        let claimIssuersToAdd = [];
        let inputDids;
        const rawCurrentClaimIssuers = yield query.complianceManager.trustedClaimIssuer(rawTicker);
        const currentClaimIssuers = rawCurrentClaimIssuers.map(issuer => conversion_1.trustedIssuerToTrustedClaimIssuer(issuer, context));
        const currentClaimIssuerDids = currentClaimIssuers.map(({ identity }) => conversion_1.signerToString(identity));
        if (args.operation === internal_2.TrustedClaimIssuerOperation.Remove) {
            inputDids = args.claimIssuers.map(conversion_1.signerToString);
            const notPresent = lodash_1.difference(inputDids, currentClaimIssuerDids);
            if (notPresent.length) {
                throw new internal_1.PolymeshError({
                    code: types_2.ErrorCode.UnmetPrerequisite,
                    message: 'One or more of the supplied Identities are not Trusted Claim Issuers',
                    data: {
                        notPresent,
                    },
                });
            }
            claimIssuersToDelete = currentClaimIssuers
                .filter(({ identity }) => inputDids.includes(conversion_1.signerToString(identity)))
                .map(({ identity }) => utils_1.tuple(rawTicker, conversion_1.stringToIdentityId(conversion_1.signerToString(identity), context)));
        }
        else {
            ({ claimIssuersToAdd, inputDids } = convertArgsToRaw(args.claimIssuers, rawTicker, context));
        }
        if (args.operation === internal_2.TrustedClaimIssuerOperation.Set) {
            claimIssuersToDelete = rawCurrentClaimIssuers.map(({ issuer }) => [rawTicker, issuer]);
            if (areSameClaimIssuers(currentClaimIssuers, args.claimIssuers)) {
                throw new internal_1.PolymeshError({
                    code: types_2.ErrorCode.NoDataChange,
                    message: 'The supplied claim issuer list is equal to the current one',
                });
            }
        }
        if (args.operation === internal_2.TrustedClaimIssuerOperation.Add) {
            const present = lodash_1.intersection(inputDids, currentClaimIssuerDids);
            if (present.length) {
                throw new internal_1.PolymeshError({
                    code: types_2.ErrorCode.UnmetPrerequisite,
                    message: 'One or more of the supplied Identities already are Trusted Claim Issuers',
                    data: {
                        present,
                    },
                });
            }
        }
        const nonExistentDids = yield context.getInvalidDids(inputDids);
        if (nonExistentDids.length) {
            throw new internal_1.PolymeshError({
                code: types_2.ErrorCode.DataUnavailable,
                message: 'Some of the supplied Identities do not exist',
                data: {
                    nonExistentDids,
                },
            });
        }
        const transactions = internal_3.assembleBatchTransactions(utils_1.tuple({
            transaction: tx.complianceManager.removeDefaultTrustedClaimIssuer,
            argsArray: claimIssuersToDelete,
        }, {
            transaction: tx.complianceManager.addDefaultTrustedClaimIssuer,
            argsArray: claimIssuersToAdd,
        }));
        this.addBatchTransaction({ transactions });
        return new internal_1.Asset({ ticker }, context);
    });
}
exports.prepareModifyAssetTrustedClaimIssuers = prepareModifyAssetTrustedClaimIssuers;
/**
 * @hidden
 */
function getAuthorization({ ticker, operation }) {
    const transactions = [];
    if (operation !== internal_2.TrustedClaimIssuerOperation.Add) {
        transactions.push(types_1.TxTags.complianceManager.RemoveDefaultTrustedClaimIssuer);
    }
    if (operation !== internal_2.TrustedClaimIssuerOperation.Remove) {
        transactions.push(types_1.TxTags.complianceManager.AddDefaultTrustedClaimIssuer);
    }
    return {
        permissions: {
            transactions,
            assets: [new internal_1.Asset({ ticker }, this.context)],
            portfolios: [],
        },
    };
}
exports.getAuthorization = getAuthorization;
/**
 * @hidden
 */
const modifyAssetTrustedClaimIssuers = () => new internal_1.Procedure(prepareModifyAssetTrustedClaimIssuers, getAuthorization);
exports.modifyAssetTrustedClaimIssuers = modifyAssetTrustedClaimIssuers;
//# sourceMappingURL=modifyAssetTrustedClaimIssuers.js.map