"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockttpClient = void 0;
const _ = require("lodash");
const mockttp_1 = require("../mockttp");
const admin_client_1 = require("./admin-client");
const mockttp_admin_request_builder_1 = require("./mockttp-admin-request-builder");
/**
 * A Mockttp implementation, controlling a remote Mockttp admin server.
 *
 * A MockttpClient supports the exact same Mockttp API as MockttpServer, but rather
 * than directly using Node.js APIs to start a mock server and rewrite traffic, it
 * makes calls to a remote admin server to start a mock server and rewrite traffic
 * there. This is useful to allow proxy configuration from inside browser tests, and
 * to allow creating mock proxies that run on remote machines.
 */
class MockttpClient extends mockttp_1.AbstractMockttp {
    constructor(options = {}) {
        super(_.defaults(options, {
            // Browser clients generally want cors enabled. For other clients, it doesn't hurt.
            // TODO: Maybe detect whether we're in a browser in future
            cors: true,
        }));
        this.reset = () => {
            return this.adminClient.reset();
        };
        this.addRequestRules = async (...rules) => {
            return this._addRequestRules(rules, false);
        };
        this.setRequestRules = async (...rules) => {
            return this._addRequestRules(rules, true);
        };
        this.addWebSocketRules = async (...rules) => {
            return this._addWsRules(rules, false);
        };
        this.setWebSocketRules = async (...rules) => {
            return this._addWsRules(rules, true);
        };
        this._addRequestRules = async (rules, reset) => {
            if (!this.requestBuilder)
                throw new Error('Cannot add rules before the server is started');
            const { adminStream } = this.adminClient;
            return this.adminClient.sendQuery(this.requestBuilder.buildAddRequestRulesQuery(rules, reset, adminStream));
        };
        this._addWsRules = async (rules, reset) => {
            if (!this.requestBuilder)
                throw new Error('Cannot add rules before the server is started');
            const { adminStream } = this.adminClient;
            return this.adminClient.sendQuery(this.requestBuilder.buildAddWebSocketRulesQuery(rules, reset, adminStream));
        };
        this.mockServerOptions = options;
        this.adminClient = new admin_client_1.AdminClient({
            adminServerUrl: options.adminServerUrl,
            requestOptions: options.client
        });
    }
    enableDebug() {
        return this.adminClient.enableDebug();
    }
    get url() {
        return this.adminClient.metadata.http.mockRoot;
    }
    get port() {
        return this.adminClient.metadata.http.port;
    }
    async start(port) {
        await this.adminClient.start({
            http: {
                port,
                options: this.mockServerOptions
            }
        });
        this.requestBuilder = new mockttp_admin_request_builder_1.MockttpAdminRequestBuilder(this.adminClient.schema);
    }
    stop() {
        return this.adminClient.stop();
    }
    async getMockedEndpoints() {
        if (!this.requestBuilder)
            throw new Error('Cannot query mocked endpoints before the server is started');
        return this.adminClient.sendQuery(this.requestBuilder.buildMockedEndpointsQuery());
    }
    async getPendingEndpoints() {
        if (!this.requestBuilder)
            throw new Error('Cannot query pending endpoints before the server is started');
        return this.adminClient.sendQuery(this.requestBuilder.buildPendingEndpointsQuery());
    }
    async getRuleParameterKeys() {
        return this.adminClient.getRuleParameterKeys();
    }
    on(event, callback) {
        if (event.startsWith('admin-client:')) {
            // All MockttpClient events come from the internal admin-client instance:
            this.adminClient.on(event.slice('admin-client:'.length), callback);
            return Promise.resolve();
        }
        if (!this.requestBuilder)
            throw new Error('Cannot subscribe to Mockttp events before the server is started');
        const subRequest = this.requestBuilder.buildSubscriptionRequest(event);
        if (!subRequest) {
            // We just return an immediately promise if we don't recognize the event, which will quietly
            // succeed but never call the corresponding callback (the same as the server and most event
            // sources in the same kind of situation). This is what happens when the *client* doesn't
            // recognize the event. Subscribe() below handles the unknown-to-server case.
            console.warn(`Ignoring subscription for event unrecognized by Mockttp client: ${event}`);
            return Promise.resolve();
        }
        return this.adminClient.subscribe(subRequest, callback);
    }
}
exports.MockttpClient = MockttpClient;
//# sourceMappingURL=mockttp-client.js.map