"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.createSecurityToken = exports.prepareStorage = exports.getAuthorization = exports.prepareCreateSecurityToken = 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.internalTokenTypeToAssetType({ Custom: data[1] }, context);
};
exports.createRegisterCustomAssetTypeResolver = createRegisterCustomAssetTypeResolver;
/**
 * @hidden
 */
function prepareCreateSecurityToken(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context: { polymeshApi: { tx, query: { asset }, }, }, context, storage: { customTypeData }, } = this;
        const { ticker, name, totalSupply, isDivisible, tokenType, tokenIdentifiers = [], fundingRound, documents, requireInvestorUniqueness, } = args;
        const reservation = new internal_1.TickerReservation({ ticker }, context);
        const rawTicker = conversion_1.stringToTicker(ticker, context);
        const [{ status }, classicTicker] = yield Promise.all([
            reservation.details(),
            asset.classicTickers(rawTicker),
        ]);
        if (status === types_2.TickerReservationStatus.TokenCreated) {
            throw new internal_1.PolymeshError({
                code: types_2.ErrorCode.UnmetPrerequisite,
                message: `A Security Token with ticker "${ticker}" already exists`,
            });
        }
        if (status === types_2.TickerReservationStatus.Free) {
            throw new internal_1.PolymeshError({
                code: types_2.ErrorCode.UnmetPrerequisite,
                message: `You must first reserve ticker "${ticker}" in order to create a Security Token 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(tx.asset.registerCustomAssetType, { resolvers: [exports.createRegisterCustomAssetTypeResolver(context)] }, rawValue);
            }
            else {
                rawType = conversion_1.internalTokenTypeToAssetType({ Custom: id }, context);
            }
        }
        else {
            rawType = conversion_1.internalTokenTypeToAssetType(tokenType, context);
        }
        const rawName = conversion_1.stringToAssetName(name, context);
        const rawIsDivisible = conversion_1.booleanToBool(isDivisible, context);
        const rawIdentifiers = tokenIdentifiers.map(identifier => conversion_1.tokenIdentifierToAssetIdentifier(identifier, context));
        const rawFundingRound = fundingRound ? conversion_1.stringToFundingRoundName(fundingRound, context) : null;
        const rawDisableIu = conversion_1.booleanToBool(!requireInvestorUniqueness, context);
        let fee;
        // we waive any protocol fees
        const tokenCreatedInEthereum = classicTicker.isSome && conversion_1.boolToBoolean(classicTicker.unwrap().is_created);
        if (tokenCreatedInEthereum) {
            fee = new bignumber_js_1.default(0);
        }
        // TODO @shuffledex: refactoring with batching mechanism
        this.addTransaction(tx.asset.createAsset, { fee }, rawName, rawTicker, rawIsDivisible, rawType, rawIdentifiers, rawFundingRound, rawDisableIu);
        if (totalSupply && totalSupply.gt(0)) {
            const rawTotalSupply = conversion_1.numberToBalance(totalSupply, context, isDivisible);
            this.addTransaction(tx.asset.issue, {}, rawTicker, rawTotalSupply);
        }
        if (documents === null || documents === void 0 ? void 0 : documents.length) {
            const rawDocuments = documents.map(doc => conversion_1.tokenDocumentToDocument(doc, context));
            internal_2.batchArguments(rawDocuments, types_1.TxTags.asset.AddDocuments).forEach(rawDocumentBatch => {
                this.addTransaction(tx.asset.addDocuments, { isCritical: false, batchSize: rawDocumentBatch.length }, rawDocumentBatch, rawTicker);
            });
        }
        return new internal_1.SecurityToken({ ticker }, context);
    });
}
exports.prepareCreateSecurityToken = prepareCreateSecurityToken;
/**
 * @hidden
 */
function getAuthorization({ ticker, documents }) {
    const { storage: { customTypeData }, } = 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);
    }
    return {
        roles: [{ type: types_2.RoleType.TickerOwner, ticker }],
        permissions: {
            transactions,
            tokens: [],
            portfolios: [],
        },
    };
}
exports.getAuthorization = getAuthorization;
/**
 * @hidden
 */
function prepareStorage({ tokenType }) {
    return __awaiter(this, void 0, void 0, function* () {
        const { context } = this;
        const isCustomType = !lodash_1.values(types_2.KnownTokenType).includes(tokenType);
        if (isCustomType) {
            const rawValue = conversion_1.stringToBytes(tokenType, context);
            const id = yield context.polymeshApi.query.asset.customTypesInverse(rawValue);
            return {
                customTypeData: {
                    id,
                    rawValue,
                },
            };
        }
        return {
            customTypeData: null,
        };
    });
}
exports.prepareStorage = prepareStorage;
/**
 * @hidden
 */
const createSecurityToken = () => new internal_1.Procedure(prepareCreateSecurityToken, getAuthorization, prepareStorage);
exports.createSecurityToken = createSecurityToken;
//# sourceMappingURL=createSecurityToken.js.map