"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.createVectorClient = exports.VectorClient = void 0;
const vector_types_1 = require("@connext/vector-types");
const vector_utils_1 = require("@connext/vector-utils");
const fastify_1 = __importDefault(require("fastify"));
class VectorClient {
    constructor(options) {
        this.logger = options.logger;
        this.metrics = options.metrics;
        this.wallet = options.wallet;
        this.node = options.node;
        this.ethereum = options.ethereum;
        this.routerIdentifier = options.routerIdentifier;
        this.channelAddress = options.channelAddress;
    }
}
exports.VectorClient = VectorClient;
function createVectorClient(options) {
    var _a, _b;
    return __awaiter(this, void 0, void 0, function* () {
        const logger = options.logger.child({ component: 'VectorClient' });
        if (options.eventServer !== undefined) {
            // Start event server for subscribing to vector events
            const serverLogger = logger.child({ component: 'VectorEventServer' });
            serverLogger.info(`Start vector event server`);
            const server = fastify_1.default({
                logger: serverLogger.inner,
            });
            for (const eventType in options.eventServer.evts) {
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                const eventInfo = options.eventServer.evts[eventType];
                server.post(`/${eventType}`, (request, response) => __awaiter(this, void 0, void 0, function* () {
                    var _c;
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    (_c = eventInfo.evt) === null || _c === void 0 ? void 0 : _c.post(request.body);
                    return response.status(200).send({ message: 'success' });
                }));
            }
            try {
                const address = yield server.listen(options.eventServer.port, '0.0.0.0');
                serverLogger.info(`Listening`, { address });
            }
            catch (err) {
                serverLogger.error(`Failed to start vector event server`, { err });
                process.exit(1);
            }
        }
        // Connect to the vector node
        const evts = Object.assign({ [vector_types_1.EngineEvents.IS_ALIVE]: {}, [vector_types_1.EngineEvents.SETUP]: {}, [vector_types_1.EngineEvents.WITHDRAWAL_CREATED]: {}, [vector_types_1.EngineEvents.WITHDRAWAL_RESOLVED]: {}, [vector_types_1.EngineEvents.WITHDRAWAL_RECONCILED]: {}, [vector_types_1.EngineEvents.REQUEST_COLLATERAL]: {}, [vector_types_1.EngineEvents.RESTORE_STATE_EVENT]: {}, [vector_types_1.EngineEvents.CONDITIONAL_TRANSFER_CREATED]: {}, [vector_types_1.EngineEvents.CONDITIONAL_TRANSFER_RESOLVED]: {}, [vector_types_1.EngineEvents.DEPOSIT_RECONCILED]: {}, [vector_types_1.EngineEvents.TRANSACTION_SUBMITTED]: {}, [vector_types_1.EngineEvents.TRANSACTION_FAILED]: {}, [vector_types_1.EngineEvents.TRANSACTION_MINED]: {} }, (_a = options.eventServer) === null || _a === void 0 ? void 0 : _a.evts);
        logger.info(`Connect to vector node`, { url: options.nodeUrl });
        const node = yield vector_utils_1.RestServerNodeService.connect(options.nodeUrl, logger.inner, 
        // NOTE: Only one client can create a subscripton for the same public
        // identifier, so we need to be very careful not to subscribe with two
        // conflicting `evts` in service and agent;
        //
        // For now, we'll assume that service passes in no custom evts and
        // that the agent passes in some custom evts. The service will then pass
        // undefined to `connect()`, which shouldn't overwrite what the agent
        // subscribes to.
        ((_b = options.eventServer) === null || _b === void 0 ? void 0 : _b.evts) ? evts : undefined, 0);
        logger.info(`Successfully connected to vector node`);
        // Ensure there is a channel set up with the router
        logger.info(`Establish state channel with router`, {
            publicIdentifier: node.publicIdentifier,
            counterpartyIdentifier: options.routerIdentifier,
            chainId: options.ethereum.network.chainId,
        });
        let channelAddress;
        try {
            const value = (yield node.getStateChannelByParticipants({
                publicIdentifier: node.publicIdentifier,
                counterparty: options.routerIdentifier,
                chainId: options.ethereum.network.chainId,
            })).getValue();
            if (value === undefined) {
                throw new Error(`Channel between "${node.publicIdentifier}" and "${options.routerIdentifier}" does not exist`);
            }
            channelAddress = value.channelAddress;
        }
        catch (err) {
            try {
                const setupResult = (yield node.setup({
                    counterpartyIdentifier: options.routerIdentifier,
                    chainId: options.ethereum.network.chainId,
                    timeout: vector_types_1.DEFAULT_CHANNEL_TIMEOUT.toString(),
                })).getValue();
                const value = (yield node.getStateChannel({
                    channelAddress: setupResult.channelAddress,
                })).getValue();
                if (value === undefined) {
                    throw new Error(`Channel between "${node.publicIdentifier}" and "${options.routerIdentifier}" could not be set up`);
                }
                channelAddress = value.channelAddress;
            }
            catch (err) {
                logger.error(`Failed to set up state channel with router`, {
                    publicIdentifier: node.publicIdentifier,
                    counterpartyIdentifier: options.routerIdentifier,
                    chainId: options.ethereum.network.chainId,
                });
                throw err;
            }
        }
        return new VectorClient(Object.assign(Object.assign({}, options), { logger,
            node,
            channelAddress }));
    });
}
exports.createVectorClient = createVectorClient;
//# sourceMappingURL=vector-client.js.map