"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const web3_eth_1 = __importDefault(require("web3-eth"));
const R = __importStar(require("ramda"));
const yup_1 = require("yup");
const Environment_1 = require("./Environment");
const ensure_1 = require("../guards/ensure");
exports.defaultOptions = {
    gasLimit: '8000000',
    gasPrice: '2000000000',
};
const checkIpc = endpoint => {
    const name = 'fs';
    const fs = typeof module !== 'undefined' && module.exports && require(name);
    try {
        fs.accessSync(endpoint, fs.constants.W_OK);
        return true;
    }
    catch (e) {
        // Swallow any potential error.
    }
    return false;
};
const makeWsProvider = endpoint => new web3_eth_1.default.providers.WebsocketProvider(endpoint);
const makeHttpProvider = endpoint => new web3_eth_1.default.providers.HttpProvider(endpoint);
const makeIpcProvider = endpoint => new web3_eth_1.default.providers.IpcProvider(endpoint);
const selectProvider = R.cond([
    [R.startsWith('ws'), makeWsProvider],
    [R.startsWith('http'), makeHttpProvider],
    [checkIpc, makeIpcProvider],
]);
const constructProvider = (endpoint, logger) => {
    const debug = logger('melon:protocol:utils:environment', Environment_1.LogLevels.DEBUG);
    debug('Endpoint', endpoint);
    yup_1.string()
        .url([
        `Invalid JSON RPC endpoint url: ${endpoint}.`,
        `Check your .env file or provide it explicitly`,
    ].join(''))
        .isValid(endpoint);
    const provider = selectProvider(endpoint);
    if (!provider) {
        throw new Error([
            `Can not construct provider from endpoint: ${endpoint}`,
            'HTTP, WS and IPC failed',
        ].join(''));
    }
    debug('Provider constructed', endpoint);
    return provider;
};
const dummyLogger = R.curryN(3, (namespace, level, ...msgs) => { });
exports.constructEnvironment = ({ endpoint = undefined, provider: givenProvider = undefined, deployment = undefined, logger = dummyLogger, wallet = undefined, track = Environment_1.Tracks.TESTING, options = exports.defaultOptions, }) => {
    ensure_1.ensure(Object.values(Environment_1.Tracks).includes(track), `Unknown track: ${track}. Possible tracks: ${Object.values(Environment_1.Tracks).join(', ')}`);
    ensure_1.ensure(!!endpoint || !!givenProvider, 'You need to provide either an endpoint or a provider instance.');
    logger('melon:protocol:utils:environment', Environment_1.LogLevels.DEBUG, 'Construct environment', { endpoint, provider: !!givenProvider, deployment, wallet, track, options });
    const provider = givenProvider || constructProvider(endpoint, logger);
    const eth = new web3_eth_1.default(provider);
    return {
        deployment,
        eth,
        logger,
        options,
        track,
        wallet,
    };
};
