"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());
    });
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.configureDividendDistribution = exports.prepareStorage = exports.getAuthorization = exports.prepareConfigureDividendDistribution = exports.createDividendDistributionResolver = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const utils_1 = require("./utils");
const internal_1 = require("../../internal");
const types_1 = require("../../types");
const conversion_1 = require("../../utils/conversion");
const internal_2 = require("../../utils/internal");
/**
 * @hidden
 */
const createDividendDistributionResolver = (context) => (receipt) => __awaiter(void 0, void 0, void 0, function* () {
    const [{ data }] = internal_2.filterEventRecords(receipt, 'capitalDistribution', 'Created');
    const [, caId, distribution] = data;
    const { ticker, local_id: localId } = caId;
    const { corporateAction } = context.polymeshApi.query;
    const [corpAction, details] = yield Promise.all([
        corporateAction.corporateActions(ticker, localId),
        corporateAction.details(caId),
    ]);
    return new internal_1.DividendDistribution(Object.assign(Object.assign({ ticker: conversion_1.tickerToString(ticker), id: conversion_1.u32ToBigNumber(localId) }, conversion_1.meshCorporateActionToCorporateActionParams(corpAction.unwrap(), details, context)), conversion_1.distributionToDividendDistributionParams(distribution, context)), context);
});
exports.createDividendDistributionResolver = createDividendDistributionResolver;
/**
 * @hidden
 */
function prepareConfigureDividendDistribution(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context: { polymeshApi: { tx }, }, context, storage: { portfolio }, } = this;
        const { ticker, originPortfolio = null, currency, perShare, maxAmount, paymentDate, expiryDate = null, checkpoint } = args, corporateActionArgs = __rest(args, ["ticker", "originPortfolio", "currency", "perShare", "maxAmount", "paymentDate", "expiryDate", "checkpoint"]);
        if (currency === ticker) {
            throw new internal_1.PolymeshError({
                code: types_1.ErrorCode.ValidationError,
                message: 'Cannot distribute Dividends using the Asset as currency',
            });
        }
        if (paymentDate <= new Date()) {
            throw new internal_1.PolymeshError({
                code: types_1.ErrorCode.ValidationError,
                message: 'Payment date must be in the future',
            });
        }
        if (expiryDate && expiryDate < paymentDate) {
            throw new internal_1.PolymeshError({
                code: types_1.ErrorCode.ValidationError,
                message: 'Expiry date must be after payment date',
            });
        }
        const checkpointValue = yield internal_2.getCheckpointValue(checkpoint, ticker, context);
        if (!(checkpointValue instanceof internal_1.Checkpoint)) {
            yield utils_1.assertDistributionDatesValid(checkpointValue, paymentDate, expiryDate);
        }
        if (portfolio instanceof internal_1.NumberedPortfolio) {
            const exists = yield portfolio.exists();
            if (!exists) {
                throw new internal_1.PolymeshError({
                    code: types_1.ErrorCode.DataUnavailable,
                    message: "The origin Portfolio doesn't exist",
                });
            }
        }
        const [{ free }] = yield portfolio.getAssetBalances({ assets: [currency] });
        if (free.lt(maxAmount)) {
            throw new internal_1.PolymeshError({
                code: types_1.ErrorCode.InsufficientBalance,
                message: "The origin Portfolio's free balance is not enough to cover the Distribution amount",
                data: {
                    free,
                },
            });
        }
        const caId = yield this.addProcedure(internal_1.initiateCorporateAction(), Object.assign({ ticker, kind: types_1.CorporateActionKind.UnpredictableBenefit, checkpoint: checkpointValue }, corporateActionArgs));
        const rawPortfolioNumber = originPortfolio &&
            internal_2.optionize(conversion_1.bigNumberToU64)(originPortfolio instanceof bignumber_js_1.default ? originPortfolio : originPortfolio.id, context);
        const rawCurrency = conversion_1.stringToTicker(currency, context);
        const rawPerShare = conversion_1.bigNumberToBalance(perShare, context);
        const rawAmount = conversion_1.bigNumberToBalance(maxAmount, context);
        const rawPaymentAt = conversion_1.dateToMoment(paymentDate, context);
        const rawExpiresAt = internal_2.optionize(conversion_1.dateToMoment)(expiryDate, context);
        const [dividendDistribution] = this.addTransaction({
            transaction: tx.capitalDistribution.distribute,
            resolvers: [exports.createDividendDistributionResolver(context)],
            args: [
                caId,
                rawPortfolioNumber,
                rawCurrency,
                rawPerShare,
                rawAmount,
                rawPaymentAt,
                rawExpiresAt,
            ],
        });
        return dividendDistribution;
    });
}
exports.prepareConfigureDividendDistribution = prepareConfigureDividendDistribution;
/**
 * @hidden
 */
function getAuthorization({ ticker }) {
    const { storage: { portfolio }, context, } = this;
    return {
        roles: [{ type: types_1.RoleType.PortfolioCustodian, portfolioId: conversion_1.portfolioToPortfolioId(portfolio) }],
        permissions: {
            transactions: [types_1.TxTags.capitalDistribution.Distribute],
            assets: [new internal_1.Asset({ ticker }, context)],
            portfolios: [portfolio],
        },
    };
}
exports.getAuthorization = getAuthorization;
/**
 * @hidden
 */
function prepareStorage({ originPortfolio }) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context } = this;
        const { did } = yield context.getCurrentIdentity();
        let portfolio = originPortfolio || new internal_1.DefaultPortfolio({ did }, context);
        if (portfolio instanceof bignumber_js_1.default) {
            portfolio = new internal_1.NumberedPortfolio({ id: portfolio, did }, context);
        }
        return {
            portfolio,
        };
    });
}
exports.prepareStorage = prepareStorage;
/**
 * @hidden
 */
const configureDividendDistribution = () => new internal_1.Procedure(prepareConfigureDividendDistribution, getAuthorization, prepareStorage);
exports.configureDividendDistribution = configureDividendDistribution;
//# sourceMappingURL=configureDividendDistribution.js.map