"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 utils_1 = require("../../../../types/utils");
const utilsConversionModule = __importStar(require("../../../../utils/conversion"));
jest.mock('~/api/entities/Identity', require("../../../../testUtils/mocks/entities").mockIdentityModule('~/api/entities/Identity'));
jest.mock('~/api/entities/NumberedPortfolio', require("../../../../testUtils/mocks/entities").mockNumberedPortfolioModule('~/api/entities/NumberedPortfolio'));
jest.mock('~/api/entities/DefaultPortfolio', require("../../../../testUtils/mocks/entities").mockDefaultPortfolioModule('~/api/entities/DefaultPortfolio'));
jest.mock('~/base/Procedure', require("../../../../testUtils/mocks/procedure").mockProcedureModule('~/base/Procedure'));
let exists;
// eslint-disable-next-line require-jsdoc
class NonAbstract extends internal_1.Portfolio {
    // eslint-disable-next-line require-jsdoc
    exists() {
        return __awaiter(this, void 0, void 0, function* () {
            return exists;
        });
    }
}
describe('Portfolio class', () => {
    let context;
    beforeAll(() => {
        mocks_1.dsMockUtils.initMocks();
        mocks_1.entityMockUtils.initMocks();
        mocks_1.procedureMockUtils.initMocks();
    });
    beforeEach(() => {
        context = mocks_1.dsMockUtils.getContextInstance();
        exists = true;
    });
    afterEach(() => {
        mocks_1.dsMockUtils.reset();
        mocks_1.entityMockUtils.reset();
        mocks_1.procedureMockUtils.reset();
    });
    afterAll(() => {
        mocks_1.dsMockUtils.cleanup();
        mocks_1.entityMockUtils.cleanup();
        mocks_1.procedureMockUtils.cleanup();
    });
    test('should extend Entity', () => {
        expect(internal_1.Portfolio.prototype instanceof internal_1.Entity).toBe(true);
    });
    describe('constructor', () => {
        test('should assign Identity to instance', () => {
            const did = 'someDid';
            const identity = mocks_1.entityMockUtils.getIdentityInstance({ did });
            const portfolio = new NonAbstract({ did }, context);
            expect(portfolio.owner).toEqual(identity);
        });
    });
    describe('method: isUniqueIdentifiers', () => {
        test('should return true if the object conforms to the interface', () => {
            expect(internal_1.Portfolio.isUniqueIdentifiers({ did: 'someDid', id: new bignumber_js_1.default(1) })).toBe(true);
            expect(internal_1.Portfolio.isUniqueIdentifiers({ did: 'someDid' })).toBe(true);
            expect(internal_1.Portfolio.isUniqueIdentifiers({})).toBe(false);
            expect(internal_1.Portfolio.isUniqueIdentifiers({ did: 'someDid', id: 3 })).toBe(false);
            expect(internal_1.Portfolio.isUniqueIdentifiers({ did: 1 })).toBe(false);
        });
    });
    describe('method: isOwnedBy', () => {
        let did;
        beforeAll(() => {
            did = 'currentIdentity';
            mocks_1.dsMockUtils.configureMocks({ contextOptions: { did } });
        });
        test('should return whether the current Identity is the Portfolio owner', () => __awaiter(void 0, void 0, void 0, function* () {
            let portfolio = new NonAbstract({ did }, context);
            let result = yield portfolio.isOwnedBy();
            expect(result).toBe(true);
            portfolio = new NonAbstract({ did: 'notTheCurrentIdentity' }, context);
            result = yield portfolio.isOwnedBy({ identity: did });
            expect(result).toBe(false);
        }));
    });
    describe('method: isCustodiedBy', () => {
        let did;
        let id;
        beforeAll(() => {
            did = 'someDid';
            id = new bignumber_js_1.default(1);
        });
        afterAll(() => {
            sinon_1.default.restore();
        });
        test('should return the custodian of the portfolio', () => __awaiter(void 0, void 0, void 0, function* () {
            const portfolio = new NonAbstract({ did, id }, context);
            const custodianDid = 'custodianDid';
            const currentIdentityDid = 'currentIdentity';
            const identityIdToStringStub = sinon_1.default.stub(utilsConversionModule, 'identityIdToString');
            const portfolioCustodianStub = mocks_1.dsMockUtils.createQueryStub('portfolio', 'portfolioCustodian');
            portfolioCustodianStub.returns(mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockIdentityId(custodianDid)));
            identityIdToStringStub.returns(custodianDid);
            let result = yield portfolio.isCustodiedBy();
            expect(result).toEqual(false);
            portfolioCustodianStub.returns(mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockIdentityId(currentIdentityDid)));
            identityIdToStringStub.returns(currentIdentityDid);
            result = yield portfolio.isCustodiedBy({ identity: currentIdentityDid });
            expect(result).toEqual(true);
        }));
    });
    describe('method: getTokenBalances', () => {
        let did;
        let id;
        let ticker0;
        let ticker1;
        let total0;
        let total1;
        let locked0;
        let locked1;
        let rawTicker0;
        let rawTicker1;
        let rawTotal0;
        let rawTotal1;
        let rawLocked0;
        let rawLocked1;
        let rawPortfolioId;
        beforeAll(() => {
            did = 'someDid';
            id = new bignumber_js_1.default(1);
            ticker0 = 'TICKER0';
            ticker1 = 'TICKER1';
            total0 = new bignumber_js_1.default(100);
            total1 = new bignumber_js_1.default(200);
            locked0 = new bignumber_js_1.default(50);
            locked1 = new bignumber_js_1.default(25);
            rawTicker0 = mocks_1.dsMockUtils.createMockTicker(ticker0);
            rawTicker1 = mocks_1.dsMockUtils.createMockTicker(ticker1);
            rawTotal0 = mocks_1.dsMockUtils.createMockBalance(total0.shiftedBy(6).toNumber());
            rawTotal1 = mocks_1.dsMockUtils.createMockBalance(total1.shiftedBy(6).toNumber());
            rawLocked0 = mocks_1.dsMockUtils.createMockBalance(locked0.shiftedBy(6).toNumber());
            rawLocked1 = mocks_1.dsMockUtils.createMockBalance(locked1.shiftedBy(6).toNumber());
            rawPortfolioId = mocks_1.dsMockUtils.createMockPortfolioId({
                did: mocks_1.dsMockUtils.createMockIdentityId(did),
                kind: mocks_1.dsMockUtils.createMockPortfolioKind({
                    User: mocks_1.dsMockUtils.createMockU64(id.toNumber()),
                }),
            });
            sinon_1.default.stub(utilsConversionModule, 'portfolioIdToMeshPortfolioId');
            mocks_1.dsMockUtils.configureMocks({ contextOptions: { did } });
        });
        beforeEach(() => {
            mocks_1.dsMockUtils.createQueryStub('portfolio', 'portfolioAssetBalances', {
                entries: [
                    utils_1.tuple([rawPortfolioId, rawTicker0], rawTotal0),
                    utils_1.tuple([rawPortfolioId, rawTicker1], rawTotal1),
                ],
            });
            mocks_1.dsMockUtils.createQueryStub('portfolio', 'portfolioLockedAssets', {
                entries: [
                    utils_1.tuple([rawPortfolioId, rawTicker0], rawLocked0),
                    utils_1.tuple([rawPortfolioId, rawTicker1], rawLocked1),
                ],
            });
        });
        afterAll(() => {
            sinon_1.default.restore();
        });
        test("should return all of the portfolio's assets and their balances", () => __awaiter(void 0, void 0, void 0, function* () {
            const portfolio = new NonAbstract({ did, id }, context);
            const result = yield portfolio.getTokenBalances();
            expect(result[0].token.ticker).toBe(ticker0);
            expect(result[0].total).toEqual(total0);
            expect(result[0].locked).toEqual(locked0);
            expect(result[0].free).toEqual(total0.minus(locked0));
            expect(result[1].token.ticker).toBe(ticker1);
            expect(result[1].total).toEqual(total1);
            expect(result[1].locked).toEqual(locked1);
            expect(result[1].free).toEqual(total1.minus(locked1));
        }));
        test('should return the requested portfolio assets and their balances', () => __awaiter(void 0, void 0, void 0, function* () {
            const portfolio = new NonAbstract({ did, id }, context);
            const otherTicker = 'OTHER_TICKER';
            const result = yield portfolio.getTokenBalances({
                tokens: [ticker0, new internal_1.SecurityToken({ ticker: otherTicker }, context)],
            });
            expect(result.length).toBe(2);
            expect(result[0].token.ticker).toBe(ticker0);
            expect(result[0].total).toEqual(total0);
            expect(result[0].locked).toEqual(locked0);
            expect(result[0].free).toEqual(total0.minus(locked0));
            expect(result[1].token.ticker).toBe(otherTicker);
            expect(result[1].total).toEqual(new bignumber_js_1.default(0));
            expect(result[1].locked).toEqual(new bignumber_js_1.default(0));
            expect(result[1].free).toEqual(new bignumber_js_1.default(0));
        }));
        test('should throw an error if the portfolio does not exist', () => {
            const portfolio = new NonAbstract({ did, id }, context);
            exists = false;
            return expect(portfolio.getTokenBalances()).rejects.toThrow('The Portfolio was removed and no longer exists');
        });
    });
    describe('method: getCustodian', () => {
        let did;
        let id;
        beforeAll(() => {
            did = 'someDid';
            id = new bignumber_js_1.default(1);
            sinon_1.default.stub(utilsConversionModule, 'portfolioIdToMeshPortfolioId');
        });
        afterAll(() => {
            sinon_1.default.restore();
        });
        test('should return the custodian of the portfolio', () => __awaiter(void 0, void 0, void 0, function* () {
            const custodianDid = 'custodianDid';
            const identityIdToStringStub = sinon_1.default.stub(utilsConversionModule, 'identityIdToString');
            mocks_1.dsMockUtils
                .createQueryStub('portfolio', 'portfolioCustodian')
                .returns(mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockIdentityId(custodianDid)));
            identityIdToStringStub.returns(custodianDid);
            const portfolio = new NonAbstract({ did, id }, context);
            let result = yield portfolio.getCustodian();
            expect(result.did).toEqual(custodianDid);
            mocks_1.dsMockUtils.createQueryStub('portfolio', 'portfolioCustodian').returns({});
            identityIdToStringStub.returns(did);
            result = yield portfolio.getCustodian();
            expect(result.did).toEqual(did);
        }));
        test('should throw an error if the portfolio does not exist', () => {
            const portfolio = new NonAbstract({ did, id }, context);
            exists = false;
            mocks_1.dsMockUtils.createQueryStub('portfolio', 'portfolioCustodian');
            return expect(portfolio.getCustodian()).rejects.toThrow('The Portfolio was removed and no longer exists');
        });
    });
    describe('method: moveFunds', () => {
        test('should prepare the procedure and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const args = {
                to: new internal_1.NumberedPortfolio({ id: new bignumber_js_1.default(1), did: 'someDid' }, context),
                items: [{ token: 'someToken', amount: new bignumber_js_1.default(100) }],
            };
            const portfolio = new NonAbstract({ did: 'someDid' }, context);
            const expectedQueue = 'someQueue';
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({ args: Object.assign(Object.assign({}, args), { from: portfolio }), transformer: undefined }, context)
                .resolves(expectedQueue);
            const queue = yield portfolio.moveFunds(args);
            expect(queue).toBe(expectedQueue);
        }));
    });
    describe('method: quitCustody', () => {
        test('should prepare the procedure and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const portfolio = new NonAbstract({ did: 'someDid' }, context);
            const expectedQueue = 'someQueue';
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({ args: { portfolio }, transformer: undefined }, context)
                .resolves(expectedQueue);
            const queue = yield portfolio.quitCustody();
            expect(queue).toBe(expectedQueue);
        }));
    });
    describe('method: setCustodian', () => {
        let did;
        let id;
        beforeAll(() => {
            did = 'someDid';
            id = new bignumber_js_1.default(1);
        });
        afterAll(() => {
            sinon_1.default.restore();
        });
        test('should prepare the procedure and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const portfolio = new NonAbstract({ id, did }, context);
            const targetIdentity = 'someTarget';
            const expectedQueue = 'someQueue';
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({ args: { id, did, targetIdentity }, transformer: undefined }, context)
                .resolves(expectedQueue);
            const queue = yield portfolio.setCustodian({ targetIdentity });
            expect(queue).toBe(expectedQueue);
        }));
    });
    describe('method: getTransactionHistory', () => {
        let did;
        let id;
        beforeAll(() => {
            did = 'someDid';
            id = new bignumber_js_1.default(1);
        });
        afterAll(() => {
            sinon_1.default.restore();
        });
        test('should return a list of transactions', () => __awaiter(void 0, void 0, void 0, function* () {
            let portfolio = new NonAbstract({ id, did }, context);
            const account = 'someAccount';
            const key = 'someKey';
            const blockNumber1 = new bignumber_js_1.default(1);
            const blockNumber2 = new bignumber_js_1.default(2);
            const blockHash1 = 'someHash';
            const blockHash2 = 'otherHash';
            const token1 = new internal_1.SecurityToken({ ticker: 'TICKER1' }, context);
            const amount1 = new bignumber_js_1.default(1000);
            const token2 = new internal_1.SecurityToken({ ticker: 'TICKER2' }, context);
            const amount2 = new bignumber_js_1.default(2000);
            const portfolioDid1 = 'somePortfolioDid';
            const portfolioKind1 = 'Default';
            const portfolioDid2 = 'somePortfolioDid2';
            const portfolioKind2 = '10';
            const portfolio1 = new internal_1.DefaultPortfolio({ did: portfolioDid1 }, context);
            const portfolio2 = new internal_1.NumberedPortfolio({ did: portfolioDid2, id: new bignumber_js_1.default(portfolioKind2) }, context);
            const leg1 = [
                {
                    ticker: token1.ticker,
                    amount: amount1.toString(),
                    direction: types_1.SettlementDirectionEnum.Incoming,
                    from: {
                        kind: portfolioKind1,
                        did: portfolioDid1,
                    },
                    to: {
                        kind: portfolioKind2,
                        did: portfolioDid2,
                    },
                },
            ];
            const leg2 = [
                {
                    ticker: token2.ticker,
                    amount: amount2.toString(),
                    direction: types_1.SettlementDirectionEnum.Outgoing,
                    from: {
                        kind: portfolioKind2,
                        did: portfolioDid2,
                    },
                    to: {
                        kind: portfolioKind1,
                        did: portfolioDid1,
                    },
                },
            ];
            /* eslint-disable @typescript-eslint/naming-convention */
            const transactionsQueryResponse = {
                totalCount: 20,
                items: [
                    {
                        block_id: blockNumber1.toNumber(),
                        addresses: ['be865155e5b6be843e99117a825e9580bb03e401a9c2ace644fff604fe624917'],
                        result: types_1.SettlementResultEnum.Executed,
                        legs: leg1,
                    },
                    {
                        block_id: blockNumber2.toNumber(),
                        addresses: ['be865155e5b6be843e99117a825e9580bb03e401a9c2ace644fff604fe624917'],
                        result: types_1.SettlementResultEnum.Executed,
                        legs: leg2,
                    },
                ],
            };
            /* eslint-enabled @typescript-eslint/naming-convention */
            mocks_1.dsMockUtils.configureMocks({ contextOptions: { withSeed: true } });
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.heartbeat(), true);
            sinon_1.default.stub(utilsConversionModule, 'addressToKey').withArgs(account, context).returns(key);
            mocks_1.dsMockUtils.createQueryStub('system', 'blockHash', {
                multi: [mocks_1.dsMockUtils.createMockHash(blockHash1), mocks_1.dsMockUtils.createMockHash(blockHash2)],
            });
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.settlements({
                identityId: did,
                portfolioNumber: id.toString(),
                addressFilter: key,
                tickerFilter: undefined,
                count: 5,
                skip: 0,
            }), {
                settlements: transactionsQueryResponse,
            });
            let result = yield portfolio.getTransactionHistory({
                account,
                size: 5,
                start: 0,
            });
            /* eslint-disable @typescript-eslint/no-non-null-assertion */
            expect(result.data[0].blockNumber).toEqual(blockNumber1);
            expect(result.data[1].blockNumber).toEqual(blockNumber2);
            expect(result.data[0].blockHash).toEqual(blockHash1);
            expect(result.data[1].blockHash).toEqual(blockHash2);
            expect(result.data[0].legs[0].token.ticker).toEqual(token1.ticker);
            expect(result.data[1].legs[0].token.ticker).toEqual(token2.ticker);
            expect(result.data[0].legs[0].amount).toEqual(amount1.div(Math.pow(10, 6)));
            expect(result.data[1].legs[0].amount).toEqual(amount2.div(Math.pow(10, 6)));
            expect(result.data[0].legs[0].from).toEqual(portfolio1);
            expect(result.data[0].legs[0].to).toEqual(portfolio2);
            expect(result.data[1].legs[0].from).toEqual(portfolio2);
            expect(result.data[1].legs[0].to).toEqual(portfolio1);
            expect(result.count).toEqual(20);
            expect(result.next).toEqual(5);
            /* eslint-enabled @typescript-eslint/no-non-null-assertion */
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.settlements({
                identityId: did,
                portfolioNumber: null,
                addressFilter: undefined,
                tickerFilter: undefined,
                count: undefined,
                skip: undefined,
            }), {
                settlements: {
                    totalCount: 0,
                    items: [],
                },
            });
            portfolio = new NonAbstract({ did }, context);
            result = yield portfolio.getTransactionHistory();
            expect(result.data).toEqual([]);
            expect(result.next).toBeNull();
        }));
        test('should throw an error if the portfolio does not exist', () => {
            const portfolio = new NonAbstract({ did, id }, context);
            exists = false;
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.heartbeat(), true);
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.settlements({
                identityId: did,
                portfolioNumber: null,
                addressFilter: undefined,
                tickerFilter: undefined,
                count: undefined,
                skip: undefined,
            }), {
                settlements: {
                    totalCount: 0,
                    items: null,
                },
            });
            return expect(portfolio.getTransactionHistory()).rejects.toThrow('The Portfolio was removed and no longer exists');
        });
    });
    describe('method: toJson', () => {
        test('should return a human readable version of the entity', () => {
            let portfolio = new NonAbstract({ did: 'someDid', id: new bignumber_js_1.default(1) }, context);
            expect(portfolio.toJson()).toEqual({
                did: 'someDid',
                id: '1',
            });
            portfolio = new NonAbstract({ did: 'someDid' }, context);
            expect(portfolio.toJson()).toEqual({
                did: 'someDid',
            });
        });
    });
});
//# sourceMappingURL=index.js.map