"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeConsumerAsyncMessagePact = exports.makeConsumerMessagePact = exports.makeConsumerPact = void 0;
const types_1 = require("../ffi/types");
const logger_1 = require("../logger");
const checkErrors_1 = require("./checkErrors");
const ffi_1 = require("../ffi");
const makeConsumerPact = (consumer, provider, version = 3, logLevel = logger_1.getLogLevel()) => {
    const ffi = ffi_1.getFfiLib(logLevel);
    if (logLevel) {
        logger_1.setLogLevel(logLevel);
    }
    const pactPtr = ffi.pactffiNewPact(consumer, provider);
    if (!ffi.pactffiWithSpecification(pactPtr, version)) {
        throw new Error(`Unable to set core spec version. The pact FfiSpecificationVersion '${version}' may be invalid (note this is not the same as the pact spec version)`);
    }
    return {
        addPlugin: (name, version) => {
            ffi.pactffiUsingPlugin(pactPtr, name, version);
        },
        cleanupPlugins: () => {
            ffi.pactffiCleanupPlugins(pactPtr);
        },
        createMockServer: (address, requestedPort, tls = false) => {
            const port = ffi.pactffiCreateMockServerForPact(pactPtr, `${address}:${requestedPort ? requestedPort : 0}`, tls);
            const error = Object.keys(types_1.CREATE_MOCK_SERVER_ERRORS).find((key) => types_1.CREATE_MOCK_SERVER_ERRORS[key] === port);
            if (error) {
                if (error === 'ADDRESS_NOT_VALID') {
                    logger_1.logErrorAndThrow(`Unable to start mock server at '${address}'. Is the address and port valid?`);
                }
                if (error === 'TLS_CONFIG') {
                    logger_1.logErrorAndThrow(`Unable to create TLS configuration with self-signed certificate`);
                }
                logger_1.logCrashAndThrow(`The pact core couldn\'t create the mock server because of an error described by '${error}'`);
            }
            if (port <= 0) {
                logger_1.logCrashAndThrow(`The pact core returned an unhandled error code '${port}'`);
            }
            return port;
        },
        mockServerMatchedSuccessfully: (port) => {
            return ffi.pactffiMockServerMatched(port);
        },
        mockServerMismatches: (port) => {
            return mockServerMismatches(ffi, port);
        },
        cleanupMockServer: (port) => {
            return checkErrors_1.wrapWithCheck((port) => ffi.pactffiCleanupMockServer(port), 'cleanupMockServer')(port);
        },
        writePactFile: (dir, merge = true) => writePact(ffi, pactPtr, dir, merge),
        writePactFileForPluginServer: (port, dir, merge = true) => writePact(ffi, pactPtr, dir, merge, port),
        addMetadata: (namespace, name, value) => {
            return ffi.pactffiWithPactMetadata(pactPtr, namespace, name, value);
        },
        newAsynchronousMessage: (description) => {
            const interactionPtr = ffi.pactffiNewAsyncMessage(pactPtr, description);
            return asyncMessage(ffi, interactionPtr);
        },
        newSynchronousMessage: (description) => {
            const interactionPtr = ffi.pactffiNewSyncMessage(pactPtr, description);
            return {
                withPluginRequestInteractionContents: (contentType, contents) => {
                    ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, contents);
                    return true;
                },
                withPluginResponseInteractionContents: (contentType, contents) => {
                    ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, contents);
                    return true;
                },
                withPluginRequestResponseInteractionContents: (contentType, contents) => {
                    ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, contents);
                    return true;
                },
                given: (state) => {
                    return ffi.pactffiGiven(interactionPtr, state);
                },
                givenWithParam: (state, name, value) => {
                    return ffi.pactffiGivenWithParam(interactionPtr, state, name, value);
                },
                withRequestContents: (body, contentType) => {
                    return ffi.pactffiWithBody(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, body);
                },
                withResponseContents: (body, contentType) => {
                    return ffi.pactffiWithBody(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, body);
                },
                withRequestBinaryContents: (body, contentType) => {
                    return ffi.pactffiWithBinaryFile(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, body, body.length);
                },
                withResponseBinaryContents: (body, contentType) => {
                    return ffi.pactffiWithBinaryFile(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, body, body.length);
                },
                withMetadata: (name, value) => {
                    return ffi.pactffiMessageWithMetadata(interactionPtr, name, value);
                },
            };
        },
        pactffiCreateMockServerForTransport(address, transport, config, port) {
            return ffi.pactffiCreateMockServerForTransport(pactPtr, address, port || 0, transport, config);
        },
        newInteraction: (description) => {
            const interactionPtr = ffi.pactffiNewInteraction(pactPtr, description);
            return checkErrors_1.wrapAllWithCheck({
                uponReceiving: (description) => {
                    return ffi.pactffiUponReceiving(interactionPtr, description);
                },
                given: (state) => {
                    return ffi.pactffiGiven(interactionPtr, state);
                },
                givenWithParam: (state, name, value) => {
                    return ffi.pactffiGivenWithParam(interactionPtr, state, name, value);
                },
                withRequest: (method, path) => {
                    return ffi.pactffiWithRequest(interactionPtr, method, path);
                },
                withQuery: (name, index, value) => {
                    return ffi.pactffiWithQueryParameter(interactionPtr, name, index, value);
                },
                withRequestHeader: (name, index, value) => {
                    return ffi.pactffiWithHeader(interactionPtr, types_1.INTERACTION_PART_REQUEST, name, index, value);
                },
                withRequestBody: (body, contentType) => {
                    return ffi.pactffiWithBody(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, body);
                },
                withRequestBinaryBody: (body, contentType) => {
                    return ffi.pactffiWithBinaryFile(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, body, body.length);
                },
                withRequestMultipartBody: (contentType, filename, mimePartName) => {
                    return (ffi.pactffiWithMultipartFile(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, filename, mimePartName) === undefined);
                },
                withResponseHeader: (name, index, value) => {
                    return ffi.pactffiWithHeader(interactionPtr, types_1.INTERACTION_PART_RESPONSE, name, index, value);
                },
                withResponseBody: (body, contentType) => {
                    return ffi.pactffiWithBody(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, body);
                },
                withResponseBinaryBody: (body, contentType) => {
                    return ffi.pactffiWithBinaryFile(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, body, body.length);
                },
                withResponseMultipartBody: (contentType, filename, mimePartName) => {
                    return (ffi.pactffiWithMultipartFile(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, filename, mimePartName) === undefined);
                },
                withStatus: (status) => {
                    return ffi.pactffiResponseStatus(interactionPtr, status);
                },
                withPluginRequestInteractionContents: (contentType, contents) => {
                    ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, contents);
                    return true;
                },
                withPluginRequestResponseInteractionContents: (contentType, contents) => {
                    ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, contents);
                    return true;
                },
                withPluginResponseInteractionContents: (contentType, contents) => {
                    ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, contents);
                    return true;
                },
            });
        },
    };
};
exports.makeConsumerPact = makeConsumerPact;
const makeConsumerMessagePact = (consumer, provider, version = 4, logLevel = logger_1.getLogLevel()) => {
    const ffi = ffi_1.getFfiLib(logLevel);
    if (logLevel) {
        logger_1.setLogLevel(logLevel);
    }
    const pactPtr = ffi.pactffiNewPact(consumer, provider);
    if (!ffi.pactffiWithSpecification(pactPtr, version) || version < 4) {
        throw new Error(`Unable to set core spec version. The pact FfiSpecificationVersion '${version}' may be invalid (note this is not the same as the pact spec version). It should be set to at least 3`);
    }
    return {
        addPlugin: (name, version) => {
            ffi.pactffiUsingPlugin(pactPtr, name, version);
        },
        cleanupPlugins: () => {
            ffi.pactffiCleanupPlugins(pactPtr);
        },
        cleanupMockServer: (port) => {
            return checkErrors_1.wrapWithCheck((port) => ffi.pactffiCleanupMockServer(port), 'cleanupMockServer')(port);
        },
        writePactFile: (dir, merge = true) => writePact(ffi, pactPtr, dir, merge),
        writePactFileForPluginServer: (port, dir, merge = true) => writePact(ffi, pactPtr, dir, merge, port),
        addMetadata: (namespace, name, value) => {
            return ffi.pactffiWithPactMetadata(pactPtr, namespace, name, value);
        },
        newMessage: (description) => {
            const interactionPtr = ffi.pactffiNewAsyncMessage(pactPtr, description);
            return asyncMessage(ffi, interactionPtr);
        },
        newAsynchronousMessage: (description) => {
            const interactionPtr = ffi.pactffiNewAsyncMessage(pactPtr, description);
            return asyncMessage(ffi, interactionPtr);
        },
        newSynchronousMessage: (description) => {
            const interactionPtr = ffi.pactffiNewSyncMessage(pactPtr, description);
            return {
                withPluginRequestInteractionContents: (contentType, contents) => {
                    ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, contents);
                    return true;
                },
                withPluginResponseInteractionContents: (contentType, contents) => {
                    ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, contents);
                    return true;
                },
                withPluginRequestResponseInteractionContents: (contentType, contents) => {
                    ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, contents);
                    return true;
                },
                given: (state) => {
                    return ffi.pactffiGiven(interactionPtr, state);
                },
                givenWithParam: (state, name, value) => {
                    return ffi.pactffiGivenWithParam(interactionPtr, state, name, value);
                },
                withRequestContents: (body, contentType) => {
                    return ffi.pactffiWithBody(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, body);
                },
                withResponseContents: (body, contentType) => {
                    return ffi.pactffiWithBody(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, body);
                },
                withRequestBinaryContents: (body, contentType) => {
                    return ffi.pactffiWithBinaryFile(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, body, body.length);
                },
                withResponseBinaryContents: (body, contentType) => {
                    return ffi.pactffiWithBinaryFile(interactionPtr, types_1.INTERACTION_PART_RESPONSE, contentType, body, body.length);
                },
                withMetadata: (name, value) => {
                    return ffi.pactffiMessageWithMetadata(interactionPtr, name, value);
                },
            };
        },
        pactffiCreateMockServerForTransport(address, transport, config, port) {
            return ffi.pactffiCreateMockServerForTransport(pactPtr, address, port || 0, transport, config);
        },
        mockServerMatchedSuccessfully: (port) => {
            return ffi.pactffiMockServerMatched(port);
        },
        mockServerMismatches: (port) => {
            return mockServerMismatches(ffi, port);
        },
    };
};
exports.makeConsumerMessagePact = makeConsumerMessagePact;
exports.makeConsumerAsyncMessagePact = exports.makeConsumerMessagePact;
const mockServerMismatches = (ffi, port) => {
    const results = JSON.parse(ffi.pactffiMockServerMismatches(port));
    return results.map((result) => ({
        ...result,
        ...('mismatches' in result
            ? {
                mismatches: result.mismatches.map((m) => typeof m === 'string' ? JSON.parse(m) : m),
            }
            : {}),
    }));
};
const writePact = (ffi, pactPtr, dir, merge = true, port = 0) => {
    let result;
    if (port != 0) {
        result = ffi.pactffiWritePactFileByPort(port, dir, !merge);
    }
    else {
        result = ffi.pactffiWritePactFile(pactPtr, dir, !merge);
    }
    switch (result) {
        case types_1.FfiWritePactResponse.SUCCESS:
            return;
        case types_1.FfiWritePactResponse.UNABLE_TO_WRITE_PACT_FILE:
            logger_1.logErrorAndThrow('The pact core was unable to write the pact file');
        case types_1.FfiWritePactResponse.GENERAL_PANIC:
            logger_1.logCrashAndThrow('The pact core panicked while writing the pact file');
        case types_1.FfiWritePactResponse.MOCK_SERVER_NOT_FOUND:
            logger_1.logCrashAndThrow('The pact core was asked to write a pact file from a mock server that appears not to exist');
        default:
            logger_1.logCrashAndThrow(`The pact core returned an unknown error code (${result}) instead of writing the pact`);
    }
};
const asyncMessage = (ffi, interactionPtr) => ({
    withPluginRequestInteractionContents: (contentType, contents) => {
        ffi.pactffiPluginInteractionContents(interactionPtr, types_1.INTERACTION_PART_REQUEST, contentType, contents);
        return true;
    },
    expectsToReceive: (description) => {
        return ffi.pactffiMessageExpectsToReceive(interactionPtr, description);
    },
    given: (state) => {
        return ffi.pactffiMessageGiven(interactionPtr, state);
    },
    givenWithParam: (state, name, value) => {
        return ffi.pactffiMessageGivenWithParam(interactionPtr, state, name, value);
    },
    withContents: (body, contentType) => {
        return ffi.pactffiMessageWithContents(interactionPtr, contentType, body);
    },
    withBinaryContents: (body, contentType) => {
        return ffi.pactffiMessageWithBinaryContents(interactionPtr, contentType, body, body.length);
    },
    reifyMessage: () => {
        return ffi.pactffiMessageReify(interactionPtr);
    },
    withMetadata: (name, value) => {
        return ffi.pactffiMessageWithMetadata(interactionPtr, name, value);
    },
});
__exportStar(require("./types"), exports);
//# sourceMappingURL=index.js.map