"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsyncRPC = exports.RPC = void 0;
const request_1 = __importDefault(require("request"));
const Loggify_1 = require("./decorators/Loggify");
let RPC = class RPC {
    constructor(username, password, host, port, protocol = 'http') {
        this.username = username;
        this.password = password;
        this.host = host;
        this.port = port;
        this.protocol = protocol;
    }
    callMethod(method, params, callback, walletName) {
        const authString = this.username ? `${this.username}:${this.password}@` : '';
        const walletString = walletName ? '/wallet/' + walletName : '';
        (0, request_1.default)({
            method: 'POST',
            url: `${this.protocol}://${authString}${this.host}:${this.port}${walletString}`,
            body: {
                jsonrpc: '1.0',
                id: Date.now(),
                method,
                params
            },
            json: true
        }, (err, res) => {
            if (err) {
                return callback(err);
            }
            else if (res) {
                if (res.body) {
                    if (res.body.error) {
                        return callback(res.body.error);
                    }
                    else if (res.body.result) {
                        return callback(null, res.body && res.body.result);
                    }
                    else {
                        return callback({ msg: 'No error or body found', body: res.body });
                    }
                }
            }
            else {
                return callback('No response or error returned by rpc call');
            }
        });
    }
    async asyncCall(method, params, walletName) {
        return new Promise((resolve, reject) => {
            this.callMethod(method, params, (err, data) => {
                if (err) {
                    return reject(err);
                }
                return resolve(data);
            }, walletName);
        });
    }
    async getChainTip() {
        const tips = await this.asyncCall('getchaintips', []);
        return tips[0];
    }
    getBestBlockHash() {
        return this.asyncCall('getbestblockhash', []);
    }
    getBlockHeight() {
        return this.asyncCall('getblockcount', []);
    }
    getBlock(hash, verbosity) {
        return this.asyncCall('getblock', [hash, verbosity]);
    }
    getBlockHash(height) {
        return this.asyncCall('getblockhash', [height]);
    }
    async getBlockByHeight(height, verbosity) {
        const hash = await this.getBlockHash(height);
        return this.getBlock(hash, verbosity);
    }
    getTransaction(txid) {
        return this.asyncCall('getrawtransaction', [txid, true]);
    }
    sendTransaction(rawTx) {
        const txs = typeof rawTx === 'string' ? [rawTx] : rawTx;
        return this.asyncCall('sendrawtransaction', txs);
    }
    decodeScript(hex) {
        return this.asyncCall('decodescript', [hex]);
    }
    getWalletAddresses(account) {
        return this.asyncCall('getaddressesbyaccount', [account]);
    }
    async getEstimateSmartFee(target, mode) {
        const args = [target];
        if (mode) {
            args.push(mode);
        }
        return this.asyncCall('estimatesmartfee', args);
    }
    async getEstimateFee() {
        return this.asyncCall('estimatefee', []);
    }
};
exports.RPC = RPC;
exports.RPC = RPC = __decorate([
    Loggify_1.LoggifyClass
], RPC);
let AsyncRPC = class AsyncRPC {
    constructor(username, password, host, port, protocol) {
        this.rpc = new RPC(username, password, host, port, protocol);
        this.walletName = process.env.LOADED_MOCHA_OPTS === 'true' ? 'MOCHA_BITCORE_WALLET' : undefined;
    }
    async call(method, params, walletName) {
        return new Promise((resolve, reject) => {
            this.rpc.callMethod(method, params, (err, data) => {
                if (err) {
                    return reject(err);
                }
                return resolve(data);
            }, walletName);
        });
    }
    async setWallet(walletName) {
        if (!this.walletName && !walletName) {
            throw new Error('No wallet name specified');
        }
        if (this.walletName == walletName) {
            return;
        }
        walletName = walletName || this.walletName;
        try {
            await this.call('createwallet', [walletName]);
        }
        catch (err) {
            if (!err.message.includes('already exists')) {
                throw err;
            }
        }
        this.walletName = walletName;
    }
    async block(hash) {
        return (await this.call('getblock', [hash, 1]));
    }
    async verbose_block(hash) {
        return (await this.call('getblock', [hash, 2]));
    }
    async getnewaddress(account) {
        await this.setWallet();
        return (await this.call('getnewaddress', [account], this.walletName));
    }
    async signrawtx(txs) {
        await this.setWallet();
        try {
            const ret = await this.call('signrawtransactionwithwallet', [txs], this.walletName);
            return ret;
        }
        catch (e) {
            if (!e.code || e.code != -32601)
                return Promise.reject(e);
            return await this.call('signrawtransaction', [txs]);
        }
    }
    async transaction(txid, block) {
        const args = [txid, true];
        if (block) {
            args.push(block);
        }
        return (await this.call('getrawtransaction', args));
    }
    async sendtoaddress(address, value) {
        await this.setWallet();
        return this.call('sendtoaddress', [address, value], this.walletName);
    }
};
exports.AsyncRPC = AsyncRPC;
exports.AsyncRPC = AsyncRPC = __decorate([
    Loggify_1.LoggifyClass
], AsyncRPC);
//# sourceMappingURL=rpc.js.map