"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
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 });
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const types_1 = require("../../../polkadot/types");
const sinon_1 = __importDefault(require("sinon"));
const modifyClaims_1 = require("../modifyClaims");
const internal_1 = require("../../../internal");
const queries_1 = require("../../../middleware/queries");
const mocks_1 = require("../../../testUtils/mocks");
const types_2 = require("../../../types");
const internal_2 = require("../../../types/internal");
const utilsConversionModule = __importStar(require("../../../utils/conversion"));
describe('modifyClaims procedure', () => {
    let mockContext;
    let claimToMeshClaimStub;
    let dateToMomentStub;
    let identityIdToStringStub;
    let stringToIdentityIdStub;
    let addBatchTransactionStub;
    let addClaimTransaction;
    let revokeClaimTransaction;
    let balanceToBigNumberStub;
    let someDid;
    let otherDid;
    let cddId;
    let cddClaim;
    let buyLockupClaim;
    let iuClaim;
    let expiry;
    let args;
    let rawCddClaim;
    let rawBuyLockupClaim;
    let rawIuClaim;
    let rawSomeDid;
    let rawOtherDid;
    let rawExpiry;
    const includeExpired = true;
    beforeAll(() => {
        mocks_1.entityMockUtils.initMocks();
        mocks_1.procedureMockUtils.initMocks();
        mocks_1.dsMockUtils.initMocks();
        claimToMeshClaimStub = sinon_1.default.stub(utilsConversionModule, 'claimToMeshClaim');
        dateToMomentStub = sinon_1.default.stub(utilsConversionModule, 'dateToMoment');
        identityIdToStringStub = sinon_1.default.stub(utilsConversionModule, 'identityIdToString');
        stringToIdentityIdStub = sinon_1.default.stub(utilsConversionModule, 'stringToIdentityId');
        balanceToBigNumberStub = sinon_1.default.stub(utilsConversionModule, 'balanceToBigNumber');
        sinon_1.default.stub(utilsConversionModule, 'stringToTicker');
        sinon_1.default.stub(utilsConversionModule, 'stringToScopeId');
        someDid = 'someDid';
        otherDid = 'otherDid';
        cddId = 'cddId';
        cddClaim = { type: types_2.ClaimType.CustomerDueDiligence, id: cddId };
        iuClaim = {
            type: types_2.ClaimType.InvestorUniqueness,
            scope: {
                type: types_2.ScopeType.Ticker,
                value: 'SOME_TICKER',
            },
            cddId: 'someCddId',
            scopeId: 'someScopeId',
        };
        buyLockupClaim = {
            type: types_2.ClaimType.BuyLockup,
            scope: { type: types_2.ScopeType.Identity, value: 'someIdentityId' },
        };
        expiry = new Date();
        args = {
            claims: [
                {
                    target: someDid,
                    claim: cddClaim,
                },
                {
                    target: otherDid,
                    claim: cddClaim,
                },
                {
                    target: someDid,
                    claim: buyLockupClaim,
                    expiry,
                },
                {
                    target: someDid,
                    claim: iuClaim,
                },
            ],
            operation: internal_2.ClaimOperation.Add,
        };
        rawCddClaim = mocks_1.dsMockUtils.createMockClaim({
            CustomerDueDiligence: mocks_1.dsMockUtils.createMockCddId(),
        });
        rawBuyLockupClaim = mocks_1.dsMockUtils.createMockClaim({
            BuyLockup: mocks_1.dsMockUtils.createMockScope(),
        });
        rawIuClaim = mocks_1.dsMockUtils.createMockClaim({
            InvestorUniqueness: [
                mocks_1.dsMockUtils.createMockScope(),
                mocks_1.dsMockUtils.createMockScopeId(),
                mocks_1.dsMockUtils.createMockCddId(),
            ],
        });
        rawSomeDid = mocks_1.dsMockUtils.createMockIdentityId(someDid);
        rawOtherDid = mocks_1.dsMockUtils.createMockIdentityId(otherDid);
        rawExpiry = mocks_1.dsMockUtils.createMockMoment(expiry.getTime());
    });
    beforeEach(() => {
        addBatchTransactionStub = mocks_1.procedureMockUtils.getAddBatchTransactionStub();
        mockContext = mocks_1.dsMockUtils.getContextInstance();
        addClaimTransaction = mocks_1.dsMockUtils.createTxStub('identity', 'addClaim');
        revokeClaimTransaction = mocks_1.dsMockUtils.createTxStub('identity', 'revokeClaim');
        claimToMeshClaimStub.withArgs(cddClaim, mockContext).returns(rawCddClaim);
        claimToMeshClaimStub.withArgs(buyLockupClaim, mockContext).returns(rawBuyLockupClaim);
        claimToMeshClaimStub.withArgs(iuClaim, mockContext).returns(rawIuClaim);
        stringToIdentityIdStub.withArgs(someDid, mockContext).returns(rawSomeDid);
        stringToIdentityIdStub.withArgs(otherDid, mockContext).returns(rawOtherDid);
        dateToMomentStub.withArgs(expiry, mockContext).returns(rawExpiry);
        identityIdToStringStub.withArgs(rawOtherDid).returns(otherDid);
    });
    afterEach(() => {
        mocks_1.entityMockUtils.reset();
        mocks_1.procedureMockUtils.reset();
        mocks_1.dsMockUtils.reset();
    });
    afterAll(() => {
        mocks_1.entityMockUtils.cleanup();
        mocks_1.procedureMockUtils.cleanup();
        mocks_1.dsMockUtils.cleanup();
    });
    test("should throw an error if some of the supplied target dids don't exist", () => __awaiter(void 0, void 0, void 0, function* () {
        mocks_1.dsMockUtils.configureMocks({ contextOptions: { invalidDids: [otherDid] } });
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        let error;
        try {
            yield modifyClaims_1.prepareModifyClaims.call(proc, args);
        }
        catch (err) {
            error = err;
        }
        expect(error.message).toBe('Some of the supplied Identity IDs do not exist');
        expect(error.data).toMatchObject({ nonExistentDids: [otherDid] });
    }));
    describe('groupByDid', () => {
        test('should return the DID of the target identity', () => {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            expect(modifyClaims_1.groupByDid([rawOtherDid])).toBe(otherDid);
        });
    });
    test('should add a batch of add claim transactions to the queue', () => __awaiter(void 0, void 0, void 0, function* () {
        mocks_1.dsMockUtils.configureMocks({
            contextOptions: {
                issuedClaims: {
                    data: [
                        {
                            target: new internal_1.Identity({ did: someDid }, mockContext),
                            issuer: 'issuerIdentity',
                            issuedAt: new Date(),
                            expiry: null,
                            claim: cddClaim,
                        },
                    ],
                    next: 1,
                    count: 1,
                },
            },
        });
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        const { did } = yield mockContext.getCurrentIdentity();
        yield modifyClaims_1.prepareModifyClaims.call(mocks_1.procedureMockUtils.getInstance(mockContext), {
            claims: [
                {
                    target: someDid,
                    claim: buyLockupClaim,
                    expiry,
                },
            ],
            operation: internal_2.ClaimOperation.Add,
        });
        sinon_1.default.assert.calledWith(addBatchTransactionStub, {
            transactions: [
                {
                    transaction: addClaimTransaction,
                    args: [rawSomeDid, rawBuyLockupClaim, rawExpiry],
                },
            ],
        });
        yield modifyClaims_1.prepareModifyClaims.call(proc, args);
        const rawAddClaimItems = [
            [rawSomeDid, rawCddClaim, null],
            [rawOtherDid, rawCddClaim, null],
            [rawSomeDid, rawBuyLockupClaim, rawExpiry],
            [rawSomeDid, rawIuClaim, null],
        ];
        sinon_1.default.assert.calledWith(addBatchTransactionStub, {
            transactions: rawAddClaimItems.map(item => ({
                transaction: addClaimTransaction,
                args: item,
            })),
        });
        sinon_1.default.resetHistory();
        mocks_1.dsMockUtils.createApolloQueryStub(queries_1.didsWithClaims({
            trustedClaimIssuers: [did],
            dids: [someDid, otherDid],
            includeExpired,
            count: 2,
        }), {
            didsWithClaims: {
                totalCount: 2,
                items: [
                    {
                        did: someDid,
                        claims: [cddClaim, buyLockupClaim, iuClaim],
                    },
                    {
                        did: otherDid,
                        claims: [cddClaim],
                    },
                ],
            },
        });
        yield modifyClaims_1.prepareModifyClaims.call(proc, Object.assign(Object.assign({}, args), { operation: internal_2.ClaimOperation.Edit }));
        sinon_1.default.assert.calledWith(addBatchTransactionStub, {
            transactions: rawAddClaimItems.map(item => ({
                transaction: addClaimTransaction,
                args: item,
            })),
        });
    }));
    test('should throw an error if any of the CDD IDs of the claims that will be added are not equal to the CDD ID of current CDD claims', () => __awaiter(void 0, void 0, void 0, function* () {
        const otherId = 'otherId';
        mocks_1.dsMockUtils.configureMocks({
            contextOptions: {
                issuedClaims: {
                    data: [
                        {
                            target: new internal_1.Identity({ did: someDid }, mockContext),
                            issuer: 'issuerIdentity',
                            issuedAt: new Date(),
                            expiry: null,
                            claim: { type: types_2.ClaimType.CustomerDueDiligence, id: otherId },
                        },
                    ],
                    next: 1,
                    count: 1,
                },
            },
        });
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        const { did } = yield mockContext.getCurrentIdentity();
        mocks_1.dsMockUtils.createApolloQueryStub(queries_1.didsWithClaims({
            trustedClaimIssuers: [did],
            dids: [someDid, otherDid],
            includeExpired,
            count: 2,
        }), {
            didsWithClaims: {
                totalCount: 2,
                items: [
                    {
                        did: someDid,
                        claims: [cddClaim, buyLockupClaim],
                    },
                    {
                        did: otherDid,
                        claims: [cddClaim],
                    },
                ],
            },
        });
        let error;
        try {
            yield modifyClaims_1.prepareModifyClaims.call(proc, {
                claims: [
                    {
                        target: someDid,
                        claim: cddClaim,
                    },
                    {
                        target: otherDid,
                        claim: cddClaim,
                    },
                    {
                        target: new internal_1.Identity({ did: someDid }, mockContext),
                        claim: cddClaim,
                    },
                ],
                operation: internal_2.ClaimOperation.Add,
            });
        }
        catch (err) {
            error = err;
        }
        expect(error.message).toBe('A target Identity cannot have CDD claims with different IDs');
        const { target: { did: targetDid }, currentCddId, newCddId, } = error.data.invalidCddClaims[0];
        expect(targetDid).toEqual(someDid);
        expect(currentCddId).toEqual(cddId);
        expect(newCddId).toEqual(otherId);
    }));
    test("should throw an error if any of the claims that will be modified weren't issued by the current Identity", () => __awaiter(void 0, void 0, void 0, function* () {
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        const { did } = yield mockContext.getCurrentIdentity();
        mocks_1.dsMockUtils.createApolloQueryStub(queries_1.didsWithClaims({
            trustedClaimIssuers: [did],
            dids: [someDid, otherDid],
            includeExpired,
            count: 2,
        }), {
            didsWithClaims: {
                totalCount: 0,
                items: [],
            },
        });
        yield expect(modifyClaims_1.prepareModifyClaims.call(proc, Object.assign(Object.assign({}, args), { operation: internal_2.ClaimOperation.Edit }))).rejects.toThrow(new RegExp("Attempt to edit claims that weren't issued by the current Identity"));
        return expect(modifyClaims_1.prepareModifyClaims.call(proc, Object.assign(Object.assign({}, args), { operation: internal_2.ClaimOperation.Revoke }))).rejects.toThrow(new RegExp("Attempt to revoke claims that weren't issued by the current Identity"));
    }));
    test('should throw an error if any Investor Uniqueness claim has balance in a revoke operation', () => __awaiter(void 0, void 0, void 0, function* () {
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        const { did } = yield mockContext.getCurrentIdentity();
        mocks_1.dsMockUtils.createApolloQueryStub(queries_1.didsWithClaims({
            trustedClaimIssuers: [did],
            dids: [someDid, otherDid],
            includeExpired,
            count: 2,
        }), {
            didsWithClaims: {
                totalCount: 2,
                items: [
                    {
                        did: someDid,
                        claims: [cddClaim, buyLockupClaim, iuClaim],
                    },
                    {
                        did: otherDid,
                        claims: [cddClaim],
                    },
                ],
            },
        });
        mocks_1.dsMockUtils.createQueryStub('asset', 'aggregateBalance');
        balanceToBigNumberStub.returns(new bignumber_js_1.default(1));
        return expect(modifyClaims_1.prepareModifyClaims.call(proc, Object.assign(Object.assign({}, args), { operation: internal_2.ClaimOperation.Revoke }))).rejects.toThrow(new RegExp('Attempt to revoke Investor Uniqueness claims from investors with positive balance'));
    }));
    test('should add a batch of revoke claim transactions to the queue', () => __awaiter(void 0, void 0, void 0, function* () {
        const proc = mocks_1.procedureMockUtils.getInstance(mockContext);
        const { did } = yield mockContext.getCurrentIdentity();
        mocks_1.dsMockUtils.createApolloQueryStub(queries_1.didsWithClaims({
            trustedClaimIssuers: [did],
            dids: [someDid, otherDid],
            includeExpired,
            count: 2,
        }), {
            didsWithClaims: {
                totalCount: 2,
                items: [
                    {
                        did: someDid,
                        claims: [cddClaim, buyLockupClaim, iuClaim],
                    },
                    {
                        did: otherDid,
                        claims: [cddClaim],
                    },
                ],
            },
        });
        mocks_1.dsMockUtils.createQueryStub('asset', 'aggregateBalance');
        balanceToBigNumberStub.returns(new bignumber_js_1.default(0));
        yield modifyClaims_1.prepareModifyClaims.call(proc, Object.assign(Object.assign({}, args), { operation: internal_2.ClaimOperation.Revoke }));
        const rawRevokeClaimItems = [
            [rawSomeDid, rawCddClaim],
            [rawOtherDid, rawCddClaim],
            [rawSomeDid, rawBuyLockupClaim],
            [rawSomeDid, rawIuClaim],
        ];
        sinon_1.default.assert.calledWith(addBatchTransactionStub, {
            transactions: rawRevokeClaimItems.map(item => ({
                transaction: revokeClaimTransaction,
                args: item,
            })),
        });
    }));
});
describe('getAuthorization', () => {
    test('should return the appropriate roles and permissions', () => {
        let args = {
            claims: [
                {
                    target: 'someDid',
                    claim: { type: types_2.ClaimType.CustomerDueDiligence },
                },
            ],
            operation: internal_2.ClaimOperation.Add,
        };
        expect(modifyClaims_1.getAuthorization(args)).toEqual({
            roles: [{ type: types_2.RoleType.CddProvider }],
            permissions: {
                assets: [],
                portfolios: [],
                transactions: [types_1.TxTags.identity.AddClaim],
            },
        });
        args = {
            claims: [
                {
                    target: 'someDid',
                    claim: {
                        type: types_2.ClaimType.Accredited,
                        scope: { type: types_2.ScopeType.Identity, value: 'someIdentityId' },
                    },
                },
            ],
            operation: internal_2.ClaimOperation.Revoke,
        };
        expect(modifyClaims_1.getAuthorization(args)).toEqual({
            permissions: {
                assets: [],
                portfolios: [],
                transactions: [types_1.TxTags.identity.RevokeClaim],
            },
        });
    });
});
//# sourceMappingURL=modifyClaims.js.map