"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 mocks_1 = require("../../../../testUtils/mocks");
const types_1 = require("../../../../types");
const utilsConversionModule = __importStar(require("../../../../utils/conversion"));
jest.mock('~/api/entities/Identity', require("../../../../testUtils/mocks/entities").mockIdentityModule('~/api/entities/Identity'));
jest.mock('~/base/Procedure', require("../../../../testUtils/mocks/procedure").mockProcedureModule('~/base/Procedure'));
jest.mock('~/api/entities/Asset', require("../../../../testUtils/mocks/entities").mockAssetModule('~/api/entities/Asset'));
describe('DividendDistribution class', () => {
    let context;
    let id;
    let ticker;
    let declarationDate;
    let description;
    let targets;
    let defaultTaxWithholding;
    let taxWithholdings;
    let origin;
    let currency;
    let perShare;
    let maxAmount;
    let expiryDate;
    let paymentDate;
    let dividendDistribution;
    beforeAll(() => {
        mocks_1.dsMockUtils.initMocks();
        mocks_1.entityMockUtils.initMocks();
        mocks_1.procedureMockUtils.initMocks();
    });
    beforeEach(() => {
        context = mocks_1.dsMockUtils.getContextInstance();
        id = new bignumber_js_1.default(1);
        ticker = 'SOME_TICKER';
        declarationDate = new Date('10/14/1987 UTC');
        description = 'something';
        targets = {
            identities: [mocks_1.entityMockUtils.getIdentityInstance()],
            treatment: types_1.TargetTreatment.Include,
        };
        defaultTaxWithholding = new bignumber_js_1.default(10);
        taxWithholdings = [];
        origin = mocks_1.entityMockUtils.getDefaultPortfolioInstance();
        currency = 'USD';
        perShare = new bignumber_js_1.default(10);
        maxAmount = new bignumber_js_1.default(10000);
        expiryDate = null;
        paymentDate = new Date(new Date().getTime() + 60 * 60 * 24 * 365);
        dividendDistribution = new internal_1.DividendDistribution({
            id,
            ticker,
            declarationDate,
            description,
            targets,
            defaultTaxWithholding,
            taxWithholdings,
            origin,
            currency,
            perShare,
            maxAmount,
            expiryDate,
            paymentDate,
            kind: types_1.CorporateActionKind.UnpredictableBenefit,
        }, context);
        mocks_1.dsMockUtils.createQueryStub('capitalDistribution', 'distributions', {
            returnValue: mocks_1.dsMockUtils.createMockOption(mocks_1.dsMockUtils.createMockDistribution({
                /* eslint-disable @typescript-eslint/naming-convention */
                from: {
                    kind: 'Default',
                    did: 'someDid',
                },
                currency: 'USD',
                per_share: new bignumber_js_1.default(20000000),
                amount: new bignumber_js_1.default(50000000000),
                remaining: new bignumber_js_1.default(40000000000),
                payment_at: new bignumber_js_1.default(new Date(new Date().getTime() + 60 * 60 * 1000).getTime()),
                expires_at: null,
                reclaimed: false,
                /* eslint-enable @typescript-eslint/naming-convention */
            })),
        });
    });
    afterEach(() => {
        mocks_1.dsMockUtils.reset();
        mocks_1.entityMockUtils.reset();
        mocks_1.procedureMockUtils.reset();
    });
    afterAll(() => {
        mocks_1.dsMockUtils.cleanup();
        mocks_1.procedureMockUtils.cleanup();
    });
    test('should extend CorporateActionBase', () => {
        expect(internal_1.DividendDistribution.prototype instanceof internal_1.CorporateActionBase).toBe(true);
    });
    describe('constructor', () => {
        test('should assign parameters to instance', () => {
            expect(dividendDistribution.id).toEqual(id);
            expect(dividendDistribution.asset.ticker).toBe(ticker);
            expect(dividendDistribution.declarationDate).toEqual(declarationDate);
            expect(dividendDistribution.description).toEqual(description);
            expect(dividendDistribution.targets).toEqual(targets);
            expect(dividendDistribution.defaultTaxWithholding).toEqual(defaultTaxWithholding);
            expect(dividendDistribution.taxWithholdings).toEqual(taxWithholdings);
        });
    });
    describe('method: checkpoint', () => {
        test('should just pass the call down the line', () => __awaiter(void 0, void 0, void 0, function* () {
            const fakeResult = 'checkpoint';
            sinon_1.default.stub(internal_1.CorporateActionBase.prototype, 'checkpoint').resolves(fakeResult);
            const result = yield dividendDistribution.checkpoint();
            expect(result).toEqual(fakeResult);
        }));
        test('should throw an error if the Dividend Distribution does not exist', () => {
            mocks_1.dsMockUtils.createQueryStub('capitalDistribution', 'distributions', {
                returnValue: mocks_1.dsMockUtils.createMockOption(),
            });
            return expect(dividendDistribution.checkpoint()).rejects.toThrow('The Dividend Distribution no longer exists');
        });
    });
    describe('method: exists', () => {
        test('should return whether the Distribution exists', () => __awaiter(void 0, void 0, void 0, function* () {
            let result = yield dividendDistribution.exists();
            expect(result).toBe(true);
            mocks_1.dsMockUtils.createQueryStub('capitalDistribution', 'distributions', {
                returnValue: mocks_1.dsMockUtils.createMockOption(),
            });
            result = yield dividendDistribution.exists();
            expect(result).toBe(false);
        }));
    });
    describe('method: claim', () => {
        test('should prepare the procedure and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const expectedQueue = 'someQueue';
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({ args: { distribution: dividendDistribution }, transformer: undefined }, context)
                .resolves(expectedQueue);
            const queue = yield dividendDistribution.claim();
            expect(queue).toBe(expectedQueue);
        }));
    });
    describe('method: pay', () => {
        test('should prepare the procedure and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const expectedQueue = 'someQueue';
            const identityTargets = ['identityDid'];
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({
                args: { targets: identityTargets, distribution: dividendDistribution },
                transformer: undefined,
            }, context)
                .resolves(expectedQueue);
            const queue = yield dividendDistribution.pay({ targets: identityTargets });
            expect(queue).toBe(expectedQueue);
        }));
    });
    describe('method: details', () => {
        test('should return the distribution details', () => __awaiter(void 0, void 0, void 0, function* () {
            const result = yield dividendDistribution.details();
            expect(result).toEqual({
                remainingFunds: new bignumber_js_1.default(40000),
                fundsReclaimed: false,
            });
        }));
        test('should throw an error if the Dividend Distribution does not exist', () => __awaiter(void 0, void 0, void 0, function* () {
            mocks_1.dsMockUtils.createQueryStub('capitalDistribution', 'distributions', {
                returnValue: mocks_1.dsMockUtils.createMockOption(),
            });
            let err;
            try {
                yield dividendDistribution.details();
            }
            catch (error) {
                err = error;
            }
            expect(err.message).toBe('The Dividend Distribution no longer exists');
        }));
    });
    describe('method: modifyCheckpoint', () => {
        test('should prepare the procedure and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const expectedQueue = 'someQueue';
            const args = {
                checkpoint: new Date(),
            };
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({ args: Object.assign({ distribution: dividendDistribution }, args), transformer: undefined }, context)
                .resolves(expectedQueue);
            const queue = yield dividendDistribution.modifyCheckpoint(args);
            expect(queue).toBe(expectedQueue);
        }));
    });
    describe('method: getWithheldTax', () => {
        test('should return the amount of the withheld tax', () => __awaiter(void 0, void 0, void 0, function* () {
            const fakeTax = new bignumber_js_1.default(100);
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.getWithholdingTaxesOfCa({
                CAId: { ticker, localId: id.toNumber() },
            }), {
                getWithholdingTaxesOfCA: {
                    taxes: fakeTax.toNumber(),
                },
            });
            const result = yield dividendDistribution.getWithheldTax();
            expect(result).toEqual(fakeTax);
        }));
        test('should throw an error if the Dividend Distribution does not exist', () => {
            mocks_1.dsMockUtils.createQueryStub('capitalDistribution', 'distributions', {
                returnValue: mocks_1.dsMockUtils.createMockOption(),
            });
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.getWithholdingTaxesOfCa({
                CAId: { ticker, localId: id.toNumber() },
            }), {
                getWithholdingTaxesOfCA: {
                    taxes: 0,
                },
            });
            return expect(dividendDistribution.getWithheldTax()).rejects.toThrow('The Dividend Distribution no longer exists');
        });
    });
    describe('method: getParticipants', () => {
        test('should return the distribution participants', () => __awaiter(void 0, void 0, void 0, function* () {
            const excluded = mocks_1.entityMockUtils.getIdentityInstance({ did: 'excluded' });
            const balances = [
                {
                    identity: mocks_1.entityMockUtils.getIdentityInstance({ did: 'someDid' }),
                    balance: new bignumber_js_1.default(10000),
                },
                {
                    identity: mocks_1.entityMockUtils.getIdentityInstance({ did: 'otherDid' }),
                    balance: new bignumber_js_1.default(0),
                },
                {
                    identity: excluded,
                    balance: new bignumber_js_1.default(20000),
                },
            ];
            const allBalancesStub = sinon_1.default.stub();
            allBalancesStub.onFirstCall().resolves({ data: balances, next: 'notNull' });
            allBalancesStub.onSecondCall().resolves({ data: [], next: null });
            mocks_1.entityMockUtils.configureMocks({
                checkpointOptions: {
                    allBalances: allBalancesStub,
                },
            });
            dividendDistribution.targets = {
                identities: [excluded],
                treatment: types_1.TargetTreatment.Exclude,
            };
            sinon_1.default
                .stub(dividendDistribution, 'checkpoint')
                .resolves(mocks_1.entityMockUtils.getCheckpointInstance());
            mocks_1.dsMockUtils.createQueryStub('capitalDistribution', 'holderPaid', {
                multi: [mocks_1.dsMockUtils.createMockBool(true)],
            });
            let result = yield dividendDistribution.getParticipants();
            expect(result).toEqual([
                {
                    identity: balances[0].identity,
                    amount: balances[0].balance.multipliedBy(dividendDistribution.perShare),
                    paid: true,
                },
            ]);
            dividendDistribution.paymentDate = new Date('10/14/1987');
            allBalancesStub.onThirdCall().resolves({ data: balances, next: null });
            result = yield dividendDistribution.getParticipants();
            expect(result).toEqual([
                {
                    identity: balances[0].identity,
                    amount: balances[0].balance.multipliedBy(dividendDistribution.perShare),
                    paid: false,
                },
            ]);
        }));
        test("should return an empty array if the distribution checkpoint hasn't been created yet", () => __awaiter(void 0, void 0, void 0, function* () {
            sinon_1.default
                .stub(dividendDistribution, 'checkpoint')
                .resolves(mocks_1.entityMockUtils.getCheckpointScheduleInstance());
            const result = yield dividendDistribution.getParticipants();
            expect(result).toEqual([]);
        }));
    });
    describe('method: getParticipant', () => {
        test('should return the distribution participant', () => __awaiter(void 0, void 0, void 0, function* () {
            const did = 'someDid';
            const balance = new bignumber_js_1.default(100);
            const excluded = mocks_1.entityMockUtils.getIdentityInstance({ did: 'excluded' });
            dividendDistribution.targets = {
                identities: [excluded],
                treatment: types_1.TargetTreatment.Exclude,
            };
            sinon_1.default.stub(dividendDistribution, 'checkpoint').resolves(mocks_1.entityMockUtils.getCheckpointInstance({
                balance,
            }));
            sinon_1.default
                .stub(utilsConversionModule, 'stringToIdentityId')
                .returns(mocks_1.dsMockUtils.createMockIdentityId(did));
            /* eslint-disable @typescript-eslint/naming-convention */
            sinon_1.default
                .stub(utilsConversionModule, 'corporateActionIdentifierToCaId')
                .returns(mocks_1.dsMockUtils.createMockCAId({ ticker, local_id: id }));
            /* eslint-enable @typescript-eslint/naming-convention */
            sinon_1.default.stub(utilsConversionModule, 'boolToBoolean').returns(false);
            mocks_1.dsMockUtils.createQueryStub('capitalDistribution', 'holderPaid', {
                returnValue: false,
            });
            let result = yield dividendDistribution.getParticipant({
                identity: did,
            });
            expect(result === null || result === void 0 ? void 0 : result.identity.did).toBe(did);
            expect(result === null || result === void 0 ? void 0 : result.amount).toEqual(balance.multipliedBy(dividendDistribution.perShare));
            expect(result === null || result === void 0 ? void 0 : result.paid).toBe(false);
            dividendDistribution.paymentDate = new Date('10/14/1987');
            result = yield dividendDistribution.getParticipant({
                identity: did,
            });
            expect(result === null || result === void 0 ? void 0 : result.identity.did).toBe(did);
            expect(result === null || result === void 0 ? void 0 : result.amount).toEqual(balance.multipliedBy(dividendDistribution.perShare));
            expect(result === null || result === void 0 ? void 0 : result.paid).toBe(false);
            result = yield dividendDistribution.getParticipant();
            expect(result === null || result === void 0 ? void 0 : result.identity.did).toBe(did);
            expect(result === null || result === void 0 ? void 0 : result.amount).toEqual(balance.multipliedBy(dividendDistribution.perShare));
            expect(result === null || result === void 0 ? void 0 : result.paid).toBe(false);
        }));
        test("should return null if the distribution checkpoint hasn't been created yet", () => __awaiter(void 0, void 0, void 0, function* () {
            sinon_1.default
                .stub(dividendDistribution, 'checkpoint')
                .resolves(mocks_1.entityMockUtils.getCheckpointScheduleInstance());
            const result = yield dividendDistribution.getParticipant({
                identity: 'someDid',
            });
            expect(result).toEqual(null);
        }));
        test('should return null if the identity is excluded of the distribution', () => __awaiter(void 0, void 0, void 0, function* () {
            const did = 'someDid';
            const excluded = mocks_1.entityMockUtils.getIdentityInstance({ did });
            dividendDistribution.targets = {
                identities: [excluded],
                treatment: types_1.TargetTreatment.Exclude,
            };
            sinon_1.default.stub(dividendDistribution, 'checkpoint').resolves(mocks_1.entityMockUtils.getCheckpointInstance({
                balance: new bignumber_js_1.default(10),
            }));
            const result = yield dividendDistribution.getParticipant({
                identity: did,
            });
            expect(result).toEqual(null);
        }));
    });
    describe('method: reclaimFunds', () => {
        test('should prepare the procedure and return the resulting transaction queue', () => __awaiter(void 0, void 0, void 0, function* () {
            const expectedQueue = 'someQueue';
            mocks_1.procedureMockUtils
                .getPrepareStub()
                .withArgs({ args: { distribution: dividendDistribution }, transformer: undefined }, context)
                .resolves(expectedQueue);
            const queue = yield dividendDistribution.reclaimFunds();
            expect(queue).toBe(expectedQueue);
        }));
    });
    describe('method: getPaymentHistory', () => {
        test('should return the amount of the withheld tax', () => __awaiter(void 0, void 0, void 0, function* () {
            const blockId = new bignumber_js_1.default(1);
            const blockHash = 'someHash';
            const eventId = 'eventId';
            const datetime = '2020-10-10';
            const eventDid = 'eventDid';
            const balance = new bignumber_js_1.default(100);
            const tax = new bignumber_js_1.default(10);
            mocks_1.dsMockUtils.createQueryStub('system', 'blockHash', {
                multi: [mocks_1.dsMockUtils.createMockHash(blockHash)],
            });
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.getHistoryOfPaymentEventsForCa({
                CAId: { ticker, localId: id.toNumber() },
                fromDate: null,
                toDate: null,
                count: 1,
                skip: 0,
            }), {
                getHistoryOfPaymentEventsForCA: {
                    totalCount: 1,
                    items: [
                        {
                            blockId: blockId.toNumber(),
                            eventId,
                            datetime,
                            eventDid,
                            balance: balance.toNumber(),
                            tax: tax.toNumber(),
                        },
                    ],
                },
            });
            const { data: [result], } = yield dividendDistribution.getPaymentHistory({
                size: new bignumber_js_1.default(1),
                start: new bignumber_js_1.default(0),
            });
            expect(result.blockNumber).toEqual(blockId);
            expect(result.blockHash).toEqual(blockHash);
            expect(result.date).toEqual(new Date(`${datetime}Z`));
            expect(result.target.did).toBe(eventDid);
            expect(result.amount).toEqual(balance);
            expect(result.withheldTax).toEqual(tax);
        }));
        test('should return null if the query result is empty', () => __awaiter(void 0, void 0, void 0, function* () {
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.getHistoryOfPaymentEventsForCa({
                CAId: { ticker, localId: id.toNumber() },
                fromDate: null,
                toDate: null,
                count: undefined,
                skip: undefined,
            }), {
                getHistoryOfPaymentEventsForCA: {
                    totalCount: 0,
                    items: [],
                },
            });
            const result = yield dividendDistribution.getPaymentHistory();
            expect(result.data).toEqual([]);
            expect(result.next).toBeNull();
        }));
        test('should throw an error if the Dividend Distribution does not exist', () => {
            mocks_1.dsMockUtils.createQueryStub('capitalDistribution', 'distributions', {
                returnValue: mocks_1.dsMockUtils.createMockOption(),
            });
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.getHistoryOfPaymentEventsForCa({
                CAId: { ticker, localId: id.toNumber() },
                fromDate: null,
                toDate: null,
                count: undefined,
                skip: undefined,
            }), {
                getHistoryOfPaymentEventsForCA: {
                    totalCount: 0,
                    items: [],
                },
            });
            return expect(dividendDistribution.getPaymentHistory()).rejects.toThrow('The Dividend Distribution no longer exists');
        });
    });
    describe('method: toJson', () => {
        test('should return a human readable version of the entity', () => {
            dividendDistribution.targets = {
                treatment: types_1.TargetTreatment.Exclude,
                identities: [],
            };
            expect(dividendDistribution.toJson()).toEqual({
                id: '1',
                ticker: 'SOME_TICKER',
                declarationDate: '1987-10-14T00:00:00.000Z',
                defaultTaxWithholding: '10',
                description: 'something',
                targets: {
                    identities: [],
                    treatment: types_1.TargetTreatment.Exclude,
                },
                taxWithholdings: [],
                currency: 'USD',
                expiryDate: null,
                paymentDate: dividendDistribution.paymentDate.toISOString(),
                maxAmount: '10000',
                origin: { did: 'someDid' },
                perShare: '10',
            });
        });
    });
});
//# sourceMappingURL=index.js.map