"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.XRPImplementation = void 0;
const axios_1 = __importDefault(require("axios"));
const axios_rate_limit_1 = __importDefault(require("../axios-rate-limiter/axios-rate-limit"));
const XrpFullBlock_1 = require("../base-objects/fullBlocks/XrpFullBlock");
const globalSettings_1 = require("../global-settings/globalSettings");
const constants_1 = require("../utils/constants");
const errors_1 = require("../utils/errors");
const utils_1 = require("../utils/utils");
const xrpUtils_1 = require("../utils/xrpUtils");
const base_objects_1 = require("../base-objects");
const genericMccTypes_1 = require("../types/genericMccTypes");
const DEFAULT_TIMEOUT = 15000;
const DEFAULT_RATE_LIMIT_OPTIONS = {
    maxRPS: 5,
};
class XRPImplementation {
    constructor(createConfig) {
        var _a;
        const createAxiosConfig = {
            baseURL: createConfig.url,
            timeout: ((_a = createConfig.rateLimitOptions) === null || _a === void 0 ? void 0 : _a.timeoutMs) || DEFAULT_TIMEOUT,
            headers: { "Content-Type": "application/json", "x-apikey": createConfig.apiTokenKey || "" },
            validateStatus: function (status) {
                return (status >= 200 && status < 300) || status == 500;
            },
        };
        if (createConfig.username && createConfig.password) {
            createAxiosConfig.auth = {
                username: createConfig.username,
                password: createConfig.password,
            };
        }
        const client = axios_1.default.create(createAxiosConfig);
        this.client = (0, axios_rate_limit_1.default)(client, Object.assign(Object.assign({}, DEFAULT_RATE_LIMIT_OPTIONS), createConfig.rateLimitOptions));
        this.inRegTest = createConfig.inRegTest || false;
        this.chainType = genericMccTypes_1.ChainType.XRP;
    }
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    getBlockTips(height_gte) {
        throw new errors_1.mccError(errors_1.mccErrorCode.NotImplemented);
    }
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    getTopLiteBlocks(branch_len, read_main = true) {
        throw new errors_1.mccError(errors_1.mccErrorCode.NotImplemented);
    }
    // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
    listTransactions(options) {
        throw new errors_1.mccError(errors_1.mccErrorCode.NotImplemented);
    }
    /**
     * get NodeStatus object with information about node used to connect to underlying chain
     * @external_docs https://xrpl.org/server_state.html
     */
    async getNodeStatus() {
        const res = await this.client.post("", {
            method: "server_state",
            params: [],
        });
        (0, xrpUtils_1.xrp_ensure_data)(res.data);
        return new base_objects_1.XrpNodeStatus(res.data);
    }
    /**
     * Get the height of the block from which the underlying node holds the full history
     * @returns the block height of the first block in latest joined block set in node memory
     */
    async getBottomBlockHeight() {
        const res = await this.client.post("", {
            method: "server_state",
            params: [],
        });
        (0, xrpUtils_1.xrp_ensure_data)(res.data);
        try {
            const Ledgers = res.data.result.state.complete_ledgers.split(",").sort();
            return parseInt(Ledgers[Ledgers.length - 1].split("-")[0]);
        }
        catch (e) {
            throw new errors_1.mccOutsideError(e);
        }
    }
    ///////////////////////////////////////////////////////////////////////////////////////
    // Block methods //////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////
    async blockRequestBase(blockNumberOrHash, full) {
        const params = {
            transactions: true,
            expand: full,
            binary: false,
            owner_funds: full,
        };
        if (typeof blockNumberOrHash === "string") {
            if (constants_1.PREFIXED_STD_BLOCK_HASH_REGEX.test(blockNumberOrHash)) {
                blockNumberOrHash = (0, utils_1.unPrefix0x)(blockNumberOrHash);
            }
            params.ledger_hash = blockNumberOrHash;
        }
        else {
            params.ledger_index = blockNumberOrHash;
        }
        globalSettings_1.mccSettings.loggingCallback(`block number: ${blockNumberOrHash} `);
        return await this.client.post("", {
            method: "ledger",
            params: [params],
        });
    }
    async getFullBlock(blockNumberOrHash) {
        var _a;
        try {
            const res = await this.blockRequestBase(blockNumberOrHash, true);
            (0, xrpUtils_1.xrp_ensure_data)(res.data);
            return new XrpFullBlock_1.XrpFullBlock(res.data);
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
        }
        catch (e) {
            // TODO: Invalid block error message (unify errors)
            throw new errors_1.mccError(errors_1.mccErrorCode.InvalidBlock);
            if (((_a = e.response) === null || _a === void 0 ? void 0 : _a.status) === 400) {
                throw new errors_1.mccError(errors_1.mccErrorCode.InvalidBlock);
            }
            throw e;
        }
    }
    async getBlock(blockNumberOrHash) {
        var _a;
        try {
            const res = await this.blockRequestBase(blockNumberOrHash, false);
            (0, xrpUtils_1.xrp_ensure_data)(res.data);
            return new base_objects_1.XrpBlock(res.data);
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
        }
        catch (e) {
            // TODO: Invalid block error message (unify errors)
            throw new errors_1.mccError(errors_1.mccErrorCode.InvalidBlock);
            if (((_a = e.response) === null || _a === void 0 ? void 0 : _a.status) === 400) {
                throw new errors_1.mccError(errors_1.mccErrorCode.InvalidBlock);
            }
            throw e;
        }
    }
    getBlockHeader(blockNumberOrHash) {
        return this.getBlock(blockNumberOrHash);
    }
    async getBlockHeight() {
        // according to https://xrpl.org/basic-data-types.html#specifying-ledgers we must set ledger_index to "validated"
        const params = {
            ledger_index: "validated",
        };
        const res = await this.client.post("", {
            method: "ledger",
            params: [params],
        });
        (0, xrpUtils_1.xrp_ensure_data)(res.data);
        return res.data.result.ledger_index;
    }
    ///////////////////////////////////////////////////////////////////////////////////////
    // Transaction methods ////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////
    async getTransaction(txId, options) {
        if (constants_1.PREFIXED_STD_TXID_REGEX.test(txId)) {
            txId = (0, utils_1.unPrefix0x)(txId);
        }
        const binary = (options === null || options === void 0 ? void 0 : options.binary) || false;
        const min_block = (options === null || options === void 0 ? void 0 : options.min_block) || undefined;
        const max_block = (options === null || options === void 0 ? void 0 : options.max_block) || undefined;
        const params = {
            transaction: txId,
            binary: binary,
        };
        if (min_block)
            params.min_ledger = min_block;
        if (max_block)
            params.max_ledger = max_block;
        const res = await this.client.post("", {
            method: "tx",
            params: [params],
        });
        (0, xrpUtils_1.xrp_ensure_data)(res.data);
        return new base_objects_1.XrpTransaction(res.data);
    }
    ///////////////////////////////////////////////////////////////////////////////////////
    // Client specific methods ////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////
    /**
     *
     * @param account A unique identifier for the account, most commonly the account's Address.
     * @param upperBound either blockHash or block number for the upper bound (The information does not contain any changes from ledger versions newer than this one.)
     * @returns
     */
    async getAccountInfo(account, upperBound = "current") {
        const params = {
            account: account,
            signer_lists: true,
        };
        if (typeof upperBound === "number") {
            params.ledger_index = upperBound;
        }
        if (upperBound === "current") {
            params.ledger_index = upperBound;
        }
        else if (typeof upperBound === "string") {
            params.ledger_hash = upperBound;
        }
        // AccountInfoRequest
        globalSettings_1.mccSettings.loggingCallback("Call Params");
        globalSettings_1.mccSettings.loggingCallback((0, utils_1.mccJsonStringify)(params));
        const res = await this.client.post("", {
            method: "account_info",
            params: [params],
        });
        (0, xrpUtils_1.xrp_ensure_data)(res.data);
        return res.data;
    }
    async getAccountTransactions(account, lowerBound = -1, upperBound = -1) {
        const params = {
            account: account,
        };
        params.ledger_index_min = lowerBound;
        params.ledger_index_max = upperBound;
        globalSettings_1.mccSettings.loggingCallback((0, utils_1.mccJsonStringify)(params));
        const res = await this.client.post("", {
            method: "account_tx",
            params: [params],
        });
        (0, xrpUtils_1.xrp_ensure_data)(res.data);
        return res.data;
    }
}
exports.XRPImplementation = XRPImplementation;
//# sourceMappingURL=XrpRpcImplementation.js.map