"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.createAsset = exports.prepareStorage = exports.getAuthorization = exports.prepareCreateAsset = exports.createRegisterCustomAssetTypeResolver = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const lodash_1 = require("lodash");
const types_1 = require("../../polkadot/types");
const internal_1 = require("../../internal");
const types_2 = require("../../types");
const conversion_1 = require("../../utils/conversion");
const internal_2 = require("../../utils/internal");
/**
 * @hidden
 */
const createRegisterCustomAssetTypeResolver = (context) => (receipt) => {
    const [{ data }] = internal_2.filterEventRecords(receipt, 'asset', 'CustomAssetTypeRegistered');
    return conversion_1.internalAssetTypeToAssetType({ Custom: data[1] }, context);
};
exports.createRegisterCustomAssetTypeResolver = createRegisterCustomAssetTypeResolver;
/**
 * @hidden
 */
function prepareCreateAsset(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context: { polymeshApi: { tx, query: { asset }, }, }, context, storage: { customTypeData, status }, } = this;
        const { ticker, name, initialSupply, isDivisible, assetType, securityIdentifiers = [], fundingRound, documents, requireInvestorUniqueness, reservationRequired, } = args;
        if (status === types_2.TickerReservationStatus.AssetCreated) {
            throw new internal_1.PolymeshError({
                code: types_2.ErrorCode.UnmetPrerequisite,
                message: `An Asset with ticker "${ticker}" already exists`,
            });
        }
        if (status === types_2.TickerReservationStatus.Free && reservationRequired) {
            throw new internal_1.PolymeshError({
                code: types_2.ErrorCode.UnmetPrerequisite,
                message: `You must first reserve ticker "${ticker}" in order to create an Asset with it`,
            });
        }
        let rawType;
        if (customTypeData) {
            const { rawValue, id } = customTypeData;
            if (id.isEmpty) {
                // if the custom asset type doesn't exist, we create it
                [rawType] = this.addTransaction({
                    transaction: tx.asset.registerCustomAssetType,
                    resolvers: [exports.createRegisterCustomAssetTypeResolver(context)],
                    args: [rawValue],
                });
            }
            else {
                rawType = conversion_1.internalAssetTypeToAssetType({ Custom: id }, context);
            }
        }
        else {
            rawType = conversion_1.internalAssetTypeToAssetType(assetType, context);
        }
        const rawName = conversion_1.stringToAssetName(name, context);
        const rawIsDivisible = conversion_1.booleanToBool(isDivisible, context);
        const rawIdentifiers = securityIdentifiers.map(identifier => conversion_1.securityIdentifierToAssetIdentifier(identifier, context));
        const rawFundingRound = fundingRound ? conversion_1.stringToFundingRoundName(fundingRound, context) : null;
        const rawDisableIu = conversion_1.booleanToBool(!requireInvestorUniqueness, context);
        let fee;
        const rawTicker = conversion_1.stringToTicker(ticker, context);
        // we waive any protocol fees if the Asset is created in Ethereum. If not created and ticker is not yet reserved, we set the fee to the sum of protocol fees for ticker registration and Asset creation.
        const classicTicker = yield asset.classicTickers(rawTicker);
        const assetCreatedInEthereum = classicTicker.isSome && conversion_1.boolToBoolean(classicTicker.unwrap().is_created);
        if (assetCreatedInEthereum) {
            fee = new bignumber_js_1.default(0);
        }
        else if (status === types_2.TickerReservationStatus.Free) {
            const [registerTickerFee, createAssetFee] = yield Promise.all([
                context.getProtocolFees({ tag: types_1.TxTags.asset.RegisterTicker }),
                context.getProtocolFees({ tag: types_1.TxTags.asset.CreateAsset }),
            ]);
            fee = registerTickerFee.plus(createAssetFee);
        }
        this.addTransaction({
            transaction: tx.asset.createAsset,
            fee,
            args: [
                rawName,
                rawTicker,
                rawIsDivisible,
                rawType,
                rawIdentifiers,
                rawFundingRound,
                rawDisableIu,
            ],
        });
        if (initialSupply && initialSupply.gt(0)) {
            const rawInitialSupply = conversion_1.bigNumberToBalance(initialSupply, context, isDivisible);
            this.addTransaction({
                transaction: tx.asset.issue,
                args: [rawTicker, rawInitialSupply],
            });
        }
        if (documents === null || documents === void 0 ? void 0 : documents.length) {
            const rawDocuments = documents.map(doc => conversion_1.assetDocumentToDocument(doc, context));
            internal_2.batchArguments(rawDocuments, types_1.TxTags.asset.AddDocuments).forEach(rawDocumentBatch => {
                this.addTransaction({
                    transaction: tx.asset.addDocuments,
                    isCritical: false,
                    feeMultiplier: new bignumber_js_1.default(rawDocumentBatch.length),
                    args: [rawDocumentBatch, rawTicker],
                });
            });
        }
        return new internal_1.Asset({ ticker }, context);
    });
}
exports.prepareCreateAsset = prepareCreateAsset;
/**
 * @hidden
 */
function getAuthorization({ ticker, documents }) {
    return __awaiter(this, void 0, void 0, function* () {
        const { storage: { customTypeData, status }, } = this;
        const transactions = [types_1.TxTags.asset.CreateAsset];
        if (documents === null || documents === void 0 ? void 0 : documents.length) {
            transactions.push(types_1.TxTags.asset.AddDocuments);
        }
        if (customTypeData === null || customTypeData === void 0 ? void 0 : customTypeData.id.isEmpty) {
            transactions.push(types_1.TxTags.asset.RegisterCustomAssetType);
        }
        const auth = {
            permissions: {
                transactions,
                assets: [],
                portfolios: [],
            },
        };
        if (status !== types_2.TickerReservationStatus.Free) {
            return Object.assign(Object.assign({}, auth), { roles: [{ type: types_2.RoleType.TickerOwner, ticker }] });
        }
        return auth;
    });
}
exports.getAuthorization = getAuthorization;
/**
 * @hidden
 */
function prepareStorage({ ticker, assetType }) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context } = this;
        const reservation = new internal_1.TickerReservation({ ticker }, context);
        const { status } = yield reservation.details();
        const isCustomType = !lodash_1.values(types_2.KnownAssetType).includes(assetType);
        if (isCustomType) {
            const rawValue = conversion_1.stringToBytes(assetType, context);
            const id = yield context.polymeshApi.query.asset.customTypesInverse(rawValue);
            return {
                customTypeData: {
                    id,
                    rawValue,
                },
                status,
            };
        }
        return {
            customTypeData: null,
            status,
        };
    });
}
exports.prepareStorage = prepareStorage;
/**
 * @hidden
 */
const createAsset = () => new internal_1.Procedure(prepareCreateAsset, getAuthorization, prepareStorage);
exports.createAsset = createAsset;
//# sourceMappingURL=createAsset.js.map