"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 __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.launchOffering = exports.prepareStorage = exports.getAuthorization = exports.prepareLaunchOffering = exports.createOfferingResolver = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const bluebird_1 = __importDefault(require("bluebird"));
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 createOfferingResolver = (ticker, context) => (receipt) => {
    const [{ data }] = internal_2.filterEventRecords(receipt, 'sto', 'FundraiserCreated');
    const newFundraiserId = conversion_1.u64ToBigNumber(data[1]);
    return new internal_1.Offering({ id: newFundraiserId, ticker }, context);
};
exports.createOfferingResolver = createOfferingResolver;
/**
 * @hidden
 */
function prepareLaunchOffering(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context: { polymeshApi: { tx }, }, context, storage: { offeringPortfolioId, raisingPortfolioId }, } = this;
        const { ticker, raisingCurrency, venue, name, tiers, start, end, minInvestment } = args;
        const portfolio = conversion_1.portfolioIdToPortfolio(offeringPortfolioId, context);
        const [, , [{ free }]] = yield Promise.all([
            utils_1.assertPortfolioExists(offeringPortfolioId, context),
            utils_1.assertPortfolioExists(raisingPortfolioId, context),
            portfolio.getAssetBalances({
                assets: [ticker],
            }),
        ]);
        let venueId;
        if (venue) {
            const venueExists = yield venue.exists();
            if (venueExists) {
                ({ id: venueId } = venue);
            }
        }
        else {
            const offeringPortfolioOwner = new internal_1.Identity({ did: offeringPortfolioId.did }, context);
            const venues = yield offeringPortfolioOwner.getVenues();
            const offeringVenues = yield bluebird_1.default.filter(venues, (ownedVenue) => __awaiter(this, void 0, void 0, function* () {
                const details = yield ownedVenue.details();
                return details.type === types_1.VenueType.Sto;
            }));
            if (offeringVenues.length) {
                [{ id: venueId }] = offeringVenues;
            }
        }
        if (!venueId) {
            throw new internal_1.PolymeshError({
                code: types_1.ErrorCode.DataUnavailable,
                message: 'A valid Venue for the Offering was neither supplied nor found',
            });
        }
        const totalTierBalance = tiers.reduce((total, { amount }) => total.plus(amount), new bignumber_js_1.default(0));
        if (totalTierBalance.gt(free)) {
            throw new internal_1.PolymeshError({
                code: types_1.ErrorCode.InsufficientBalance,
                message: "There isn't enough free balance in the offering Portfolio",
                data: {
                    free,
                },
            });
        }
        const [sto] = this.addTransaction({
            transaction: tx.sto.createFundraiser,
            resolvers: [exports.createOfferingResolver(ticker, context)],
            args: [
                conversion_1.portfolioIdToMeshPortfolioId(offeringPortfolioId, context),
                conversion_1.stringToTicker(ticker, context),
                conversion_1.portfolioIdToMeshPortfolioId(raisingPortfolioId, context),
                conversion_1.stringToTicker(raisingCurrency, context),
                tiers.map(tier => conversion_1.stoTierToPriceTier(tier, context)),
                conversion_1.numberToU64(venueId, context),
                start ? conversion_1.dateToMoment(start, context) : null,
                end ? conversion_1.dateToMoment(end, context) : null,
                conversion_1.numberToBalance(minInvestment, context),
                conversion_1.stringToText(name, context),
            ],
        });
        return sto;
    });
}
exports.prepareLaunchOffering = prepareLaunchOffering;
/**
 * @hidden
 */
function getAuthorization({ ticker }) {
    const { storage: { offeringPortfolioId, raisingPortfolioId }, context, } = this;
    return {
        roles: [
            { type: types_1.RoleType.PortfolioCustodian, portfolioId: offeringPortfolioId },
            { type: types_1.RoleType.PortfolioCustodian, portfolioId: raisingPortfolioId },
        ],
        permissions: {
            transactions: [types_1.TxTags.sto.CreateFundraiser],
            assets: [new internal_1.Asset({ ticker }, context)],
            portfolios: [
                conversion_1.portfolioIdToPortfolio(offeringPortfolioId, context),
                conversion_1.portfolioIdToPortfolio(raisingPortfolioId, context),
            ],
        },
    };
}
exports.getAuthorization = getAuthorization;
/**
 * @hidden
 */
function prepareStorage({ offeringPortfolio, raisingPortfolio }) {
    return __awaiter(this, void 0, void 0, function* () {
        return {
            offeringPortfolioId: conversion_1.portfolioLikeToPortfolioId(offeringPortfolio),
            raisingPortfolioId: conversion_1.portfolioLikeToPortfolioId(raisingPortfolio),
        };
    });
}
exports.prepareStorage = prepareStorage;
/**
 * @hidden
 */
const launchOffering = () => new internal_1.Procedure(prepareLaunchOffering, getAuthorization, prepareStorage);
exports.launchOffering = launchOffering;
//# sourceMappingURL=launchOffering.js.map