"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 sinon_1 = __importDefault(require("sinon"));
const internal_1 = require("../../../internal");
const queries_1 = require("../../../middleware/queries");
const types_1 = require("../../../middleware/types");
const mocks_1 = require("../../../testUtils/mocks");
const types_2 = require("../../../types");
const utilsConversionModule = __importStar(require("../../../utils/conversion"));
const utilsInternalModule = __importStar(require("../../../utils/internal"));
jest.mock('~/base/Procedure', require("../../../testUtils/mocks/procedure").mockProcedureModule('~/base/Procedure'));
describe('Account class', () => {
    let context;
    let address;
    let key;
    let account;
    let assertFormatValidStub;
    let addressToKeyStub;
    beforeAll(() => {
        mocks_1.entityMockUtils.initMocks();
        mocks_1.dsMockUtils.initMocks();
        mocks_1.procedureMockUtils.initMocks();
        assertFormatValidStub = sinon_1.default.stub(utilsInternalModule, 'assertFormatValid');
        addressToKeyStub = sinon_1.default.stub(utilsConversionModule, 'addressToKey');
        address = 'someAddress';
        key = 'someKey';
    });
    beforeEach(() => {
        context = mocks_1.dsMockUtils.getContextInstance();
        account = new internal_1.Account({ address }, context);
    });
    afterEach(() => {
        mocks_1.entityMockUtils.reset();
        mocks_1.dsMockUtils.reset();
        mocks_1.procedureMockUtils.reset();
    });
    afterAll(() => {
        mocks_1.entityMockUtils.cleanup();
        mocks_1.dsMockUtils.cleanup();
        mocks_1.procedureMockUtils.cleanup();
        sinon_1.default.restore();
    });
    test('should extend Entity', () => {
        expect(internal_1.Account.prototype instanceof internal_1.Entity).toBe(true);
    });
    test('should throw an error if the supplied address is not encoded with the correct SS58 format', () => {
        assertFormatValidStub.throws();
        expect(() => {
            // eslint-disable-next-line no-new
            new internal_1.Account({ address: 'ajYMsCKsEAhEvHpeA4XqsfiA9v1CdzZPrCfS6pEfeGHW9j8' }, context);
        }).toThrow();
        sinon_1.default.reset();
    });
    describe('method: isUniqueIdentifiers', () => {
        test('should return true if the object conforms to the interface', () => {
            expect(internal_1.Account.isUniqueIdentifiers({ address: 'someAdddress' })).toBe(true);
            expect(internal_1.Account.isUniqueIdentifiers({})).toBe(false);
            expect(internal_1.Account.isUniqueIdentifiers({ address: 3 })).toBe(false);
        });
    });
    describe('method: getBalance', () => {
        let fakeResult;
        beforeAll(() => {
            fakeResult = {
                free: new bignumber_js_1.default(100),
                locked: new bignumber_js_1.default(10),
                total: new bignumber_js_1.default(110),
            };
        });
        beforeEach(() => {
            context = mocks_1.dsMockUtils.getContextInstance({ balance: fakeResult });
            account = new internal_1.Account({ address }, context);
        });
        test("should return the account's balance", () => __awaiter(void 0, void 0, void 0, function* () {
            const result = yield account.getBalance();
            expect(result).toEqual(fakeResult);
        }));
        test('should allow subscription', () => __awaiter(void 0, void 0, void 0, function* () {
            const unsubCallback = 'unsubCallback';
            const callback = sinon_1.default.stub();
            context.accountBalance.callsFake((_, cbFunc) => __awaiter(void 0, void 0, void 0, function* () {
                cbFunc(fakeResult);
                return unsubCallback;
            }));
            const result = yield account.getBalance(callback);
            expect(result).toEqual(unsubCallback);
            sinon_1.default.assert.calledWithExactly(callback, fakeResult);
        }));
    });
    describe('method: getSubsidy', () => {
        let fakeResult;
        beforeEach(() => {
            context = mocks_1.dsMockUtils.getContextInstance();
            account = new internal_1.Account({ address }, context);
            const subsidizer = new internal_1.Account({ address: 'subsidizer ' }, context);
            fakeResult = {
                allowance: new bignumber_js_1.default(1000),
                subsidizer,
            };
            context.accountSubsidy.resolves(fakeResult);
        });
        test("should return the account's balance", () => __awaiter(void 0, void 0, void 0, function* () {
            const result = yield account.getSubsidy();
            expect(result).toEqual(fakeResult);
        }));
        test('should allow subscription', () => __awaiter(void 0, void 0, void 0, function* () {
            const unsubCallback = 'unsubCallback';
            const callback = sinon_1.default.stub();
            context.accountSubsidy.callsFake((_, cbFunc) => __awaiter(void 0, void 0, void 0, function* () {
                cbFunc(fakeResult);
                return unsubCallback;
            }));
            const result = yield account.getSubsidy(callback);
            expect(result).toEqual(unsubCallback);
            sinon_1.default.assert.calledWithExactly(callback, fakeResult);
        }));
    });
    describe('method: getIdentity', () => {
        test('should return the Identity associated to the Account', () => __awaiter(void 0, void 0, void 0, function* () {
            const did = 'someDid';
            mocks_1.dsMockUtils.createQueryStub('identity', 'keyToIdentityIds', {
                returnValue: mocks_1.dsMockUtils.createMockIdentityId(did),
            });
            const result = yield account.getIdentity();
            expect(result === null || result === void 0 ? void 0 : result.did).toBe(did);
        }));
        test('should return null if there is no Identity associated to the Account', () => __awaiter(void 0, void 0, void 0, function* () {
            mocks_1.dsMockUtils.createQueryStub('identity', 'keyToIdentityIds', {
                returnValue: mocks_1.dsMockUtils.createMockIdentityId(),
            });
            const result = yield account.getIdentity();
            expect(result).toBe(null);
        }));
    });
    describe('method: getTransactionHistory', () => {
        test('should return a list of transactions', () => __awaiter(void 0, void 0, void 0, function* () {
            const tag = types_2.TxTags.identity.CddRegisterDid;
            const moduleId = types_1.ModuleIdEnum.Identity;
            const callId = types_1.CallIdEnum.CddRegisterDid;
            const blockNumber1 = new bignumber_js_1.default(1);
            const blockNumber2 = new bignumber_js_1.default(2);
            addressToKeyStub.returns(key);
            sinon_1.default.stub(utilsConversionModule, 'txTagToExtrinsicIdentifier').withArgs(tag).returns({
                moduleId,
                callId,
            });
            /* eslint-disable @typescript-eslint/naming-convention */
            const transactionsQueryResponse = {
                totalCount: 20,
                items: [
                    {
                        module_id: types_1.ModuleIdEnum.Asset,
                        call_id: types_1.CallIdEnum.RegisterTicker,
                        extrinsic_idx: 2,
                        spec_version_id: 2006,
                        params: [],
                        block_id: blockNumber1.toNumber(),
                        address,
                        success: 0,
                        signedby_address: 1,
                    },
                    {
                        module_id: types_1.ModuleIdEnum.Asset,
                        call_id: types_1.CallIdEnum.RegisterTicker,
                        extrinsic_idx: 2,
                        spec_version_id: 2006,
                        params: [],
                        block_id: blockNumber2.toNumber(),
                        success: 1,
                        signedby_address: 1,
                    },
                ],
            };
            /* eslint-enabled @typescript-eslint/naming-convention */
            mocks_1.dsMockUtils.configureMocks({ contextOptions: { withSeed: true } });
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.heartbeat(), true);
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.transactions({
                block_id: blockNumber1.toNumber(),
                address: key,
                module_id: moduleId,
                call_id: callId,
                success: undefined,
                count: 2,
                skip: 1,
                orderBy: undefined,
            }), {
                transactions: transactionsQueryResponse,
            });
            let result = yield account.getTransactionHistory({
                blockNumber: blockNumber1,
                tag,
                size: 2,
                start: 1,
            });
            expect(result.data[0].blockNumber).toEqual(blockNumber1);
            expect(result.data[1].blockNumber).toEqual(blockNumber2);
            expect(result.data[0].address).toEqual(address);
            expect(result.data[1].address).toBeNull();
            expect(result.data[0].success).toBeFalsy();
            expect(result.data[1].success).toBeTruthy();
            expect(result.count).toEqual(20);
            expect(result.next).toEqual(3);
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.transactions({
                block_id: undefined,
                address: key,
                module_id: undefined,
                call_id: undefined,
                success: undefined,
                count: undefined,
                skip: undefined,
                orderBy: undefined,
            }), {
                transactions: transactionsQueryResponse,
            });
            result = yield account.getTransactionHistory();
            expect(result.data[0].blockNumber).toEqual(blockNumber1);
            expect(result.data[0].address).toEqual(address);
            expect(result.data[0].success).toBeFalsy();
            expect(result.count).toEqual(20);
            expect(result.next).toBeNull();
        }));
    });
    describe('method: isFrozen', () => {
        test('should return if the Account is frozen or not', () => __awaiter(void 0, void 0, void 0, function* () {
            const keyToIdentityIdsStub = mocks_1.dsMockUtils.createQueryStub('identity', 'keyToIdentityIds');
            mocks_1.dsMockUtils.createQueryStub('identity', 'didRecords').returns(mocks_1.dsMockUtils.createMockDidRecord({
                primary_key: mocks_1.dsMockUtils.createMockAccountId(address),
                roles: [],
                secondary_keys: [],
            }));
            const isDidFrozenStub = mocks_1.dsMockUtils.createQueryStub('identity', 'isDidFrozen', {
                returnValue: mocks_1.dsMockUtils.createMockBool(false),
            });
            keyToIdentityIdsStub.returns(mocks_1.dsMockUtils.createMockIdentityId());
            let result = yield account.isFrozen();
            expect(result).toBe(false);
            keyToIdentityIdsStub.returns(mocks_1.dsMockUtils.createMockIdentityId(address));
            result = yield account.isFrozen();
            expect(result).toBe(false);
            const otherAddress = 'otherAddress';
            account = new internal_1.Account({ address: otherAddress }, context);
            result = yield account.isFrozen();
            expect(result).toBe(false);
            isDidFrozenStub.resolves(mocks_1.dsMockUtils.createMockBool(true));
            result = yield account.isFrozen();
            expect(result).toBe(true);
        }));
    });
    describe('method: toJson', () => {
        test('should return a human readable version of the entity', () => {
            expect(account.toJson()).toBe(account.address);
        });
    });
    describe('method: exists', () => {
        test('should return true', () => {
            return expect(account.exists()).resolves.toBe(true);
        });
    });
    describe('method: getPermissions', () => {
        test('should return full permissions if the account is the primary key', () => __awaiter(void 0, void 0, void 0, function* () {
            context = mocks_1.dsMockUtils.getContextInstance({ primaryKey: address });
            account = new internal_1.Account({ address }, context);
            const result = yield account.getPermissions();
            expect(result).toEqual({
                tokens: null,
                transactions: null,
                transactionGroups: [],
                portfolios: null,
            });
        }));
        test("should return the account's permissions if it is a secondary key", () => __awaiter(void 0, void 0, void 0, function* () {
            const permissions = {
                tokens: null,
                transactions: null,
                transactionGroups: [],
                portfolios: null,
            };
            context = mocks_1.dsMockUtils.getContextInstance({
                secondaryKeys: [
                    { signer: mocks_1.entityMockUtils.getAccountInstance({ address }), permissions },
                    {
                        signer: mocks_1.entityMockUtils.getAccountInstance({ address: 'otherAddress' }),
                        permissions: {
                            tokens: null,
                            transactions: {
                                values: [types_2.TxTags.identity.AcceptPrimaryKey],
                                type: types_2.PermissionType.Include,
                            },
                            transactionGroups: [],
                            portfolios: null,
                        },
                    },
                ],
            });
            account = new internal_1.Account({ address }, context);
            const result = yield account.getPermissions();
            expect(result).toEqual(permissions);
        }));
    });
    describe('method: hasPermissions', () => {
        test('should return whether the Account has the passed permissions', () => __awaiter(void 0, void 0, void 0, function* () {
            context = mocks_1.dsMockUtils.getContextInstance({ primaryKey: address });
            account = new internal_1.Account({ address }, context);
            let result = yield account.hasPermissions({ tokens: [], portfolios: [], transactions: [] });
            expect(result).toEqual(true);
            let permissions = {
                tokens: null,
                transactions: null,
                transactionGroups: [],
                portfolios: null,
            };
            context = mocks_1.dsMockUtils.getContextInstance({
                secondaryKeys: [{ signer: mocks_1.entityMockUtils.getAccountInstance({ address }), permissions }],
            });
            account = new internal_1.Account({ address }, context);
            result = yield account.hasPermissions({ tokens: null, portfolios: null, transactions: null });
            expect(result).toEqual(true);
            const token = mocks_1.entityMockUtils.getSecurityTokenInstance({ ticker: 'SOME_TOKEN' });
            permissions = {
                tokens: { values: [token], type: types_2.PermissionType.Include },
                transactions: { values: [types_2.TxTags.asset.CreateAsset], type: types_2.PermissionType.Include },
                transactionGroups: [],
                portfolios: {
                    values: [mocks_1.entityMockUtils.getDefaultPortfolioInstance({ did: 'someDid' })],
                    type: types_2.PermissionType.Include,
                },
            };
            context = mocks_1.dsMockUtils.getContextInstance({
                secondaryKeys: [{ signer: mocks_1.entityMockUtils.getAccountInstance({ address }), permissions }],
            });
            account = new internal_1.Account({ address }, context);
            result = yield account.hasPermissions({
                tokens: [token],
                portfolios: [mocks_1.entityMockUtils.getDefaultPortfolioInstance({ did: 'otherDid' })],
                transactions: [types_2.TxTags.asset.CreateAsset],
            });
            expect(result).toEqual(false);
            permissions = {
                tokens: { values: [token], type: types_2.PermissionType.Exclude },
                transactions: { values: [types_2.TxTags.asset.CreateAsset], type: types_2.PermissionType.Exclude },
                transactionGroups: [],
                portfolios: {
                    values: [mocks_1.entityMockUtils.getDefaultPortfolioInstance({ did: 'someDid' })],
                    type: types_2.PermissionType.Exclude,
                },
            };
            context = mocks_1.dsMockUtils.getContextInstance({
                secondaryKeys: [{ signer: mocks_1.entityMockUtils.getAccountInstance({ address }), permissions }],
            });
            account = new internal_1.Account({ address }, context);
            result = yield account.hasPermissions({
                tokens: [token],
                portfolios: null,
                transactions: null,
            });
            expect(result).toEqual(false);
            result = yield account.hasPermissions({
                tokens: null,
                portfolios: [],
                transactions: [types_2.TxTags.asset.CreateAsset],
            });
            expect(result).toEqual(false);
            result = yield account.hasPermissions({
                tokens: [],
                portfolios: [mocks_1.entityMockUtils.getDefaultPortfolioInstance({ did: 'otherDid' })],
                transactions: [],
            });
            expect(result).toEqual(true);
            result = yield account.hasPermissions({});
            expect(result).toEqual(true);
        }));
        test('should exempt certain transactions from requiring permissions', () => __awaiter(void 0, void 0, void 0, function* () {
            context = mocks_1.dsMockUtils.getContextInstance({ primaryKey: address });
            account = new internal_1.Account({ address }, context);
            const result = yield account.hasPermissions({
                tokens: [],
                portfolios: [],
                transactions: [
                    types_2.TxTags.balances.Transfer,
                    types_2.TxTags.balances.TransferWithMemo,
                    types_2.TxTags.staking.AddPermissionedValidator,
                    types_2.TxTags.sudo.SetKey,
                    types_2.TxTags.session.PurgeKeys,
                ],
            });
            expect(result).toEqual(true);
        }));
    });
    describe('method: leaveIdentity', () => {
        test('should prepare the procedure with the correct arguments and context, and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const expectedQueue = 'someQueue';
            const args = {
                account,
            };
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({ args, transformer: undefined }, context)
                .resolves(expectedQueue);
            const queue = yield account.leaveIdentity();
            expect(queue).toBe(expectedQueue);
        }));
    });
});
//# sourceMappingURL=Account.js.map