"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.Network = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const internal_1 = require("../../internal");
const queries_1 = require("../../middleware/queries");
const constants_1 = require("../../utils/constants");
const conversion_1 = require("../../utils/conversion");
const internal_2 = require("../../utils/internal");
/**
 * Handles all Network related functionality, including querying for historical events from middleware
 */
class Network {
    /**
     * @hidden
     */
    constructor(context) {
        this.context = context;
        this.transferPolyx = (0, internal_2.createProcedureMethod)({ getProcedureAndArgs: args => [internal_1.transferPolyx, args] }, context);
    }
    /**
     * Retrieve the number of the latest block in the chain
     */
    getLatestBlock() {
        return this.context.getLatestBlock();
    }
    /**
     * Fetch the current network version (i.e. 3.1.0)
     */
    getVersion() {
        return __awaiter(this, void 0, void 0, function* () {
            return this.context.getNetworkVersion();
        });
    }
    /**
     * Retrieve the chain's SS58 format
     */
    getSs58Format() {
        return this.context.ss58Format;
    }
    /**
     * Retrieve information for the current network
     */
    getNetworkProperties() {
        return __awaiter(this, void 0, void 0, function* () {
            const { context: { polymeshApi: { runtimeVersion: { specVersion }, rpc: { system: { chain }, }, }, }, } = this;
            const name = yield chain();
            return {
                name: (0, conversion_1.textToString)(name),
                version: (0, conversion_1.u32ToBigNumber)(specVersion),
            };
        });
    }
    /**
     * Retrieve the protocol fees associated with running specific transactions
     *
     * @param args.tags - list of transaction tags (i.e. [TxTags.asset.CreateAsset, TxTags.asset.RegisterTicker] or ["asset.createAsset", "asset.registerTicker"])
     */
    getProtocolFees(args) {
        return this.context.getProtocolFees(args);
    }
    /**
     * Get the treasury wallet address
     */
    getTreasuryAccount() {
        const { context } = this;
        return new internal_1.Account({ address: (0, conversion_1.moduleAddressToString)(constants_1.TREASURY_MODULE_ADDRESS, context) }, context);
    }
    // eslint-disable-next-line require-jsdoc
    getTreasuryBalance(callback) {
        return __awaiter(this, void 0, void 0, function* () {
            const account = this.getTreasuryAccount();
            if (callback) {
                return account.getBalance(({ free: freeBalance }) => {
                    // eslint-disable-next-line @typescript-eslint/no-floating-promises -- callback errors should be handled by the caller
                    callback(freeBalance);
                });
            }
            const { free } = yield account.getBalance();
            return free;
        });
    }
    /**
     * Retrieve a single event by any of its indexed arguments. Can be filtered using parameters
     *
     * @param opts.moduleId - type of the module to fetch
     * @param opts.eventId - type of the event to fetch
     * @param opts.eventArg0 - event parameter value to filter by in position 0
     * @param opts.eventArg1 - event parameter value to filter by in position 1
     * @param opts.eventArg2 - event parameter value to filter by in position 2
     *
     * @note uses the middleware
     */
    getEventByIndexedArgs(opts) {
        return __awaiter(this, void 0, void 0, function* () {
            const { context } = this;
            const { moduleId, eventId, eventArg0, eventArg1, eventArg2 } = opts;
            const { data: { eventByIndexedArgs: event }, } = yield context.queryMiddleware((0, queries_1.eventByIndexedArgs)({
                moduleId,
                eventId,
                eventArg0,
                eventArg1,
                eventArg2,
            }));
            return (0, internal_2.optionize)(conversion_1.middlewareEventToEventIdentifier)(event);
        });
    }
    /**
     * Retrieve a list of events. Can be filtered using parameters
     *
     * @param opts.moduleId - type of the module to fetch
     * @param opts.eventId - type of the event to fetch
     * @param opts.eventArg0 - event parameter value to filter by in position 0
     * @param opts.eventArg1 - event parameter value to filter by in position 1
     * @param opts.eventArg2 - event parameter value to filter by in position 2
     * @param opts.size - page size
     * @param opts.start - page offset
     *
     * @note uses the middleware
     */
    getEventsByIndexedArgs(opts) {
        return __awaiter(this, void 0, void 0, function* () {
            const { context } = this;
            const { moduleId, eventId, eventArg0, eventArg1, eventArg2, size, start } = opts;
            const result = yield context.queryMiddleware((0, queries_1.eventsByIndexedArgs)({
                moduleId,
                eventId,
                eventArg0,
                eventArg1,
                eventArg2,
                count: size === null || size === void 0 ? void 0 : size.toNumber(),
                skip: start === null || start === void 0 ? void 0 : start.toNumber(),
            }));
            const { data: { eventsByIndexedArgs: events }, } = result;
            if (events) {
                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                return events.map(event => (0, conversion_1.middlewareEventToEventIdentifier)(event));
            }
            return null;
        });
    }
    /**
     * Retrieve a transaction by hash
     *
     * @param opts.txHash - hash of the transaction
     *
     * @note uses the middleware
     */
    getTransactionByHash(opts) {
        return __awaiter(this, void 0, void 0, function* () {
            const { context: { polymeshApi: { rpc: { chain: { getBlock }, payment: { queryInfo }, }, }, }, context, } = this;
            const { txHash: transactionHash } = opts;
            const result = yield context.queryMiddleware((0, queries_1.transactionByHash)({
                transactionHash,
            }));
            const { data: { transactionByHash: transaction }, } = result;
            if (transaction) {
                const { block_id: blockNumber, extrinsic_idx: extrinsicIdx, address: rawAddress, nonce, module_id: moduleId, call_id: callId, params, success: txSuccess, spec_version_id: specVersionId, extrinsic_hash: extrinsicHash, block, } = transaction;
                const txTag = (0, conversion_1.extrinsicIdentifierToTxTag)({ moduleId, callId });
                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                const blockHash = block.hash;
                const rawBlockHash = (0, conversion_1.stringToBlockHash)(blockHash, context);
                const { block: { extrinsics }, } = yield getBlock(rawBlockHash);
                const [{ partialFee }, [{ fees: protocolFees }]] = yield Promise.all([
                    queryInfo(extrinsics[extrinsicIdx].toHex(), rawBlockHash),
                    context.getProtocolFees({ tags: [txTag], blockHash }),
                ]);
                return {
                    blockNumber: new bignumber_js_1.default(blockNumber),
                    blockHash,
                    extrinsicIdx: new bignumber_js_1.default(extrinsicIdx),
                    address: rawAddress !== null && rawAddress !== void 0 ? rawAddress : null,
                    nonce: nonce ? new bignumber_js_1.default(nonce) : null,
                    txTag,
                    params,
                    success: !!txSuccess,
                    specVersionId: new bignumber_js_1.default(specVersionId),
                    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                    extrinsicHash: extrinsicHash,
                    fee: {
                        gas: (0, conversion_1.balanceToBigNumber)(partialFee),
                        protocol: protocolFees,
                    },
                };
            }
            return null;
        });
    }
}
exports.Network = Network;
//# sourceMappingURL=Network.js.map