/**
 * @file
 * @brief "An FFI interface to the pact libraries, enabling cross-language use of Pact's core functionality."
 */


#ifndef pact_ffi_h
#define pact_ffi_h

/* Generated with cbindgen:0.24.5 */

/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

/**
 * The type of value detected after parsing the expression
 */
typedef enum ExpressionValueType {
  /**
   * If the type is unknown
   */
  ExpressionValueType_Unknown,
  /**
   * String type
   */
  ExpressionValueType_String,
  /**
   * Numeric type
   */
  ExpressionValueType_Number,
  /**
   * Integer numeric type (no significant figures after the decimal point)
   */
  ExpressionValueType_Integer,
  /**
   * Decimal numeric type (at least one significant figure after the decimal point)
   */
  ExpressionValueType_Decimal,
  /**
   * Boolean type
   */
  ExpressionValueType_Boolean,
} ExpressionValueType;

/**
 * Enum defining the categories that generators can be applied to
 */
typedef enum GeneratorCategory {
  /**
   * Request Method
   */
  GeneratorCategory_METHOD,
  /**
   * Request Path
   */
  GeneratorCategory_PATH,
  /**
   * Request/Response Header
   */
  GeneratorCategory_HEADER,
  /**
   * Request Query Parameter
   */
  GeneratorCategory_QUERY,
  /**
   * Body
   */
  GeneratorCategory_BODY,
  /**
   * Response Status
   */
  GeneratorCategory_STATUS,
  /**
   * Message metadata
   */
  GeneratorCategory_METADATA,
} GeneratorCategory;

/**
 * Request or Response enum
 */
typedef enum InteractionPart {
  /**
   * Request part
   */
  InteractionPart_Request,
  /**
   * Response part
   */
  InteractionPart_Response,
} InteractionPart;

/**
 * An enum representing the log level to use.
 *
 * This enum is passed to `log_attach_sink`, which defines where to direct
 * log output at the specified level or lower.
 */
typedef enum LevelFilter {
  LevelFilter_Off,
  LevelFilter_Error,
  LevelFilter_Warn,
  LevelFilter_Info,
  LevelFilter_Debug,
  LevelFilter_Trace,
} LevelFilter;

/**
 * Enum defining the categories that matching rules can be applied to
 */
typedef enum MatchingRuleCategory {
  /**
   * Request Method
   */
  MatchingRuleCategory_METHOD,
  /**
   * Request Path
   */
  MatchingRuleCategory_PATH,
  /**
   * Request/Response Header
   */
  MatchingRuleCategory_HEADER,
  /**
   * Request Query Parameter
   */
  MatchingRuleCategory_QUERY,
  /**
   * Body
   */
  MatchingRuleCategory_BODY,
  /**
   * Response Status
   */
  MatchingRuleCategory_STATUS,
  /**
   * Message contents (body)
   */
  MatchingRuleCategory_CONTENTS,
  /**
   * Message metadata
   */
  MatchingRuleCategory_METADATA,
} MatchingRuleCategory;

/**
 * Enum defining the pact specification versions supported by the library
 */
typedef enum PactSpecification {
  /**
   * Unknown or unsupported specification version
   */
  PactSpecification_Unknown,
  /**
   * First version of the pact specification (<https://github.com/pact-foundation/pact-specification/tree/version-1>)
   */
  PactSpecification_V1,
  /**
   * Second version of the pact specification (<https://github.com/pact-foundation/pact-specification/tree/version-1.1>)
   */
  PactSpecification_V1_1,
  /**
   * Version two of the pact specification (<https://github.com/pact-foundation/pact-specification/tree/version-2>)
   */
  PactSpecification_V2,
  /**
   * Version three of the pact specification (<https://github.com/pact-foundation/pact-specification/tree/version-3>)
   */
  PactSpecification_V3,
  /**
   * Version four of the pact specification (<https://github.com/pact-foundation/pact-specification/tree/version-4>)
   */
  PactSpecification_V4,
} PactSpecification;

/**
 * Asynchronous interactions as a sequence of messages
 */
typedef struct AsynchronousMessage AsynchronousMessage;

/**
 * Struct that defines the consumer of the pact.
 */
typedef struct Consumer Consumer;

/**
 * Trait to represent a generator
 */
typedef struct Generator Generator;

/**
 * An iterator that enables FFI iteration over the generators for a particular generator
 * category.
 */
typedef struct GeneratorCategoryIterator GeneratorCategoryIterator;

/**
 * Struct that defines the HTTP request.
 */
typedef struct HttpRequest HttpRequest;

/**
 * Struct that defines the HTTP response.
 */
typedef struct HttpResponse HttpResponse;

/**
 * Set of all matching rules
 */
typedef struct MatchingRule MatchingRule;

/**
 * An iterator that enables FFI iteration over the matching rules for a particular matching rule
 * category.
 */
typedef struct MatchingRuleCategoryIterator MatchingRuleCategoryIterator;

/**
 * Result of parsing a matching rule definition
 */
typedef struct MatchingRuleDefinitionResult MatchingRuleDefinitionResult;

/**
 * An iterator over the matching rules from a matching definition expression.
 */
typedef struct MatchingRuleIterator MatchingRuleIterator;

/**
 * The matching rule or reference from parsing the matching definition expression.
 *
 * For matching rules, the ID corresponds to the following rules:
 * | Rule | ID |
 * | ---- | -- |
 * | Equality | 1 |
 * | Regex | 2 |
 * | Type | 3 |
 * | MinType | 4 |
 * | MaxType | 5 |
 * | MinMaxType | 6 |
 * | Timestamp | 7 |
 * | Time | 8 |
 * | Date | 9 |
 * | Include | 10 |
 * | Number | 11 |
 * | Integer | 12 |
 * | Decimal | 13 |
 * | Null | 14 |
 * | ContentType | 15 |
 * | ArrayContains | 16 |
 * | Values | 17 |
 * | Boolean | 18 |
 * | StatusCode | 19 |
 * | NotEmpty | 20 |
 * | Semver | 21 |
 * | EachKey | 22 |
 * | EachValue | 23 |
 */
typedef struct MatchingRuleResult MatchingRuleResult;

/**
 * Struct that defines a message.
 */
typedef struct Message Message;

/**
 * Contents of a message interaction
 */
typedef struct MessageContents MessageContents;

/**
 * An iterator that enables FFI iteration over metadata by putting all the keys on the heap
 * and tracking which one we're currently at.
 *
 * This assumes no mutation of the underlying metadata happens while the iterator is live.
 */
typedef struct MessageMetadataIterator MessageMetadataIterator;

/**
 * Struct that represents a pact between the consumer and provider of a service.
 * It contains a list of Messages instead of Interactions, but is otherwise
 * identical to `struct Pact`.
 */
typedef struct MessagePact MessagePact;

/**
 * An iterator over messages in a message pact.
 */
typedef struct MessagePactMessageIterator MessagePactMessageIterator;

/**
 * An iterator that enables FFI iteration over metadata by putting all the keys on the heap
 * and tracking which one we're currently at.
 *
 * This assumes no mutation of the underlying metadata happens while the iterator is live.
 */
typedef struct MessagePactMetadataIterator MessagePactMetadataIterator;

/**
 * Enum that defines the different types of mismatches that can occur.
 */
typedef struct Mismatch Mismatch;

/**
 * A collection of mismatches from a matching comparison.
 */
typedef struct Mismatches Mismatches;

/**
 * An iterator over mismatches.
 */
typedef struct MismatchesIterator MismatchesIterator;

/**
 * Opaque type for use as a pointer to a Pact model
 */
typedef struct Pact Pact;

/**
 * Opaque type for use as a pointer to a Pact interaction model
 */
typedef struct PactInteraction PactInteraction;

/**
 * An iterator over the interactions in a pact.
 */
typedef struct PactInteractionIterator PactInteractionIterator;

/**
 * An iterator over messages in a pact.
 */
typedef struct PactMessageIterator PactMessageIterator;

/**
 * An iterator over synchronous HTTP request/response interactions in a V4 pact.
 */
typedef struct PactSyncHttpIterator PactSyncHttpIterator;

/**
 * An iterator over synchronous request/response messages in a V4 pact.
 */
typedef struct PactSyncMessageIterator PactSyncMessageIterator;

/**
 * Struct that defines a provider of a pact.
 */
typedef struct Provider Provider;

/**
 * Struct that encapsulates all the info about a provider state
 */
typedef struct ProviderState ProviderState;

/**
 * Iterator over individual provider states.
 */
typedef struct ProviderStateIterator ProviderStateIterator;

/**
 * An iterator that enables FFI iteration over provider state params by putting all the keys on the heap
 * and tracking which one we're currently at.
 *
 * This assumes no mutation of the underlying provider state happens while the iterator is live.
 */
typedef struct ProviderStateParamIterator ProviderStateParamIterator;

/**
 * V4 HTTP Interaction Type
 */
typedef struct SynchronousHttp SynchronousHttp;

/**
 * Synchronous interactions as a request message to a sequence of response messages
 */
typedef struct SynchronousMessage SynchronousMessage;

/**
 * Wraps a Pact verifier
 */
typedef struct VerifierHandle VerifierHandle;

/**
 * A single key-value pair of a path and generator exported to the C-side.
 */
typedef struct GeneratorKeyValuePair {
  /**
   * The generator path
   */
  const char *path;
  /**
   * The generator
   */
  const struct Generator *generator;
} GeneratorKeyValuePair;

/**
 * A single key-value pair of a path and matching rule exported to the C-side.
 */
typedef struct MatchingRuleKeyValuePair {
  /**
   * The matching rule path
   */
  const char *path;
  /**
   * The matching rule
   */
  const struct MatchingRule *rule;
} MatchingRuleKeyValuePair;

/**
 * A single key-value pair exported to the C-side.
 */
typedef struct MessageMetadataPair {
  /**
   * The metadata key.
   */
  const char *key;
  /**
   * The metadata value.
   */
  const char *value;
} MessageMetadataPair;

/**
 * A triple, containing the outer key, inner key, and value, exported to the C-side.
 */
typedef struct MessagePactMetadataTriple {
  /**
   * The outer key of the `MessagePact` metadata.
   */
  const char *outer_key;
  /**
   * The inner key of the `MessagePact` metadata.
   */
  const char *inner_key;
  /**
   * The value of the `MessagePact` metadata.
   */
  const char *value;
} MessagePactMetadataTriple;

/**
 * A single key-value pair exported to the C-side.
 */
typedef struct ProviderStateParamPair {
  /**
   * The key of the `ProviderState` parameter.
   */
  const char *key;
  /**
   * The value of the `ProviderState` parameter.
   */
  const char *value;
} ProviderStateParamPair;

/**
 * Wraps a Pact model struct
 */
typedef uint16_t PactHandle;

/**
 * Result of wrapping a string value
 */
typedef enum StringResult_Tag {
  /**
   * Was generated OK
   */
  StringResult_Ok,
  /**
   * There was an error generating the string
   */
  StringResult_Failed,
} StringResult_Tag;

typedef struct StringResult {
  StringResult_Tag tag;
  union {
    struct {
      char *ok;
    };
    struct {
      char *failed;
    };
  };
} StringResult;

/**
 * Wraps a Pact model struct
 */
typedef uint32_t InteractionHandle;

/**
 * Wraps a Pact model struct
 */
typedef uint16_t MessagePactHandle;

/**
 * Wraps a Pact model struct
 */
typedef uint32_t MessageHandle;

/**
 * Returns the current library version
 */
const char *pactffi_version(void);

/**
 * Initialise the mock server library, can provide an environment variable name to use to
 * set the log levels. This function should only be called once, as it tries to install a global
 * tracing subscriber.
 *
 * # Safety
 *
 * log_env_var must be a valid NULL terminated UTF-8 string.
 */
void pactffi_init(const char *log_env_var);

/**
 * Initialises logging, and sets the log level explicitly. This function should only be called
 * once, as it tries to install a global tracing subscriber.
 *
 * # Safety
 *
 * Exported functions are inherently unsafe.
 */
void pactffi_init_with_log_level(const char *level);

/**
 * Enable ANSI coloured output on Windows. On non-Windows platforms, this function is a no-op.
 *
 * # Safety
 *
 * This function is safe.
 */
void pactffi_enable_ansi_support(void);

/**
 * Log using the shared core logging facility.
 *
 * This is useful for callers to have a single set of logs.
 *
 * * `source` - String. The source of the log, such as the class or caller framework to
 *                      disambiguate log lines from the rust logging (e.g. pact_go)
 * * `log_level` - String. One of TRACE, DEBUG, INFO, WARN, ERROR
 * * `message` - Message to log
 *
 * # Safety
 * This function will fail if any of the pointers passed to it are invalid.
 */
void pactffi_log_message(const char *source, const char *log_level, const char *message);

/**
 * Match a pair of messages, producing a collection of mismatches,
 * which is empty if the two messages matched.
 */
const struct Mismatches *pactffi_match_message(const struct Message *msg_1,
                                               const struct Message *msg_2);

/**
 * Get an iterator over mismatches.
 */
struct MismatchesIterator *pactffi_mismatches_get_iter(const struct Mismatches *mismatches);

/**
 * Delete mismatches
 */
void pactffi_mismatches_delete(const struct Mismatches *mismatches);

/**
 * Get the next mismatch from a mismatches iterator.
 *
 * Returns a null pointer if no mismatches remain.
 */
const struct Mismatch *pactffi_mismatches_iter_next(struct MismatchesIterator *iter);

/**
 * Delete a mismatches iterator when you're done with it.
 */
void pactffi_mismatches_iter_delete(struct MismatchesIterator *iter);

/**
 * Get a JSON representation of the mismatch.
 */
const char *pactffi_mismatch_to_json(const struct Mismatch *mismatch);

/**
 * Get the type of a mismatch.
 */
const char *pactffi_mismatch_type(const struct Mismatch *mismatch);

/**
 * Get a summary of a mismatch.
 */
const char *pactffi_mismatch_summary(const struct Mismatch *mismatch);

/**
 * Get a description of a mismatch.
 */
const char *pactffi_mismatch_description(const struct Mismatch *mismatch);

/**
 * Get an ANSI-compatible description of a mismatch.
 */
const char *pactffi_mismatch_ansi_description(const struct Mismatch *mismatch);

/**
 * Provide the error message from `LAST_ERROR` to the calling C code.
 *
 * This function should be called after any other function in the pact_matching FFI
 * indicates a failure with its own error message, if the caller wants to get more context
 * on why the error happened.
 *
 * Do note that this error-reporting mechanism only reports the top-level error message,
 * not any source information embedded in the original Rust error type. If you want more
 * detailed information for debugging purposes, use the logging interface.
 *
 * # Params
 *
 * * `buffer`: a pointer to an array of `char` of sufficient length to hold the error message.
 * * `length`: an int providing the length of the `buffer`.
 *
 * # Return Codes
 *
 * * The number of bytes written to the provided buffer, which may be zero if there is no last error.
 * * `-1` if the provided buffer is a null pointer.
 * * `-2` if the provided buffer length is too small for the error message.
 * * `-3` if the write failed for some other reason.
 * * `-4` if the error message had an interior NULL
 *
 * # Notes
 *
 * Note that this function zeroes out any excess in the provided buffer.
 *
 * # Error Handling
 *
 * The return code must be checked for one of the negative number error codes before the buffer
 * is used. If an error code is present, the buffer may not be in a usable state.
 *
 * If the buffer is longer than needed for the error message, the excess space will be zeroed
 * as a safety mechanism. This is slightly less efficient than leaving the contents of the buffer
 * alone, but the difference is expected to be negligible in practice.
 */
int pactffi_get_error_message(char *buffer,
                              int length);

/**
 * Convenience function to direct all logging to stdout.
 */
int pactffi_log_to_stdout(enum LevelFilter level_filter);

/**
 * Convenience function to direct all logging to stderr.
 */
int pactffi_log_to_stderr(enum LevelFilter level_filter);

/**
 * Convenience function to direct all logging to a file.
 *
 * # Safety
 * This function will fail if the file_name pointer is invalid or does not point to a NULL
 * terminated string.
 */
int pactffi_log_to_file(const char *file_name, enum LevelFilter level_filter);

/**
 * Convenience function to direct all logging to a task local memory buffer.
 */
int pactffi_log_to_buffer(enum LevelFilter level_filter);

/**
 * Initialize the FFI logger with no sinks.
 *
 * This initialized logger does nothing until `pactffi_logger_apply` has been called.
 *
 * # Usage
 *
 * ```c
 * pactffi_logger_init();
 * ```
 *
 * # Safety
 *
 * This function is always safe to call.
 */
void pactffi_logger_init(void);

/**
 * Attach an additional sink to the thread-local logger.
 *
 * This logger does nothing until `pactffi_logger_apply` has been called.
 *
 * Types of sinks can be specified:
 *
 * - stdout (`pactffi_logger_attach_sink("stdout", LevelFilter_Info)`)
 * - stderr (`pactffi_logger_attach_sink("stderr", LevelFilter_Debug)`)
 * - file w/ file path (`pactffi_logger_attach_sink("file /some/file/path", LevelFilter_Trace)`)
 * - buffer (`pactffi_logger_attach_sink("buffer", LevelFilter_Debug)`)
 *
 * # Usage
 *
 * ```c
 * int result = pactffi_logger_attach_sink("file /some/file/path", LogLevel_Filter);
 * ```
 *
 * # Error Handling
 *
 * The return error codes are as follows:
 *
 * - `-1`: Can't set logger (applying the logger failed, perhaps because one is applied already).
 * - `-2`: No logger has been initialized (call `pactffi_logger_init` before any other log function).
 * - `-3`: The sink specifier was not UTF-8 encoded.
 * - `-4`: The sink type specified is not a known type (known types: "stdout", "stderr", or "file /some/path").
 * - `-5`: No file path was specified in a file-type sink specification.
 * - `-6`: Opening a sink to the specified file path failed (check permissions).
 *
 * # Safety
 *
 * This function checks the validity of the passed-in sink specifier, and errors
 * out if the specifier isn't valid UTF-8. Passing in an invalid or NULL pointer will result in
 * undefined behaviour.
 */
int pactffi_logger_attach_sink(const char *sink_specifier,
                               enum LevelFilter level_filter);

/**
 * Apply the previously configured sinks and levels to the program. If no sinks have been setup,
 * will set the log level to info and the target to standard out.
 *
 * This function will install a global tracing subscriber. Any attempts to modify the logger
 * after the call to `logger_apply` will fail.
 */
int pactffi_logger_apply(void);

/**
 * Fetch the in-memory logger buffer contents. This will only have any contents if the `buffer`
 * sink has been configured to log to. The contents will be allocated on the heap and will need
 * to be freed with `pactffi_string_delete`.
 *
 * Fetches the logs associated with the provided identifier, or uses the "global" one if the
 * identifier is not specified (i.e. NULL).
 *
 * Returns a NULL pointer if the buffer can't be fetched. This can occur is there is not
 * sufficient memory to make a copy of the contents or the buffer contains non-UTF-8 characters.
 *
 * # Safety
 *
 * This function will fail if the log_id pointer is invalid or does not point to a NULL
 * terminated string.
 */
const char *pactffi_fetch_log_buffer(const char *log_id);

/**
 * Parses the provided JSON into a Pact model. The returned Pact model must be freed with the
 * `pactffi_pact_model_delete` function when no longer needed.
 *
 * # Error Handling
 *
 * This function will return a NULL pointer if passed a NULL pointer or if an error occurs.
 */
struct Pact *pactffi_parse_pact_json(const char *json);

/**
 * Frees the memory used by the Pact model
 */
void pactffi_pact_model_delete(struct Pact *pact);

/**
 * Returns an iterator over all the interactions in the Pact. The iterator will have to be
 * deleted using the `pactffi_pact_interaction_iter_delete` function. The iterator will
 * contain a copy of the interactions, so it will not be affected but mutations to the Pact
 * model and will still function if the Pact model is deleted.
 *
 * # Safety
 * This function is safe as long as the Pact pointer is a valid pointer.
 *
 * # Errors
 * On any error, this function will return a NULL pointer.
 */
struct PactInteractionIterator *pactffi_pact_model_interaction_iterator(struct Pact *pact);

/**
 * Returns the Pact specification enum that the Pact is for.
 */
enum PactSpecification pactffi_pact_spec_version(const struct Pact *pact);

/**
 * Frees the memory used by the Pact interaction model
 */
void pactffi_pact_interaction_delete(const struct PactInteraction *interaction);

/**
 * Get a mutable pointer to a newly-created default message on the heap.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * Returns NULL on error.
 */
struct AsynchronousMessage *pactffi_async_message_new(void);

/**
 * Destroy the `AsynchronousMessage` being pointed to.
 */
void pactffi_async_message_delete(const struct AsynchronousMessage *message);

/**
 * Get the message contents of an `AsynchronousMessage` as a `MessageContents` pointer.
 *
 * # Safety
 *
 * The data pointed to by the pointer this function returns will be deleted when the message
 * is deleted. Trying to use if after the message is deleted will result in undefined behaviour.
 *
 * # Error Handling
 *
 * If the message is NULL, returns NULL.
 */
const struct MessageContents *pactffi_async_message_get_contents(const struct AsynchronousMessage *message);

/**
 * Get the message contents of an `AsynchronousMessage` in string form.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * The returned string can outlive the message.
 *
 * # Error Handling
 *
 * If the message is NULL, returns NULL. If the body of the message
 * is missing, then this function also returns NULL. This means there's
 * no mechanism to differentiate with this function call alone between
 * a NULL message and a missing message body.
 */
const char *pactffi_async_message_get_contents_str(const struct AsynchronousMessage *message);

/**
 * Sets the contents of the message as a string.
 *
 * * `message` - the message to set the contents for
 * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer.
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The message contents and content type must either be NULL pointers, or point to valid
 * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the message contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_async_message_set_contents_str(struct AsynchronousMessage *message,
                                            const char *contents,
                                            const char *content_type);

/**
 * Get the length of the contents of a `AsynchronousMessage`.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the message is NULL, returns 0. If the body of the request
 * is missing, then this function also returns 0.
 */
size_t pactffi_async_message_get_contents_length(const struct AsynchronousMessage *message);

/**
 * Get the contents of an `AsynchronousMessage` as a pointer to an array of bytes.
 *
 * # Safety
 *
 * The number of bytes in the buffer will be returned by `pactffi_async_message_get_contents_length`.
 * It is safe to use the pointer while the message is not deleted or changed. Using the pointer
 * after the message is mutated or deleted may lead to undefined behaviour.
 *
 * # Error Handling
 *
 * If the message is NULL, returns NULL. If the body of the message
 * is missing, then this function also returns NULL.
 */
const unsigned char *pactffi_async_message_get_contents_bin(const struct AsynchronousMessage *message);

/**
 * Sets the contents of the message as an array of bytes.
 *
 * * `message` - the message to set the contents for
 * * `contents` - pointer to contents to copy from
 * * `len` - number of bytes to copy from the contents pointer
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned
 * and consecutive. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the message contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_async_message_set_contents_bin(struct AsynchronousMessage *message,
                                            const unsigned char *contents,
                                            size_t len,
                                            const char *content_type);

/**
 * Get a copy of the description.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * Since it is a copy, the returned string may safely outlive the `AsynchronousMessage`.
 *
 * # Errors
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if the Rust string contains embedded
 * null ('\0') bytes.
 */
const char *pactffi_async_message_get_description(const struct AsynchronousMessage *message);

/**
 * Write the `description` field on the `AsynchronousMessage`.
 *
 * # Safety
 *
 * `description` must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 * This function will only reallocate if the new string
 * does not fit in the existing buffer.
 *
 * # Error Handling
 *
 * Errors will be reported with a non-zero return value.
 */
int pactffi_async_message_set_description(struct AsynchronousMessage *message,
                                          const char *description);

/**
 * Get a copy of the provider state at the given index from this message.
 *
 * # Safety
 *
 * The returned structure must be deleted with `provider_state_delete`.
 *
 * Since it is a copy, the returned structure may safely outlive the `AsynchronousMessage`.
 *
 * # Error Handling
 *
 * On failure, this function will return a variant other than Success.
 *
 * This function may fail if the index requested is out of bounds,
 * or if any of the Rust strings contain embedded null ('\0') bytes.
 */
const struct ProviderState *pactffi_async_message_get_provider_state(const struct AsynchronousMessage *message,
                                                                     unsigned int index);

/**
 * Get an iterator over provider states.
 *
 * # Safety
 *
 * The underlying data must not change during iteration.
 *
 * # Error Handling
 *
 * Returns NULL if an error occurs.
 */
struct ProviderStateIterator *pactffi_async_message_get_provider_state_iter(struct AsynchronousMessage *message);

/**
 * Get a copy of this consumer's name.
 *
 * The copy must be deleted with `pactffi_string_delete`.
 *
 * # Usage
 *
 * ```c
 * // Assuming `file_name` and `json_str` are already defined.
 *
 * MessagePact *message_pact = pactffi_message_pact_new_from_json(file_name, json_str);
 * if (message_pact == NULLPTR) {
 *     // handle error.
 * }
 *
 * Consumer *consumer = pactffi_message_pact_get_consumer(message_pact);
 * if (consumer == NULLPTR) {
 *     // handle error.
 * }
 *
 * char *name = pactffi_consumer_get_name(consumer);
 * if (name == NULL) {
 *     // handle error.
 * }
 *
 * printf("%s\n", name);
 *
 * pactffi_string_delete(name);
 * ```
 *
 * # Errors
 *
 * This function will fail if it is passed a NULL pointer,
 * or the Rust string contains an embedded NULL byte.
 * In the case of error, a NULL pointer will be returned.
 */
const char *pactffi_consumer_get_name(const struct Consumer *consumer);

/**
 * Get the consumer from a Pact. This returns a copy of the consumer model, and needs to
 * be cleaned up with `pactffi_pact_consumer_delete` when no longer required.
 *
 * # Errors
 *
 * This function will fail if it is passed a NULL pointer.
 * In the case of error, a NULL pointer will be returned.
 */
const struct Consumer *pactffi_pact_get_consumer(const struct Pact *pact);

/**
 * Frees the memory used by the Pact consumer
 */
void pactffi_pact_consumer_delete(const struct Consumer *consumer);

/**
 * Get the message contents in string form.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * The returned string can outlive the message.
 *
 * # Error Handling
 *
 * If the message contents is NULL, returns NULL. If the body of the message
 * is missing, then this function also returns NULL. This means there's
 * no mechanism to differentiate with this function call alone between
 * a NULL message and a missing message body.
 */
const char *pactffi_message_contents_get_contents_str(const struct MessageContents *contents);

/**
 * Sets the contents of the message as a string.
 *
 * * `contents` - the message contents to set the contents for
 * * `contents_str` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer.
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The message contents and content type must either be NULL pointers, or point to valid
 * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents string is a NULL pointer, it will set the message contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_message_contents_set_contents_str(struct MessageContents *contents,
                                               const char *contents_str,
                                               const char *content_type);

/**
 * Get the length of the message contents.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the message is NULL, returns 0. If the body of the message
 * is missing, then this function also returns 0.
 */
size_t pactffi_message_contents_get_contents_length(const struct MessageContents *contents);

/**
 * Get the contents of a message as a pointer to an array of bytes.
 *
 * # Safety
 *
 * The number of bytes in the buffer will be returned by `pactffi_message_contents_get_contents_length`.
 * It is safe to use the pointer while the message is not deleted or changed. Using the pointer
 * after the message is mutated or deleted may lead to undefined behaviour.
 *
 * # Error Handling
 *
 * If the message is NULL, returns NULL. If the body of the message
 * is missing, then this function also returns NULL.
 */
const unsigned char *pactffi_message_contents_get_contents_bin(const struct MessageContents *contents);

/**
 * Sets the contents of the message as an array of bytes.
 *
 * * `message` - the message contents to set the contents for
 * * `contents_bin` - pointer to contents to copy from
 * * `len` - number of bytes to copy from the contents pointer
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned
 * and consecutive. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the message contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_message_contents_set_contents_bin(struct MessageContents *contents,
                                               const unsigned char *contents_bin,
                                               size_t len,
                                               const char *content_type);

/**
 * Get an iterator over the metadata of a message.
 *
 * The returned pointer must be deleted with `pactffi_message_metadata_iter_delete` when done
 * with it.
 *
 * # Safety
 *
 * This iterator carries a pointer to the message contents, and must
 * not outlive the message.
 *
 * The message metadata also must not be modified during iteration. If it is,
 * the old iterator must be deleted and a new iterator created.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if any of the Rust strings contain
 * embedded null ('\0') bytes.
 */
struct MessageMetadataIterator *pactffi_message_contents_get_metadata_iter(const struct MessageContents *contents);

/**
 * Get an iterator over the matching rules for a category of a message.
 *
 * The returned pointer must be deleted with `pactffi_matching_rules_iter_delete` when done
 * with it.
 *
 * Note that there could be multiple matching rules for the same key, so this iterator will
 * sequentially return each rule with the same key.
 *
 * For sample, given the following rules:
 *    "$.a" => Type,
 *    "$.b" => Regex("\\d+"), Number
 *
 * This iterator will return a sequence of 3 values: ("$.a", Type), ("$.b", Regex("\\d+")), ("$.b", Number)
 *
 * # Safety
 *
 * The iterator contains a copy of the data, so is safe to use when the message or message
 * contents has been deleted.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 */
struct MatchingRuleCategoryIterator *pactffi_message_contents_get_matching_rule_iter(const struct MessageContents *contents,
                                                                                     enum MatchingRuleCategory category);

/**
 * Get an iterator over the matching rules for a category of an HTTP request.
 *
 * The returned pointer must be deleted with `pactffi_matching_rules_iter_delete` when done
 * with it.
 *
 * For sample, given the following rules:
 *    "$.a" => Type,
 *    "$.b" => Regex("\\d+"), Number
 *
 * This iterator will return a sequence of 3 values: ("$.a", Type), ("$.b", Regex("\\d+")), ("$.b", Number)
 *
 * # Safety
 *
 * The iterator contains a copy of the data, so is safe to use when the interaction or request
 * contents has been deleted.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 */
struct MatchingRuleCategoryIterator *pactffi_request_contents_get_matching_rule_iter(const struct HttpRequest *request,
                                                                                     enum MatchingRuleCategory category);

/**
 * Get an iterator over the matching rules for a category of an HTTP response.
 *
 * The returned pointer must be deleted with `pactffi_matching_rules_iter_delete` when done
 * with it.
 *
 * For sample, given the following rules:
 *    "$.a" => Type,
 *    "$.b" => Regex("\\d+"), Number
 *
 * This iterator will return a sequence of 3 values: ("$.a", Type), ("$.b", Regex("\\d+")), ("$.b", Number)
 *
 * # Safety
 *
 * The iterator contains a copy of the data, so is safe to use when the interaction or response
 * contents has been deleted.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 */
struct MatchingRuleCategoryIterator *pactffi_response_contents_get_matching_rule_iter(const struct HttpResponse *response,
                                                                                      enum MatchingRuleCategory category);

/**
 * Get an iterator over the generators for a category of a message.
 *
 * The returned pointer must be deleted with `pactffi_generators_iter_delete` when done
 * with it.
 *
 * # Safety
 *
 * The iterator contains a copy of the data, so is safe to use when the message or message
 * contents has been deleted.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 */
struct GeneratorCategoryIterator *pactffi_message_contents_get_generators_iter(const struct MessageContents *contents,
                                                                               enum GeneratorCategory category);

/**
 * Get an iterator over the generators for a category of an HTTP request.
 *
 * The returned pointer must be deleted with `pactffi_generators_iter_delete` when done
 * with it.
 *
 * # Safety
 *
 * The iterator contains a copy of the data, so is safe to use when the interaction or request
 * contents has been deleted.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 */
struct GeneratorCategoryIterator *pactffi_request_contents_get_generators_iter(const struct HttpRequest *request,
                                                                               enum GeneratorCategory category);

/**
 * Get an iterator over the generators for a category of an HTTP response.
 *
 * The returned pointer must be deleted with `pactffi_generators_iter_delete` when done
 * with it.
 *
 * # Safety
 *
 * The iterator contains a copy of the data, so is safe to use when the interaction or response
 * contents has been deleted.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 */
struct GeneratorCategoryIterator *pactffi_response_contents_get_generators_iter(const struct HttpResponse *response,
                                                                                enum GeneratorCategory category);

/**
 * Parse a matcher definition string into a MatchingRuleDefinition containing the example value,
 * and matching rules and any generator.
 *
 * The following are examples of matching rule definitions:
 * * `matching(type,'Name')` - type matcher with string value 'Name'
 * * `matching(number,100)` - number matcher
 * * `matching(datetime, 'yyyy-MM-dd','2000-01-01')` - datetime matcher with format string
 *
 * See [Matching Rule definition expressions](https://docs.rs/pact_models/latest/pact_models/matchingrules/expressions/index.html).
 *
 * The returned value needs to be freed up with the `pactffi_matcher_definition_delete` function.
 *
 * # Errors
 * If the expression is invalid, the MatchingRuleDefinition error will be set. You can check for
 * this value with the `pactffi_matcher_definition_error` function.
 *
 * # Safety
 *
 * This function is safe if the expression is a valid NULL terminated string pointer.
 */
const struct MatchingRuleDefinitionResult *pactffi_parse_matcher_definition(const char *expression);

/**
 * Returns any error message from parsing a matching definition expression. If there is no error,
 * it will return a NULL pointer, otherwise returns the error message as a NULL-terminated string.
 * The returned string must be freed using the `pactffi_string_delete` function once done with it.
 */
const char *pactffi_matcher_definition_error(const struct MatchingRuleDefinitionResult *definition);

/**
 * Returns the value from parsing a matching definition expression. If there was an error,
 * it will return a NULL pointer, otherwise returns the value as a NULL-terminated string.
 * The returned string must be freed using the `pactffi_string_delete` function once done with it.
 *
 * Note that different expressions values can have types other than a string. Use
 * `pactffi_matcher_definition_value_type` to get the actual type of the value. This function
 * will always return the string representation of the value.
 */
const char *pactffi_matcher_definition_value(const struct MatchingRuleDefinitionResult *definition);

/**
 * Frees the memory used by the result of parsing the matching definition expression
 */
void pactffi_matcher_definition_delete(const struct MatchingRuleDefinitionResult *definition);

/**
 * Returns the generator from parsing a matching definition expression. If there was an error or
 * there is no associated generator, it will return a NULL pointer, otherwise returns the generator
 * as a pointer.
 *
 * The generator pointer will be a valid pointer as long as `pactffi_matcher_definition_delete`
 * has not been called on the definition. Using the generator pointer after the definition
 * has been deleted will result in undefined behaviour.
 */
const struct Generator *pactffi_matcher_definition_generator(const struct MatchingRuleDefinitionResult *definition);

/**
 * Returns the type of the value from parsing a matching definition expression. If there was an
 * error parsing the expression, it will return Unknown.
 */
enum ExpressionValueType pactffi_matcher_definition_value_type(const struct MatchingRuleDefinitionResult *definition);

/**
 * Free the iterator when you're done using it.
 */
void pactffi_matching_rule_iter_delete(struct MatchingRuleIterator *iter);

/**
 * Returns an iterator over the matching rules from the parsed definition. The iterator needs to
 * be deleted with the `pactffi_matching_rule_iter_delete` function once done with it.
 *
 * If there was an error parsing the expression, this function will return a NULL pointer.
 */
struct MatchingRuleIterator *pactffi_matcher_definition_iter(const struct MatchingRuleDefinitionResult *definition);

/**
 * Get the next matching rule or reference from the iterator. As the values returned are owned
 * by the iterator, they do not need to be deleted but will be cleaned up when the iterator is
 * deleted.
 *
 * Will return a NULL pointer when the iterator has advanced past the end of the list.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * This function will return a NULL pointer if passed a NULL pointer or if an error occurs.
 */
const struct MatchingRuleResult *pactffi_matching_rule_iter_next(struct MatchingRuleIterator *iter);

/**
 * Return the ID of the matching rule.
 *
 * The ID corresponds to the following rules:
 * | Rule | ID |
 * | ---- | -- |
 * | Equality | 1 |
 * | Regex | 2 |
 * | Type | 3 |
 * | MinType | 4 |
 * | MaxType | 5 |
 * | MinMaxType | 6 |
 * | Timestamp | 7 |
 * | Time | 8 |
 * | Date | 9 |
 * | Include | 10 |
 * | Number | 11 |
 * | Integer | 12 |
 * | Decimal | 13 |
 * | Null | 14 |
 * | ContentType | 15 |
 * | ArrayContains | 16 |
 * | Values | 17 |
 * | Boolean | 18 |
 * | StatusCode | 19 |
 * | NotEmpty | 20 |
 * | Semver | 21 |
 * | EachKey | 22 |
 * | EachValue | 23 |
 *
 * # Safety
 *
 * This function is safe as long as the MatchingRuleResult pointer is a valid pointer and the
 * iterator has not been deleted.
 */
uint16_t pactffi_matching_rule_id(const struct MatchingRuleResult *rule_result);

/**
 * Returns the associated value for the matching rule. If the matching rule does not have an
 * associated value, will return a NULL pointer.
 *
 * The associated values for the rules are:
 * | Rule | ID | VALUE |
 * | ---- | -- | ----- |
 * | Equality | 1 | NULL |
 * | Regex | 2 | Regex value |
 * | Type | 3 | NULL |
 * | MinType | 4 | Minimum value |
 * | MaxType | 5 | Maximum value |
 * | MinMaxType | 6 | "min:max" |
 * | Timestamp | 7 | Format string |
 * | Time | 8 | Format string |
 * | Date | 9 | Format string |
 * | Include | 10 | String value |
 * | Number | 11 | NULL |
 * | Integer | 12 | NULL |
 * | Decimal | 13 | NULL |
 * | Null | 14 | NULL |
 * | ContentType | 15 | Content type |
 * | ArrayContains | 16 | NULL |
 * | Values | 17 | NULL |
 * | Boolean | 18 | NULL |
 * | StatusCode | 19 | NULL |
 * | NotEmpty | 20 | NULL |
 * | Semver | 21 | NULL |
 * | EachKey | 22 | NULL |
 * | EachValue | 23 | NULL |
 *
 * Will return a NULL pointer if the matching rule was a reference or does not have an
 * associated value.
 *
 * # Safety
 *
 * This function is safe as long as the MatchingRuleResult pointer is a valid pointer and the
 * iterator it came from has not been deleted.
 */
const char *pactffi_matching_rule_value(const struct MatchingRuleResult *rule_result);

/**
 * Returns the matching rule pointer for the matching rule. Will return a NULL pointer if the
 * matching rule result was a reference.
 *
 * # Safety
 *
 * This function is safe as long as the MatchingRuleResult pointer is a valid pointer and the
 * iterator it came from has not been deleted.
 */
const struct MatchingRule *pactffi_matching_rule_pointer(const struct MatchingRuleResult *rule_result);

/**
 * Return any matching rule reference to a attribute by name. This is when the matcher should
 * be configured to match the type of a structure. I.e.,
 *
 * ```json
 * {
 *   "pact:match": "eachValue(matching($'person'))",
 *   "person": {
 *     "name": "Fred",
 *     "age": 100
 *   }
 * }
 * ```
 *
 * Will return a NULL pointer if the matching rule was not a reference.
 *
 * # Safety
 *
 * This function is safe as long as the MatchingRuleResult pointer is a valid pointer and the
 * iterator has not been deleted.
 */
const char *pactffi_matching_rule_reference_name(const struct MatchingRuleResult *rule_result);

/**
 * Validates the date/time value against the date/time format string. If the value is valid,
 * this function will return a zero status code (EXIT_SUCCESS).
 * If the value is not valid, will return a value of 1 (EXIT_FAILURE) and set the
 * error message which can be retrieved with `pactffi_get_error_message`.
 *
 * # Errors
 * If the function receives a panic, it will return 2 and the message associated with the
 * panic can be retrieved with `pactffi_get_error_message`.
 *
 * # Safety
 *
 * This function is safe as long as the value and format parameters point to valid
 * NULL-terminated strings.
 */
int pactffi_validate_datetime(const char *value, const char *format);

/**
 * Get the JSON form of the generator.
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * # Safety
 *
 * This function will fail if it is passed a NULL pointer, or the owner of the generator has
 * been deleted.
 */
const char *pactffi_generator_to_json(const struct Generator *generator);

/**
 * Generate a string value using the provided generator and an optional JSON payload containing
 * any generator context. The context value is used for generators like `MockServerURL` (which
 * should contain details about the running mock server) and `ProviderStateGenerator` (which
 * should be the values returned from the Provider State callback function).
 *
 * If anything goes wrong, it will return a NULL pointer.
 */
const char *pactffi_generator_generate_string(const struct Generator *generator,
                                              const char *context_json);

/**
 * Generate an integer value using the provided generator and an optional JSON payload containing
 * any generator context. The context value is used for generators like `ProviderStateGenerator`
 * (which should be the values returned from the Provider State callback function).
 *
 * If anything goes wrong or the generator is not a type that can generate an integer value, it
 * will return a zero value.
 */
unsigned short pactffi_generator_generate_integer(const struct Generator *generator,
                                                  const char *context_json);

/**
 * Free the iterator when you're done using it.
 */
void pactffi_generators_iter_delete(struct GeneratorCategoryIterator *iter);

/**
 * Get the next path and generator out of the iterator, if possible.
 *
 * The returned pointer must be deleted with `pactffi_generator_iter_pair_delete`.
 *
 * # Safety
 *
 * The underlying data is owned by the `GeneratorKeyValuePair`, so is always safe to use.
 *
 * # Error Handling
 *
 * If no further data is present, returns NULL.
 */
const struct GeneratorKeyValuePair *pactffi_generators_iter_next(struct GeneratorCategoryIterator *iter);

/**
 * Free a pair of key and value returned from `pactffi_generators_iter_next`.
 */
void pactffi_generators_iter_pair_delete(const struct GeneratorKeyValuePair *pair);

/**
 * Get a mutable pointer to a newly-created default interaction on the heap.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * Returns NULL on error.
 */
struct SynchronousHttp *pactffi_sync_http_new(void);

/**
 * Destroy the `SynchronousHttp` interaction being pointed to.
 */
void pactffi_sync_http_delete(const struct SynchronousHttp *interaction);

/**
 * Get the request of a `SynchronousHttp` interaction.
 *
 * # Safety
 *
 * The data pointed to by the pointer this function returns will be deleted when the interaction
 * is deleted. Trying to use if after the interaction is deleted will result in undefined behaviour.
 *
 * # Error Handling
 *
 * If the interaction is NULL, returns NULL.
 */
const struct HttpRequest *pactffi_sync_http_get_request(const struct SynchronousHttp *interaction);

/**
 * Get the request contents of a `SynchronousHttp` interaction in string form.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * The returned string can outlive the interaction.
 *
 * # Error Handling
 *
 * If the interaction is NULL, returns NULL. If the body of the request
 * is missing, then this function also returns NULL. This means there's
 * no mechanism to differentiate with this function call alone between
 * a NULL body and a missing body.
 */
const char *pactffi_sync_http_get_request_contents(const struct SynchronousHttp *interaction);

/**
 * Sets the request contents of the interaction.
 *
 * * `interaction` - the interaction to set the request contents for
 * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer.
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The request contents and content type must either be NULL pointers, or point to valid
 * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the request contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_sync_http_set_request_contents(struct SynchronousHttp *interaction,
                                            const char *contents,
                                            const char *content_type);

/**
 * Get the length of the request contents of a `SynchronousHttp` interaction.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the interaction is NULL, returns 0. If the body of the request
 * is missing, then this function also returns 0.
 */
size_t pactffi_sync_http_get_request_contents_length(const struct SynchronousHttp *interaction);

/**
 * Get the request contents of a `SynchronousHttp` interaction as a pointer to an array of bytes.
 *
 * # Safety
 *
 * The number of bytes in the buffer will be returned by `pactffi_sync_http_get_request_contents_length`.
 * It is safe to use the pointer while the interaction is not deleted or changed. Using the pointer
 * after the interaction is mutated or deleted may lead to undefined behaviour.
 *
 * # Error Handling
 *
 * If the interaction is NULL, returns NULL. If the body of the request
 * is missing, then this function also returns NULL.
 */
const unsigned char *pactffi_sync_http_get_request_contents_bin(const struct SynchronousHttp *interaction);

/**
 * Sets the request contents of the interaction as an array of bytes.
 *
 * * `interaction` - the interaction to set the request contents for
 * * `contents` - pointer to contents to copy from
 * * `len` - number of bytes to copy from the contents pointer
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned
 * and consecutive. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the request contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_sync_http_set_request_contents_bin(struct SynchronousHttp *interaction,
                                                const unsigned char *contents,
                                                size_t len,
                                                const char *content_type);

/**
 * Get the response of a `SynchronousHttp` interaction.
 *
 * # Safety
 *
 * The data pointed to by the pointer this function returns will be deleted when the interaction
 * is deleted. Trying to use if after the interaction is deleted will result in undefined behaviour.
 *
 * # Error Handling
 *
 * If the interaction is NULL, returns NULL.
 */
const struct HttpResponse *pactffi_sync_http_get_response(const struct SynchronousHttp *interaction);

/**
 * Get the response contents of a `SynchronousHttp` interaction in string form.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * The returned string can outlive the interaction.
 *
 * # Error Handling
 *
 * If the interaction is NULL, returns NULL.
 *
 * If the body of the response is missing, then this function also returns NULL.
 * This means there's no mechanism to differentiate with this function call alone between
 * a NULL body and a missing body.
 */
const char *pactffi_sync_http_get_response_contents(const struct SynchronousHttp *interaction);

/**
 * Sets the response contents of the interaction.
 *
 * * `interaction` - the interaction to set the response contents for
 * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer.
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The response contents and content type must either be NULL pointers, or point to valid
 * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the response contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_sync_http_set_response_contents(struct SynchronousHttp *interaction,
                                             const char *contents,
                                             const char *content_type);

/**
 * Get the length of the response contents of a `SynchronousHttp` interaction.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the interaction is NULL or the index is not valid, returns 0. If the body of the response
 * is missing, then this function also returns 0.
 */
size_t pactffi_sync_http_get_response_contents_length(const struct SynchronousHttp *interaction);

/**
 * Get the response contents of a `SynchronousHttp` interaction as a pointer to an array of bytes.
 *
 * # Safety
 *
 * The number of bytes in the buffer will be returned by `pactffi_sync_http_get_response_contents_length`.
 * It is safe to use the pointer while the interaction is not deleted or changed. Using the pointer
 * after the interaction is mutated or deleted may lead to undefined behaviour.
 *
 * # Error Handling
 *
 * If the interaction is NULL, returns NULL. If the body of the response
 * is missing, then this function also returns NULL.
 */
const unsigned char *pactffi_sync_http_get_response_contents_bin(const struct SynchronousHttp *interaction);

/**
 * Sets the response contents of the `SynchronousHttp` interaction as an array of bytes.
 *
 * * `interaction` - the interaction to set the response contents for
 * * `contents` - pointer to contents to copy from
 * * `len` - number of bytes to copy
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned
 * and consecutive. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the response contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_sync_http_set_response_contents_bin(struct SynchronousHttp *interaction,
                                                 const unsigned char *contents,
                                                 size_t len,
                                                 const char *content_type);

/**
 * Get a copy of the description.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * Since it is a copy, the returned string may safely outlive
 * the `SynchronousHttp` interaction.
 *
 * # Errors
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if the Rust string contains embedded
 * null ('\0') bytes.
 */
const char *pactffi_sync_http_get_description(const struct SynchronousHttp *interaction);

/**
 * Write the `description` field on the `SynchronousHttp`.
 *
 * # Safety
 *
 * `description` must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 * This function will only reallocate if the new string
 * does not fit in the existing buffer.
 *
 * # Error Handling
 *
 * Errors will be reported with a non-zero return value.
 */
int pactffi_sync_http_set_description(struct SynchronousHttp *interaction, const char *description);

/**
 * Get a copy of the provider state at the given index from this interaction.
 *
 * # Safety
 *
 * The returned structure must be deleted with `provider_state_delete`.
 *
 * Since it is a copy, the returned structure may safely outlive
 * the `SynchronousHttp`.
 *
 * # Error Handling
 *
 * On failure, this function will return a variant other than Success.
 *
 * This function may fail if the index requested is out of bounds,
 * or if any of the Rust strings contain embedded null ('\0') bytes.
 */
const struct ProviderState *pactffi_sync_http_get_provider_state(const struct SynchronousHttp *interaction,
                                                                 unsigned int index);

/**
 * Get an iterator over provider states.
 *
 * # Safety
 *
 * The underlying data must not change during iteration.
 *
 * # Error Handling
 *
 * Returns NULL if an error occurs.
 */
struct ProviderStateIterator *pactffi_sync_http_get_provider_state_iter(struct SynchronousHttp *interaction);

/**
 * Casts this interaction to a `SynchronousHttp` interaction. Returns a NULL pointer if the
 * interaction can not be casted to a `SynchronousHttp` interaction (for instance, it is a
 * message interaction). The returned pointer must be freed with `pactffi_sync_http_delete`
 * when no longer required.
 *
 * # Safety
 * This function is safe as long as the interaction pointer is a valid pointer.
 *
 * # Errors
 * On any error, this function will return a NULL pointer.
 */
const struct SynchronousHttp *pactffi_pact_interaction_as_synchronous_http(const struct PactInteraction *interaction);

/**
 * Casts this interaction to a `Message` interaction. Returns a NULL pointer if the
 * interaction can not be casted to a `Message` interaction (for instance, it is a
 * http interaction). The returned pointer must be freed with `pactffi_message_delete`
 * when no longer required.
 *
 * Note that if the interaction is a V4 `AsynchronousMessage`, it will be converted to a V3
 * `Message` before being returned.
 *
 * # Safety
 * This function is safe as long as the interaction pointer is a valid pointer.
 *
 * # Errors
 * On any error, this function will return a NULL pointer.
 */
const struct Message *pactffi_pact_interaction_as_message(const struct PactInteraction *interaction);

/**
 * Casts this interaction to a `AsynchronousMessage` interaction. Returns a NULL pointer if the
 * interaction can not be casted to a `AsynchronousMessage` interaction (for instance, it is a
 * http interaction). The returned pointer must be freed with `pactffi_async_message_delete`
 * when no longer required.
 *
 * Note that if the interaction is a V3 `Message`, it will be converted to a V4
 * `AsynchronousMessage` before being returned.
 *
 * # Safety
 * This function is safe as long as the interaction pointer is a valid pointer.
 *
 * # Errors
 * On any error, this function will return a NULL pointer.
 */
const struct AsynchronousMessage *pactffi_pact_interaction_as_asynchronous_message(const struct PactInteraction *interaction);

/**
 * Casts this interaction to a `SynchronousMessage` interaction. Returns a NULL pointer if the
 * interaction can not be casted to a `SynchronousMessage` interaction (for instance, it is a
 * http interaction). The returned pointer must be freed with `pactffi_sync_message_delete`
 * when no longer required.
 *
 * # Safety
 * This function is safe as long as the interaction pointer is a valid pointer.
 *
 * # Errors
 * On any error, this function will return a NULL pointer.
 */
const struct SynchronousMessage *pactffi_pact_interaction_as_synchronous_message(const struct PactInteraction *interaction);

/**
 * Free the iterator when you're done using it.
 */
void pactffi_pact_message_iter_delete(struct PactMessageIterator *iter);

/**
 * Get the next message from the message pact. As the messages returned are owned by the
 * iterator, they do not need to be deleted but will be cleaned up when the iterator is
 * deleted.
 *
 * Will return a NULL pointer when the iterator has advanced past the end of the list.
 *
 * # Safety
 *
 * This function is safe.
 *
 * Deleting a message returned by the iterator can lead to undefined behaviour.
 *
 * # Error Handling
 *
 * This function will return a NULL pointer if passed a NULL pointer or if an error occurs.
 */
struct Message *pactffi_pact_message_iter_next(struct PactMessageIterator *iter);

/**
 * Get the next synchronous request/response message from the V4 pact. As the messages returned are owned by the
 * iterator, they do not need to be deleted but will be cleaned up when the iterator is
 * deleted.
 *
 * Will return a NULL pointer when the iterator has advanced past the end of the list.
 *
 * # Safety
 *
 * This function is safe.
 *
 * Deleting a message returned by the iterator can lead to undefined behaviour.
 *
 * # Error Handling
 *
 * This function will return a NULL pointer if passed a NULL pointer or if an error occurs.
 */
struct SynchronousMessage *pactffi_pact_sync_message_iter_next(struct PactSyncMessageIterator *iter);

/**
 * Free the iterator when you're done using it.
 */
void pactffi_pact_sync_message_iter_delete(struct PactSyncMessageIterator *iter);

/**
 * Get the next synchronous HTTP request/response interaction from the V4 pact. As the
 * interactions returned are owned by the iterator, they do not need to be deleted but
 * will be cleaned up when the iterator is deleted.
 *
 * Will return a NULL pointer when the iterator has advanced past the end of the list.
 *
 * # Safety
 *
 * This function is safe.
 *
 * Deleting an interaction returned by the iterator can lead to undefined behaviour.
 *
 * # Error Handling
 *
 * This function will return a NULL pointer if passed a NULL pointer or if an error occurs.
 */
struct SynchronousHttp *pactffi_pact_sync_http_iter_next(struct PactSyncHttpIterator *iter);

/**
 * Free the iterator when you're done using it.
 */
void pactffi_pact_sync_http_iter_delete(struct PactSyncHttpIterator *iter);

/**
 * Get the next interaction from the pact. As the interactions returned are owned by the
 * iterator, they do not need to be deleted but will be cleaned up when the iterator is
 * deleted.
 *
 * Will return a NULL pointer when the iterator has advanced past the end of the list.
 *
 * # Safety
 *
 * This function is safe.
 *
 * Deleting an interaction returned by the iterator can lead to undefined behaviour.
 *
 * # Error Handling
 *
 * This function will return a NULL pointer if passed a NULL pointer or if an error occurs.
 */
const struct PactInteraction *pactffi_pact_interaction_iter_next(struct PactInteractionIterator *iter);

/**
 * Free the iterator when you're done using it.
 */
void pactffi_pact_interaction_iter_delete(struct PactInteractionIterator *iter);

/**
 * Get the JSON form of the matching rule.
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * # Safety
 *
 * This function will fail if it is passed a NULL pointer, or the iterator that owns the
 * value of the matching rule has been deleted.
 */
const char *pactffi_matching_rule_to_json(const struct MatchingRule *rule);

/**
 * Free the iterator when you're done using it.
 */
void pactffi_matching_rules_iter_delete(struct MatchingRuleCategoryIterator *iter);

/**
 * Get the next path and matching rule out of the iterator, if possible.
 *
 * The returned pointer must be deleted with `pactffi_matching_rules_iter_pair_delete`.
 *
 * # Safety
 *
 * The underlying data is owned by the `MatchingRuleKeyValuePair`, so is always safe to use.
 *
 * # Error Handling
 *
 * If no further data is present, returns NULL.
 */
const struct MatchingRuleKeyValuePair *pactffi_matching_rules_iter_next(struct MatchingRuleCategoryIterator *iter);

/**
 * Free a pair of key and value returned from `message_metadata_iter_next`.
 */
void pactffi_matching_rules_iter_pair_delete(const struct MatchingRuleKeyValuePair *pair);

/**
 * Get a mutable pointer to a newly-created default message on the heap.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * Returns NULL on error.
 */
struct Message *pactffi_message_new(void);

/**
 * Constructs a `Message` from the JSON string
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the JSON string is invalid or not UTF-8 encoded, returns a NULL.
 */
struct Message *pactffi_message_new_from_json(unsigned int index,
                                              const char *json_str,
                                              enum PactSpecification spec_version);

/**
 * Constructs a `Message` from a body with a given content-type.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the body or content type are invalid or not UTF-8 encoded, returns NULL.
 */
struct Message *pactffi_message_new_from_body(const char *body, const char *content_type);

/**
 * Destroy the `Message` being pointed to.
 */
void pactffi_message_delete(struct Message *message);

/**
 * Get the contents of a `Message` in string form.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * The returned string can outlive the message.
 *
 * # Error Handling
 *
 * If the message is NULL, returns NULL. If the body of the message
 * is missing, then this function also returns NULL. This means there's
 * no mechanism to differentiate with this function call alone between
 * a NULL message and a missing message body.
 */
const char *pactffi_message_get_contents(const struct Message *message);

/**
 * Sets the contents of the message.
 *
 * # Safety
 *
 * The message contents and content type must either be NULL pointers, or point to valid
 * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the message contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_message_set_contents(struct Message *message,
                                  const char *contents,
                                  const char *content_type);

/**
 * Get the length of the contents of a `Message`.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the message is NULL, returns 0. If the body of the message
 * is missing, then this function also returns 0.
 */
size_t pactffi_message_get_contents_length(const struct Message *message);

/**
 * Get the contents of a `Message` as a pointer to an array of bytes.
 *
 * # Safety
 *
 * The number of bytes in the buffer will be returned by `pactffi_message_get_contents_length`.
 * It is safe to use the pointer while the message is not deleted or changed. Using the pointer
 * after the message is mutated or deleted may lead to undefined behaviour.
 *
 * # Error Handling
 *
 * If the message is NULL, returns NULL. If the body of the message
 * is missing, then this function also returns NULL.
 */
const unsigned char *pactffi_message_get_contents_bin(const struct Message *message);

/**
 * Sets the contents of the message as an array of bytes.
 *
 * # Safety
 *
 * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned
 * and consecutive. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the message contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_message_set_contents_bin(struct Message *message,
                                      const unsigned char *contents,
                                      size_t len,
                                      const char *content_type);

/**
 * Get a copy of the description.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * Since it is a copy, the returned string may safely outlive
 * the `Message`.
 *
 * # Errors
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if the Rust string contains embedded
 * null ('\0') bytes.
 */
const char *pactffi_message_get_description(const struct Message *message);

/**
 * Write the `description` field on the `Message`.
 *
 * # Safety
 *
 * `description` must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 * This function will only reallocate if the new string
 * does not fit in the existing buffer.
 *
 * # Error Handling
 *
 * Errors will be reported with a non-zero return value.
 */
int pactffi_message_set_description(struct Message *message, const char *description);

/**
 * Get a copy of the provider state at the given index from this message.
 *
 * # Safety
 *
 * The returned structure must be deleted with `provider_state_delete`.
 *
 * Since it is a copy, the returned structure may safely outlive
 * the `Message`.
 *
 * # Error Handling
 *
 * On failure, this function will return a variant other than Success.
 *
 * This function may fail if the index requested is out of bounds,
 * or if any of the Rust strings contain embedded null ('\0') bytes.
 */
const struct ProviderState *pactffi_message_get_provider_state(const struct Message *message,
                                                               unsigned int index);

/**
 * Get an iterator over provider states.
 *
 * # Safety
 *
 * The underlying data must not change during iteration.
 *
 * # Error Handling
 *
 * Returns NULL if an error occurs.
 */
struct ProviderStateIterator *pactffi_message_get_provider_state_iter(struct Message *message);

/**
 * Get the next value from the iterator.
 *
 * # Safety
 *
 * The underlying data must not change during iteration.
 *
 * If a previous call panicked, then the internal mutex will have been poisoned and this
 * function will return NULL.
 *
 * # Error Handling
 *
 * Returns NULL if an error occurs.
 */
struct ProviderState *pactffi_provider_state_iter_next(struct ProviderStateIterator *iter);

/**
 * Delete the iterator.
 */
void pactffi_provider_state_iter_delete(struct ProviderStateIterator *iter);

/**
 * Get a copy of the metadata value indexed by `key`.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * Since it is a copy, the returned string may safely outlive
 * the `Message`.
 *
 * The returned pointer will be NULL if the metadata does not contain
 * the given key, or if an error occurred.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if the provided `key` string contains
 * invalid UTF-8, or if the Rust string contains embedded null ('\0')
 * bytes.
 */
const char *pactffi_message_find_metadata(const struct Message *message, const char *key);

/**
 * Insert the (`key`, `value`) pair into this Message's
 * `metadata` HashMap.
 *
 * # Safety
 *
 * This function returns an enum indicating the result;
 * see the comments on HashMapInsertStatus for details.
 *
 * # Error Handling
 *
 * This function may fail if the provided `key` or `value` strings
 * contain invalid UTF-8.
 */
int pactffi_message_insert_metadata(struct Message *message, const char *key, const char *value);

/**
 * Get the next key and value out of the iterator, if possible.
 *
 * The returned pointer must be deleted with `pactffi_message_metadata_pair_delete`.
 *
 * # Safety
 *
 * The underlying data must not change during iteration.
 *
 * # Error Handling
 *
 * If no further data is present, returns NULL.
 */
struct MessageMetadataPair *pactffi_message_metadata_iter_next(struct MessageMetadataIterator *iter);

/**
 * Get an iterator over the metadata of a message.
 *
 * # Safety
 *
 * This iterator carries a pointer to the message, and must
 * not outlive the message.
 *
 * The message metadata also must not be modified during iteration. If it is,
 * the old iterator must be deleted and a new iterator created.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if any of the Rust strings contain
 * embedded null ('\0') bytes.
 */
struct MessageMetadataIterator *pactffi_message_get_metadata_iter(struct Message *message);

/**
 * Free the metadata iterator when you're done using it.
 */
void pactffi_message_metadata_iter_delete(struct MessageMetadataIterator *iter);

/**
 * Free a pair of key and value returned from `message_metadata_iter_next`.
 */
void pactffi_message_metadata_pair_delete(struct MessageMetadataPair *pair);

/**
 * Construct a new `MessagePact` from the JSON string.
 * The provided file name is used when generating error messages.
 *
 * # Safety
 *
 * The `file_name` and `json_str` parameters must both be valid UTF-8
 * encoded strings.
 *
 * # Error Handling
 *
 * On error, this function will return a null pointer.
 */
struct MessagePact *pactffi_message_pact_new_from_json(const char *file_name, const char *json_str);

/**
 * Delete the `MessagePact` being pointed to.
 */
void pactffi_message_pact_delete(struct MessagePact *message_pact);

/**
 * Get a pointer to the Consumer struct inside the MessagePact.
 * This is a mutable borrow: The caller may mutate the Consumer
 * through this pointer.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * This function will only fail if it is passed a NULL pointer.
 * In the case of error, a NULL pointer will be returned.
 */
struct Consumer *pactffi_message_pact_get_consumer(struct MessagePact *message_pact);

/**
 * Get a pointer to the Provider struct inside the MessagePact.
 * This is a mutable borrow: The caller may mutate the Provider
 * through this pointer.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * This function will only fail if it is passed a NULL pointer.
 * In the case of error, a NULL pointer will be returned.
 */
struct Provider *pactffi_message_pact_get_provider(struct MessagePact *message_pact);

/**
 * Get an iterator over the messages of a message pact.
 *
 * # Safety
 *
 * This iterator carries a pointer to the message pact, and must
 * not outlive the message pact.
 *
 * The message pact messages also must not be modified during iteration.
 * If they are, the old iterator must be deleted and a new iterator created.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if any of the Rust strings contain embedded
 * null ('\0') bytes.
 */
struct MessagePactMessageIterator *pactffi_message_pact_get_message_iter(struct MessagePact *message_pact);

/**
 * Get the next message from the message pact.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * This function will return a NULL pointer if passed a NULL pointer or if an error occurs.
 */
struct Message *pactffi_message_pact_message_iter_next(struct MessagePactMessageIterator *iter);

/**
 * Delete the iterator.
 */
void pactffi_message_pact_message_iter_delete(struct MessagePactMessageIterator *iter);

/**
 * Get a copy of the metadata value indexed by `key1` and `key2`.
 *
 * # Safety
 *
 * Since it is a copy, the returned string may safely outlive
 * the `Message`.
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * The returned pointer will be NULL if the metadata does not contain
 * the given key, or if an error occurred.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if the provided `key1` or `key2` strings contains
 * invalid UTF-8, or if the Rust string contains embedded null ('\0')
 * bytes.
 */
const char *pactffi_message_pact_find_metadata(const struct MessagePact *message_pact,
                                               const char *key1,
                                               const char *key2);

/**
 * Get an iterator over the metadata of a message pact.
 *
 * # Safety
 *
 * This iterator carries a pointer to the message pact, and must
 * not outlive the message pact.
 *
 * The message pact metadata also must not be modified during iteration. If it is,
 * the old iterator must be deleted and a new iterator created.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if any of the Rust strings contain
 * embedded null ('\0') bytes.
 */
struct MessagePactMetadataIterator *pactffi_message_pact_get_metadata_iter(struct MessagePact *message_pact);

/**
 * Get the next triple out of the iterator, if possible
 *
 * # Safety
 *
 * This operation is invalid if the underlying data has been changed during iteration.
 *
 * # Error Handling
 *
 * Returns null if no next element is present.
 */
struct MessagePactMetadataTriple *pactffi_message_pact_metadata_iter_next(struct MessagePactMetadataIterator *iter);

/**
 * Free the metadata iterator when you're done using it.
 */
void pactffi_message_pact_metadata_iter_delete(struct MessagePactMetadataIterator *iter);

/**
 * Free a triple returned from `pactffi_message_pact_metadata_iter_next`.
 */
void pactffi_message_pact_metadata_triple_delete(struct MessagePactMetadataTriple *triple);

/**
 * Get a copy of this provider's name.
 *
 * The copy must be deleted with `pactffi_string_delete`.
 *
 * # Usage
 *
 * ```c
 * // Assuming `file_name` and `json_str` are already defined.
 *
 * MessagePact *message_pact = pactffi_message_pact_new_from_json(file_name, json_str);
 * if (message_pact == NULLPTR) {
 *     // handle error.
 * }
 *
 * Provider *provider = pactffi_message_pact_get_provider(message_pact);
 * if (provider == NULLPTR) {
 *     // handle error.
 * }
 *
 * char *name = pactffi_provider_get_name(provider);
 * if (name == NULL) {
 *     // handle error.
 * }
 *
 * printf("%s\n", name);
 *
 * pactffi_string_delete(name);
 * ```
 *
 * # Errors
 *
 * This function will fail if it is passed a NULL pointer,
 * or the Rust string contains an embedded NULL byte.
 * In the case of error, a NULL pointer will be returned.
 */
const char *pactffi_provider_get_name(const struct Provider *provider);

/**
 * Get the provider from a Pact. This returns a copy of the provider model, and needs to
 * be cleaned up with `pactffi_pact_provider_delete` when no longer required.
 *
 * # Errors
 *
 * This function will fail if it is passed a NULL pointer.
 * In the case of error, a NULL pointer will be returned.
 */
const struct Provider *pactffi_pact_get_provider(const struct Pact *pact);

/**
 * Frees the memory used by the Pact provider
 */
void pactffi_pact_provider_delete(const struct Provider *provider);

/**
 * Get the name of the provider state as a string, which needs to be deleted with `pactffi_string_delete`.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the provider_state param is NULL, this returns NULL.
 */
const char *pactffi_provider_state_get_name(const struct ProviderState *provider_state);

/**
 * Get an iterator over the params of a provider state.
 *
 * # Safety
 *
 * This iterator carries a pointer to the provider state, and must
 * not outlive the provider state.
 *
 * The provider state params also must not be modified during iteration. If it is,
 * the old iterator must be deleted and a new iterator created.
 *
 * # Errors
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if any of the Rust strings contain
 * embedded null ('\0') bytes.
 */
struct ProviderStateParamIterator *pactffi_provider_state_get_param_iter(struct ProviderState *provider_state);

/**
 * Get the next key and value out of the iterator, if possible
 *
 * Returns a pointer to a heap allocated array of 2 elements, the pointer to the
 * key string on the heap, and the pointer to the value string on the heap.
 *
 * # Safety
 *
 * The underlying data must not be modified during iteration.
 *
 * The user needs to free both the contained strings and the array.
 *
 * # Error Handling
 *
 * Returns NULL if there's no further elements or the iterator is NULL.
 */
struct ProviderStateParamPair *pactffi_provider_state_param_iter_next(struct ProviderStateParamIterator *iter);

/**
 * Free the provider state when you're done using it.
 */
void pactffi_provider_state_delete(struct ProviderState *provider_state);

/**
 * Free the provider state param iterator when you're done using it.
 */
void pactffi_provider_state_param_iter_delete(struct ProviderStateParamIterator *iter);

/**
 * Free a pair of key and value returned from `pactffi_provider_state_param_iter_next`.
 */
void pactffi_provider_state_param_pair_delete(struct ProviderStateParamPair *pair);

/**
 * Get a mutable pointer to a newly-created default message on the heap.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * Returns NULL on error.
 */
struct SynchronousMessage *pactffi_sync_message_new(void);

/**
 * Destroy the `Message` being pointed to.
 */
void pactffi_sync_message_delete(struct SynchronousMessage *message);

/**
 * Get the request contents of a `SynchronousMessage` in string form.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * The returned string can outlive the message.
 *
 * # Error Handling
 *
 * If the message is NULL, returns NULL. If the body of the request message
 * is missing, then this function also returns NULL. This means there's
 * no mechanism to differentiate with this function call alone between
 * a NULL message and a missing message body.
 */
const char *pactffi_sync_message_get_request_contents_str(const struct SynchronousMessage *message);

/**
 * Sets the request contents of the message.
 *
 * * `message` - the message to set the request contents for
 * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer.
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The message contents and content type must either be NULL pointers, or point to valid
 * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the message contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_sync_message_set_request_contents_str(struct SynchronousMessage *message,
                                                   const char *contents,
                                                   const char *content_type);

/**
 * Get the length of the request contents of a `SynchronousMessage`.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the message is NULL, returns 0. If the body of the request
 * is missing, then this function also returns 0.
 */
size_t pactffi_sync_message_get_request_contents_length(const struct SynchronousMessage *message);

/**
 * Get the request contents of a `SynchronousMessage` as a pointer to an array of bytes.
 *
 * # Safety
 *
 * The number of bytes in the buffer will be returned by `pactffi_sync_message_get_request_contents_length`.
 * It is safe to use the pointer while the message is not deleted or changed. Using the pointer
 * after the message is mutated or deleted may lead to undefined behaviour.
 *
 * # Error Handling
 *
 * If the message is NULL, returns NULL. If the body of the message
 * is missing, then this function also returns NULL.
 */
const unsigned char *pactffi_sync_message_get_request_contents_bin(const struct SynchronousMessage *message);

/**
 * Sets the request contents of the message as an array of bytes.
 *
 * * `message` - the message to set the request contents for
 * * `contents` - pointer to contents to copy from
 * * `len` - number of bytes to copy from the contents pointer
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned
 * and consecutive. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the message contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_sync_message_set_request_contents_bin(struct SynchronousMessage *message,
                                                   const unsigned char *contents,
                                                   size_t len,
                                                   const char *content_type);

/**
 * Get the request contents of an `SynchronousMessage` as a `MessageContents` pointer.
 *
 * # Safety
 *
 * The data pointed to by the pointer this function returns will be deleted when the message
 * is deleted. Trying to use if after the message is deleted will result in undefined behaviour.
 *
 * # Error Handling
 *
 * If the message is NULL, returns NULL.
 */
const struct MessageContents *pactffi_sync_message_get_request_contents(const struct SynchronousMessage *message);

/**
 * Get the number of response messages in the `SynchronousMessage`.
 *
 * # Safety
 *
 * The message pointer must point to a valid SynchronousMessage.
 *
 * # Error Handling
 *
 * If the message is NULL, returns 0.
 */
size_t pactffi_sync_message_get_number_responses(const struct SynchronousMessage *message);

/**
 * Get the response contents of a `SynchronousMessage` in string form.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * The returned string can outlive the message.
 *
 * # Error Handling
 *
 * If the message is NULL or the index is not valid, returns NULL.
 *
 * If the body of the response message is missing, then this function also returns NULL.
 * This means there's no mechanism to differentiate with this function call alone between
 * a NULL message and a missing message body.
 */
const char *pactffi_sync_message_get_response_contents_str(const struct SynchronousMessage *message,
                                                           size_t index);

/**
 * Sets the response contents of the message as a string. If index is greater than the number of responses
 * in the message, the responses will be padded with default values.
 *
 * * `message` - the message to set the response contents for
 * * `index` - index of the response to set. 0 is the first response.
 * * `contents` - pointer to contents to copy from. Must be a valid NULL-terminated UTF-8 string pointer.
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The message contents and content type must either be NULL pointers, or point to valid
 * UTF-8 encoded NULL-terminated strings. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the response contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_sync_message_set_response_contents_str(struct SynchronousMessage *message,
                                                    size_t index,
                                                    const char *contents,
                                                    const char *content_type);

/**
 * Get the length of the response contents of a `SynchronousMessage`.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * If the message is NULL or the index is not valid, returns 0. If the body of the request
 * is missing, then this function also returns 0.
 */
size_t pactffi_sync_message_get_response_contents_length(const struct SynchronousMessage *message,
                                                         size_t index);

/**
 * Get the response contents of a `SynchronousMessage` as a pointer to an array of bytes.
 *
 * # Safety
 *
 * The number of bytes in the buffer will be returned by `pactffi_sync_message_get_response_contents_length`.
 * It is safe to use the pointer while the message is not deleted or changed. Using the pointer
 * after the message is mutated or deleted may lead to undefined behaviour.
 *
 * # Error Handling
 *
 * If the message is NULL or the index is not valid, returns NULL. If the body of the message
 * is missing, then this function also returns NULL.
 */
const unsigned char *pactffi_sync_message_get_response_contents_bin(const struct SynchronousMessage *message,
                                                                    size_t index);

/**
 * Sets the response contents of the message at the given index as an array of bytes. If index
 * is greater than the number of responses in the message, the responses will be padded with
 * default values.
 *
 * * `message` - the message to set the response contents for
 * * `index` - index of the response to set. 0 is the first response
 * * `contents` - pointer to contents to copy from
 * * `len` - number of bytes to copy
 * * `content_type` - pointer to the NULL-terminated UTF-8 string containing the content type of the data.
 *
 * # Safety
 *
 * The contents pointer must be valid for reads of `len` bytes, and it must be properly aligned
 * and consecutive. Otherwise behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the message contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as unknown.
 */
void pactffi_sync_message_set_response_contents_bin(struct SynchronousMessage *message,
                                                    size_t index,
                                                    const unsigned char *contents,
                                                    size_t len,
                                                    const char *content_type);

/**
 * Get the response contents of an `SynchronousMessage` as a `MessageContents` pointer.
 *
 * # Safety
 *
 * The data pointed to by the pointer this function returns will be deleted when the message
 * is deleted. Trying to use if after the message is deleted will result in undefined behaviour.
 *
 * # Error Handling
 *
 * If the message is NULL or the index is not valid, returns NULL.
 */
const struct MessageContents *pactffi_sync_message_get_response_contents(const struct SynchronousMessage *message,
                                                                         size_t index);

/**
 * Get a copy of the description.
 *
 * # Safety
 *
 * The returned string must be deleted with `pactffi_string_delete`.
 *
 * Since it is a copy, the returned string may safely outlive
 * the `SynchronousMessage`.
 *
 * # Errors
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if the Rust string contains embedded
 * null ('\0') bytes.
 */
const char *pactffi_sync_message_get_description(const struct SynchronousMessage *message);

/**
 * Write the `description` field on the `SynchronousMessage`.
 *
 * # Safety
 *
 * `description` must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 * This function will only reallocate if the new string
 * does not fit in the existing buffer.
 *
 * # Error Handling
 *
 * Errors will be reported with a non-zero return value.
 */
int pactffi_sync_message_set_description(struct SynchronousMessage *message,
                                         const char *description);

/**
 * Get a copy of the provider state at the given index from this message.
 *
 * # Safety
 *
 * The returned structure must be deleted with `provider_state_delete`.
 *
 * Since it is a copy, the returned structure may safely outlive
 * the `SynchronousMessage`.
 *
 * # Error Handling
 *
 * On failure, this function will return a variant other than Success.
 *
 * This function may fail if the index requested is out of bounds,
 * or if any of the Rust strings contain embedded null ('\0') bytes.
 */
const struct ProviderState *pactffi_sync_message_get_provider_state(const struct SynchronousMessage *message,
                                                                    unsigned int index);

/**
 * Get an iterator over provider states.
 *
 * # Safety
 *
 * The underlying data must not change during iteration.
 *
 * # Error Handling
 *
 * Returns NULL if an error occurs.
 */
struct ProviderStateIterator *pactffi_sync_message_get_provider_state_iter(struct SynchronousMessage *message);

/**
 * Delete a string previously returned by this FFI.
 *
 * It is explicitly allowed to pass a null pointer to this function;
 * in that case the function will do nothing.
 *
 * # Safety
 * Passing an invalid pointer, or one that was not returned by a FFI function can result in
 * undefined behaviour.
 */
void pactffi_string_delete(char *string);

/**
 * [DEPRECATED] External interface to create a HTTP mock server. A pointer to the pact JSON as a NULL-terminated C
 * string is passed in, as well as the port for the mock server to run on. A value of 0 for the
 * port will result in a port being allocated by the operating system. The port of the mock server is returned.
 *
 * * `pact_str` - Pact JSON
 * * `addr_str` - Address to bind to in the form name:port (i.e. 127.0.0.1:0)
 * * `tls` - boolean flag to indicate of the mock server should use TLS (using a self-signed certificate)
 *
 * This function is deprecated and replaced with `pactffi_create_mock_server_for_transport`.
 *
 * # Errors
 *
 * Errors are returned as negative values.
 *
 * | Error | Description |
 * |-------|-------------|
 * | -1 | A null pointer was received |
 * | -2 | The pact JSON could not be parsed |
 * | -3 | The mock server could not be started |
 * | -4 | The method panicked |
 * | -5 | The address is not valid |
 * | -6 | Could not create the TLS configuration with the self-signed certificate |
 *
 */
int32_t pactffi_create_mock_server(const char *pact_str,
                                   const char *addr_str,
                                   bool tls);

/**
 * Fetch the CA Certificate used to generate the self-signed certificate for the TLS mock server.
 *
 * **NOTE:** The string for the result is allocated on the heap, and will have to be freed
 * by the caller using pactffi_string_delete.
 *
 * # Errors
 *
 * An empty string indicates an error reading the pem file.
 */
char *pactffi_get_tls_ca_certificate(void);

/**
 * [DEPRECATED] External interface to create a HTTP mock server. A Pact handle is passed in,
 * as well as the port for the mock server to run on. A value of 0 for the port will result in a
 * port being allocated by the operating system. The port of the mock server is returned.
 *
 * * `pact` - Handle to a Pact model created with created with `pactffi_new_pact`.
 * * `addr_str` - Address to bind to in the form name:port (i.e. 127.0.0.1:0). Must be a valid UTF-8 NULL-terminated string.
 * * `tls` - boolean flag to indicate of the mock server should use TLS (using a self-signed certificate)
 *
 * This function is deprecated and replaced with `pactffi_create_mock_server_for_transport`.
 *
 * # Errors
 *
 * Errors are returned as negative values.
 *
 * | Error | Description |
 * |-------|-------------|
 * | -1 | An invalid handle was received. Handles should be created with `pactffi_new_pact` |
 * | -3 | The mock server could not be started |
 * | -4 | The method panicked |
 * | -5 | The address is not valid |
 * | -6 | Could not create the TLS configuration with the self-signed certificate |
 *
 */
int32_t pactffi_create_mock_server_for_pact(PactHandle pact,
                                            const char *addr_str,
                                            bool tls);

/**
 * Create a mock server for the provided Pact handle and transport. If the transport is not
 * provided (it is a NULL pointer or an empty string), will default to an HTTP transport. The
 * address is the interface bind to, and will default to the loopback adapter if not specified.
 * Specifying a value of zero for the port will result in the operating system allocating the port.
 *
 * Parameters:
 * * `pact` - Handle to a Pact model created with created with `pactffi_new_pact`.
 * * `addr` - Address to bind to (i.e. `127.0.0.1` or `[::1]`). Must be a valid UTF-8 NULL-terminated string, or NULL or empty, in which case the loopback adapter is used.
 * * `port` - Port number to bind to. A value of zero will result in the operating system allocating an available port.
 * * `transport` - The transport to use (i.e. http, https, grpc). Must be a valid UTF-8 NULL-terminated string, or NULL or empty, in which case http will be used.
 * * `transport_config` - (OPTIONAL) Configuration for the transport as a valid JSON string. Set to NULL or empty if not required.
 *
 * The port of the mock server is returned.
 *
 * # Safety
 * NULL pointers or empty strings can be passed in for the address, transport and transport_config,
 * in which case a default value will be used. Passing in an invalid pointer will result in undefined behaviour.
 *
 * # Errors
 *
 * Errors are returned as negative values.
 *
 * | Error | Description |
 * |-------|-------------|
 * | -1 | An invalid handle was received. Handles should be created with `pactffi_new_pact` |
 * | -2 | transport_config is not valid JSON |
 * | -3 | The mock server could not be started |
 * | -4 | The method panicked |
 * | -5 | The address is not valid |
 *
 */
int32_t pactffi_create_mock_server_for_transport(PactHandle pact,
                                                 const char *addr,
                                                 uint16_t port,
                                                 const char *transport,
                                                 const char *transport_config);

/**
 * External interface to check if a mock server has matched all its requests. The port number is
 * passed in, and if all requests have been matched, true is returned. False is returned if there
 * is no mock server on the given port, or if any request has not been successfully matched, or
 * the method panics.
 */
bool pactffi_mock_server_matched(int32_t mock_server_port);

/**
 * External interface to get all the mismatches from a mock server. The port number of the mock
 * server is passed in, and a pointer to a C string with the mismatches in JSON format is
 * returned.
 *
 * **NOTE:** The JSON string for the result is allocated on the heap, and will have to be freed
 * once the code using the mock server is complete. The [`cleanup_mock_server`](fn.cleanup_mock_server.html) function is
 * provided for this purpose.
 *
 * # Errors
 *
 * If there is no mock server with the provided port number, or the function panics, a NULL
 * pointer will be returned. Don't try to dereference it, it will not end well for you.
 *
 */
char *pactffi_mock_server_mismatches(int32_t mock_server_port);

/**
 * External interface to cleanup a mock server. This function will try terminate the mock server
 * with the given port number and cleanup any memory allocated for it. Returns true, unless a
 * mock server with the given port number does not exist, or the function panics.
 */
bool pactffi_cleanup_mock_server(int32_t mock_server_port);

/**
 * External interface to trigger a mock server to write out its pact file. This function should
 * be called if all the consumer tests have passed. The directory to write the file to is passed
 * as the second parameter. If a NULL pointer is passed, the current working directory is used.
 *
 * If overwrite is true, the file will be overwritten with the contents of the current pact.
 * Otherwise, it will be merged with any existing pact file.
 *
 * Returns 0 if the pact file was successfully written. Returns a positive code if the file can
 * not be written, or there is no mock server running on that port or the function panics.
 *
 * # Errors
 *
 * Errors are returned as positive values.
 *
 * | Error | Description |
 * |-------|-------------|
 * | 1 | A general panic was caught |
 * | 2 | The pact file was not able to be written |
 * | 3 | A mock server with the provided port was not found |
 */
int32_t pactffi_write_pact_file(int32_t mock_server_port, const char *directory, bool overwrite);

/**
 * Fetch the logs for the mock server. This needs the memory buffer log sink to be setup before
 * the mock server is started. Returned string will be freed with the `cleanup_mock_server`
 * function call.
 *
 * Will return a NULL pointer if the logs for the mock server can not be retrieved.
 */
const char *pactffi_mock_server_logs(int32_t mock_server_port);

/**
 * Generates a datetime value from the provided format string, using the current system date and time
 * NOTE: The memory for the returned string needs to be freed with the `pactffi_string_delete` function
 *
 * # Safety
 *
 * If the format string pointer is NULL or has invalid UTF-8 characters, an error result will be
 * returned. If the format string pointer is not a valid pointer or is not a NULL-terminated string,
 * this will lead to undefined behaviour.
 */
struct StringResult pactffi_generate_datetime_string(const char *format);

/**
 * Checks that the example string matches the given regex.
 *
 * # Safety
 *
 * Both the regex and example pointers must be valid pointers to NULL-terminated strings. Invalid
 * pointers will result in undefined behaviour.
 */
bool pactffi_check_regex(const char *regex, const char *example);

/**
 * Generates an example string based on the provided regex.
 * NOTE: The memory for the returned string needs to be freed with the `pactffi_string_delete` function.
 *
 * # Safety
 *
 * The regex pointer must be a valid pointer to a NULL-terminated string. Invalid pointers will
 * result in undefined behaviour.
 */
struct StringResult pactffi_generate_regex_value(const char *regex);

/**
 * [DEPRECATED] Frees the memory allocated to a string by another function
 *
 * This function is deprecated. Use `pactffi_string_delete` instead.
 *
 * # Safety
 *
 * The string pointer can be NULL (which is a no-op), but if it is not a valid pointer the call
 * will result in undefined behaviour.
 */
void pactffi_free_string(char *s);

/**
 * Creates a new Pact model and returns a handle to it.
 *
 * * `consumer_name` - The name of the consumer for the pact.
 * * `provider_name` - The name of the provider for the pact.
 *
 * Returns a new `PactHandle`. The handle will need to be freed with the `pactffi_free_pact_handle`
 * method to release its resources.
 */
PactHandle pactffi_new_pact(const char *consumer_name, const char *provider_name);

/**
 * Creates a new HTTP Interaction and returns a handle to it.
 *
 * * `description` - The interaction description. It needs to be unique for each interaction.
 *
 * Returns a new `InteractionHandle`.
 */
InteractionHandle pactffi_new_interaction(PactHandle pact, const char *description);

/**
 * Creates a new message interaction and return a handle to it
 * * `description` - The interaction description. It needs to be unique for each interaction.
 *
 * Returns a new `InteractionHandle`.
 */
InteractionHandle pactffi_new_message_interaction(PactHandle pact, const char *description);

/**
 * Creates a new synchronous message interaction (request/response) and return a handle to it
 * * `description` - The interaction description. It needs to be unique for each interaction.
 *
 * Returns a new `InteractionHandle`.
 */
InteractionHandle pactffi_new_sync_message_interaction(PactHandle pact, const char *description);

/**
 * Sets the description for the Interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `description` - The interaction description. It needs to be unique for each interaction.
 */
bool pactffi_upon_receiving(InteractionHandle interaction, const char *description);

/**
 * Adds a provider state to the Interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `description` - The provider state description. It needs to be unique.
 */
bool pactffi_given(InteractionHandle interaction, const char *description);

/**
 * Sets the test name annotation for the interaction. This allows capturing the name of
 * the test as metadata. This can only be used with V4 interactions.
 *
 * # Safety
 *
 * The test name parameter must be a valid pointer to a NULL terminated string.
 *
 * # Error Handling
 *
 * If the test name can not be set, this will return a positive value.
 *
 * * `1` - Function panicked. Error message will be available by calling `pactffi_get_error_message`.
 * * `2` - Handle was not valid.
 * * `3` - Mock server was already started and the integration can not be modified.
 * * `4` - Not a V4 interaction.
 */
unsigned int pactffi_interaction_test_name(InteractionHandle interaction,
                                           const char *test_name);

/**
 * Adds a parameter key and value to a provider state to the Interaction. If the provider state
 * does not exist, a new one will be created, otherwise the parameter will be merged into the
 * existing one. The parameter value will be parsed as JSON.
 *
 * Returns false if the interaction or Pact can't be modified (i.e. the mock server for it has
 * already started).
 *
 * # Parameters
 * * `description` - The provider state description. It needs to be unique.
 * * `name` - Parameter name.
 * * `value` - Parameter value as JSON.
 */
bool pactffi_given_with_param(InteractionHandle interaction,
                              const char *description,
                              const char *name,
                              const char *value);

/**
 * Adds a provider state to the Interaction with a set of parameter key and value pairs in JSON
 * form. If the params is not an JSON object, it will add it as a single parameter with a `value`
 * key.
 *
 * # Parameters
 * * `description` - The provider state description.
 * * `params` - Parameter values as a JSON fragment.
 *
 * # Errors
 * Returns EXIT_FAILURE (1) if the interaction or Pact can't be modified (i.e. the mock server
 * for it has already started).
 * Returns 2 and sets the error message (which can be retrieved with `pactffi_get_error_message`)
 * if the parameter values con't be parsed as JSON.
 * Returns 3 if any of the C strings are not valid.
 *
 */
int pactffi_given_with_params(InteractionHandle interaction,
                              const char *description,
                              const char *params);

/**
 * Configures the request for the Interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `method` - The request method. Defaults to GET.
 * * `path` - The request path. Defaults to `/`.
 *
 * To include matching rules for the path (only regex really makes sense to use), include the
 * matching rule JSON format with the value as a single JSON document. I.e.
 *
 * ```c
 * const char* value = "{\"value\":\"/path/to/100\", \"pact:matcher:type\":\"regex\", \"regex\":\"\\/path\\/to\\/\\\\d+\"}";
 * pactffi_with_request(handle, "GET", value);
 * ```
 * See [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md)
 */
bool pactffi_with_request(InteractionHandle interaction,
                          const char *method,
                          const char *path);

/**
 * Configures a query parameter for the Interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `name` - the query parameter name.
 * * `value` - the query parameter value.
 * * `index` - the index of the value (starts at 0). You can use this to create a query parameter with multiple values
 *
 * **DEPRECATED:** Use `pactffi_with_query_parameter_v2`, which deals with multiple values correctly
 */
bool pactffi_with_query_parameter(InteractionHandle interaction,
                                  const char *name,
                                  size_t index,
                                  const char *value);

/**
 * Configures a query parameter for the Interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `name` - the query parameter name.
 * * `value` - the query parameter value. Either a simple string or a JSON document.
 * * `index` - the index of the value (starts at 0). You can use this to create a query parameter with multiple values
 *
 * To setup a query parameter with multiple values, you can either call this function multiple times
 * with a different index value, i.e. to create `id=2&id=3`
 *
 * ```c
 * pactffi_with_query_parameter_v2(handle, "id", 0, "2");
 * pactffi_with_query_parameter_v2(handle, "id", 1, "3");
 * ```
 *
 * Or you can call it once with a JSON value that contains multiple values:
 *
 * ```c
 * const char* value = "{\"value\": [\"2\",\"3\"]}";
 * pactffi_with_query_parameter_v2(handle, "id", 0, value);
 * ```
 *
 * To include matching rules for the query parameter, include the matching rule JSON format with
 * the value as a single JSON document. I.e.
 *
 * ```c
 * const char* value = "{\"value\":\"2\", \"pact:matcher:type\":\"regex\", \"regex\":\"\\\\d+\"}";
 * pactffi_with_query_parameter_v2(handle, "id", 0, value);
 * ```
 * See [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md)
 *
 * # Safety
 * The name and value parameters must be valid pointers to NULL terminated strings.
 * ```
 */
bool pactffi_with_query_parameter_v2(InteractionHandle interaction,
                                     const char *name,
                                     size_t index,
                                     const char *value);

/**
 * Sets the specification version for a given Pact model. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started) or the version is invalid.
 *
 * * `pact` - Handle to a Pact model
 * * `version` - the spec version to use
 */
bool pactffi_with_specification(PactHandle pact,
                                enum PactSpecification version);

/**
 * Sets the additional metadata on the Pact file. Common uses are to add the client library details such as the name and version
 * Returns false if the interaction or Pact can't be modified (i.e. the mock server for it has already started)
 *
 * * `pact` - Handle to a Pact model
 * * `namespace` - the top level metadat key to set any key values on
 * * `name` - the key to set
 * * `value` - the value to set
 */
bool pactffi_with_pact_metadata(PactHandle pact,
                                const char *namespace_,
                                const char *name,
                                const char *value);

/**
 * Configures a header for the Interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `part` - The part of the interaction to add the header to (Request or Response).
 * * `name` - the header name.
 * * `value` - the header value.
 * * `index` - the index of the value (starts at 0). You can use this to create a header with multiple values
 *
 * **DEPRECATED:** Use `pactffi_with_header_v2`, which deals with multiple values correctly
 */
bool pactffi_with_header(InteractionHandle interaction,
                         enum InteractionPart part,
                         const char *name,
                         size_t index,
                         const char *value);

/**
 * Configures a header for the Interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `part` - The part of the interaction to add the header to (Request or Response).
 * * `name` - the header name.
 * * `value` - the header value.
 * * `index` - the index of the value (starts at 0). You can use this to create a header with multiple values
 *
 * To setup a header with multiple values, you can either call this function multiple times
 * with a different index value, i.e. to create `x-id=2, 3`
 *
 * ```c
 * pactffi_with_header_v2(handle, InteractionPart::Request, "x-id", 0, "2");
 * pactffi_with_header_v2(handle, InteractionPart::Request, "x-id", 1, "3");
 * ```
 *
 * Or you can call it once with a JSON value that contains multiple values:
 *
 * ```c
 * const char* value = "{\"value\": [\"2\",\"3\"]}";
 * pactffi_with_header_v2(handle, InteractionPart::Request, "x-id", 0, value);
 * ```
 *
 * To include matching rules for the header, include the matching rule JSON format with
 * the value as a single JSON document. I.e.
 *
 * ```c
 * const char* value = "{\"value\":\"2\", \"pact:matcher:type\":\"regex\", \"regex\":\"\\\\d+\"}";
 * pactffi_with_header_v2(handle, InteractionPart::Request, "id", 0, value);
 * ```
 * See [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md)
 *
 * # Safety
 * The name and value parameters must be valid pointers to NULL terminated strings.
 */
bool pactffi_with_header_v2(InteractionHandle interaction,
                            enum InteractionPart part,
                            const char *name,
                            size_t index,
                            const char *value);

/**
 * Configures the response for the Interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `status` - the response status. Defaults to 200.
 */
bool pactffi_response_status(InteractionHandle interaction, unsigned short status);

/**
 * Adds the body for the interaction. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `part` - The part of the interaction to add the body to (Request or Response).
 * * `content_type` - The content type of the body. Defaults to `text/plain`. Will be ignored if a content type
 *   header is already set.
 * * `body` - The body contents. For JSON payloads, matching rules can be embedded in the body. See
 * [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md)
 *
 * For HTTP and async message interactions, this will overwrite the body. With asynchronous messages, the
 * part parameter will be ignored. With synchronous messages, the request contents will be overwritten,
 * while a new response will be appended to the message.
 *
 * # Safety
 *
 * The interaction contents and content type must either be NULL pointers, or point to valid
 * UTF-8 encoded NULL-terminated strings. Otherwise, behaviour is undefined.
 *
 * # Error Handling
 *
 * If the contents is a NULL pointer, it will set the body contents as null. If the content
 * type is a null pointer, or can't be parsed, it will set the content type as TEXT.
 * Returns false if the interaction or Pact can't be modified (i.e. the mock server for it has
 * already started) or an error has occurred.
 */
bool pactffi_with_body(InteractionHandle interaction,
                       enum InteractionPart part,
                       const char *content_type,
                       const char *body);

/**
 * Adds a binary file as the body with the expected content type and example contents. Will use
 * a mime type matcher to match the body. Returns false if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started)
 *
 * * `interaction` - Interaction handle to set the body for.
 * * `part` - Request or response part.
 * * `content_type` - Expected content type.
 * * `body` - example body contents in bytes
 * * `size` - number of bytes in the body
 *
 * For HTTP and async message interactions, this will overwrite the body. With asynchronous messages, the
 * part parameter will be ignored. With synchronous messages, the request contents will be overwritten,
 * while a new response will be appended to the message.
 *
 * # Safety
 *
 * The content type must be a valid UTF-8 encoded NULL-terminated string. The body pointer must
 * be valid for reads of `size` bytes, and it must be properly aligned and consecutive.
 *
 * # Error Handling
 *
 * If the body is a NULL pointer, it will set the body contents as null. If the content
 * type is a null pointer, or can't be parsed, it will return false.
 * Returns false if the interaction or Pact can't be modified (i.e. the mock server for it has
 * already started) or an error has occurred.
 */
bool pactffi_with_binary_file(InteractionHandle interaction,
                              enum InteractionPart part,
                              const char *content_type,
                              const uint8_t *body,
                              size_t size);

/**
 * Adds a binary file as the body as a MIME multipart with the expected content type and example contents. Will use
 * a mime type matcher to match the body. Returns an error if the interaction or Pact can't be
 * modified (i.e. the mock server for it has already started) or an error occurs.
 *
 * * `interaction` - Interaction handle to set the body for.
 * * `part` - Request or response part.
 * * `content_type` - Expected content type of the file.
 * * `file` - path to the example file
 * * `part_name` - name for the mime part
 *
 * # Safety
 *
 * The content type, file path and part name must be valid pointers to UTF-8 encoded NULL-terminated strings.
 * Passing invalid pointers or pointers to strings that are not NULL terminated will lead to undefined
 * behaviour.
 *
 * # Error Handling
 *
 * If the file path is a NULL pointer, it will set the body contents as as an empty mime-part.
 * If the file path does not point to a valid file, or is not able to be read, it will return an
 * error result. If the content type is a null pointer, or can't be parsed, it will return an error result.
 * Returns an error if the interaction or Pact can't be modified (i.e. the mock server for it has
 * already started), the interaction is not an HTTP interaction or some other error occurs.
 */
struct StringResult pactffi_with_multipart_file(InteractionHandle interaction,
                                                enum InteractionPart part,
                                                const char *content_type,
                                                const char *file,
                                                const char *part_name);

/**
 * Get an iterator over all the messages of the Pact. The returned iterator needs to be
 * freed with `pactffi_pact_message_iter_delete`.
 *
 * # Safety
 *
 * The iterator contains a copy of the Pact, so it is always safe to use.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if any of the Rust strings contain embedded
 * null ('\0') bytes.
 */
struct PactMessageIterator *pactffi_pact_handle_get_message_iter(PactHandle pact);

/**
 * Get an iterator over all the synchronous request/response messages of the Pact.
 * The returned iterator needs to be freed with `pactffi_pact_sync_message_iter_delete`.
 *
 * # Safety
 *
 * The iterator contains a copy of the Pact, so it is always safe to use.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if any of the Rust strings contain embedded
 * null ('\0') bytes.
 */
struct PactSyncMessageIterator *pactffi_pact_handle_get_sync_message_iter(PactHandle pact);

/**
 * Get an iterator over all the synchronous HTTP request/response interactions of the Pact.
 * The returned iterator needs to be freed with `pactffi_pact_sync_http_iter_delete`.
 *
 * # Safety
 *
 * The iterator contains a copy of the Pact, so it is always safe to use.
 *
 * # Error Handling
 *
 * On failure, this function will return a NULL pointer.
 *
 * This function may fail if any of the Rust strings contain embedded
 * null ('\0') bytes.
 */
struct PactSyncHttpIterator *pactffi_pact_handle_get_sync_http_iter(PactHandle pact);

/**
 * Creates a new Pact Message model and returns a handle to it.
 *
 * * `consumer_name` - The name of the consumer for the pact.
 * * `provider_name` - The name of the provider for the pact.
 *
 * Returns a new `MessagePactHandle`. The handle will need to be freed with the `pactffi_free_message_pact_handle`
 * function to release its resources.
 */
MessagePactHandle pactffi_new_message_pact(const char *consumer_name,
                                           const char *provider_name);

/**
 * Creates a new Message and returns a handle to it.
 *
 * * `description` - The message description. It needs to be unique for each Message.
 *
 * Returns a new `MessageHandle`.
 */
MessageHandle pactffi_new_message(MessagePactHandle pact, const char *description);

/**
 * Sets the description for the Message.
 *
 * * `description` - The message description. It needs to be unique for each message.
 */
void pactffi_message_expects_to_receive(MessageHandle message, const char *description);

/**
 * Adds a provider state to the Interaction.
 *
 * * `description` - The provider state description. It needs to be unique for each message
 */
void pactffi_message_given(MessageHandle message, const char *description);

/**
 * Adds a provider state to the Message with a parameter key and value.
 *
 * * `description` - The provider state description. It needs to be unique.
 * * `name` - Parameter name.
 * * `value` - Parameter value.
 */
void pactffi_message_given_with_param(MessageHandle message,
                                      const char *description,
                                      const char *name,
                                      const char *value);

/**
 * Adds the contents of the Message.
 *
 * Accepts JSON, binary and other payload types. Binary data will be base64 encoded when serialised.
 *
 * Note: For text bodies (plain text, JSON or XML), you can pass in a C string (NULL terminated)
 * and the size of the body is not required (it will be ignored). For binary bodies, you need to
 * specify the number of bytes in the body.
 *
 * * `content_type` - The content type of the body. Defaults to `text/plain`, supports JSON structures with matchers and binary data.
 * * `body` - The body contents as bytes. For text payloads (JSON, XML, etc.), a C string can be used and matching rules can be embedded in the body.
 * * `content_type` - Expected content type (e.g. application/json, application/octet-stream)
 * * `size` - number of bytes in the message body to read. This is not required for text bodies (JSON, XML, etc.).
 */
void pactffi_message_with_contents(MessageHandle message_handle,
                                   const char *content_type,
                                   const uint8_t *body,
                                   size_t size);

/**
 * Adds expected metadata to the Message
 *
 * * `key` - metadata key
 * * `value` - metadata value.
 */
void pactffi_message_with_metadata(MessageHandle message_handle,
                                   const char *key,
                                   const char *value);

/**
 * Reifies the given message
 *
 * Reification is the process of stripping away any matchers, and returning the original contents.
 * NOTE: the returned string needs to be deallocated with the `free_string` function
 */
const char *pactffi_message_reify(MessageHandle message_handle);

/**
 * External interface to write out the message pact file. This function should
 * be called if all the consumer tests have passed. The directory to write the file to is passed
 * as the second parameter. If a NULL pointer is passed, the current working directory is used.
 *
 * If overwrite is true, the file will be overwritten with the contents of the current pact.
 * Otherwise, it will be merged with any existing pact file.
 *
 * Returns 0 if the pact file was successfully written. Returns a positive code if the file can
 * not be written, or there is no mock server running on that port or the function panics.
 *
 * # Errors
 *
 * Errors are returned as positive values.
 *
 * | Error | Description |
 * |-------|-------------|
 * | 1 | The pact file was not able to be written |
 * | 2 | The message pact for the given handle was not found |
 */
int32_t pactffi_write_message_pact_file(MessagePactHandle pact,
                                        const char *directory,
                                        bool overwrite);

/**
 * Sets the additional metadata on the Pact file. Common uses are to add the client library details such as the name and version
 *
 * * `pact` - Handle to a Pact model
 * * `namespace` - the top level metadat key to set any key values on
 * * `name` - the key to set
 * * `value` - the value to set
 */
void pactffi_with_message_pact_metadata(MessagePactHandle pact,
                                        const char *namespace_,
                                        const char *name,
                                        const char *value);

/**
 * External interface to write out the pact file. This function should
 * be called if all the consumer tests have passed. The directory to write the file to is passed
 * as the second parameter. If a NULL pointer is passed, the current working directory is used.
 *
 * If overwrite is true, the file will be overwritten with the contents of the current pact.
 * Otherwise, it will be merged with any existing pact file.
 *
 * Returns 0 if the pact file was successfully written. Returns a positive code if the file can
 * not be written or the function panics.
 *
 * # Safety
 *
 * The directory parameter must either be NULL or point to a valid NULL terminated string.
 *
 * # Errors
 *
 * Errors are returned as positive values.
 *
 * | Error | Description |
 * |-------|-------------|
 * | 1 | The function panicked. |
 * | 2 | The pact file was not able to be written. |
 * | 3 | The pact for the given handle was not found. |
 */
int32_t pactffi_pact_handle_write_file(PactHandle pact, const char *directory, bool overwrite);

/**
 * Creates a new V4 asynchronous message and returns a handle to it.
 *
 * * `description` - The message description. It needs to be unique for each Message.
 *
 * Returns a new `MessageHandle`.
 */
MessageHandle pactffi_new_async_message(PactHandle pact, const char *description);

/**
 * Delete a Pact handle and free the resources used by it.
 *
 * # Error Handling
 *
 * On failure, this function will return a positive integer value.
 *
 * * `1` - The handle is not valid or does not refer to a valid Pact. Could be that it was previously deleted.
 *
 */
unsigned int pactffi_free_pact_handle(PactHandle pact);

/**
 * Delete a Pact handle and free the resources used by it.
 *
 * # Error Handling
 *
 * On failure, this function will return a positive integer value.
 *
 * * `1` - The handle is not valid or does not refer to a valid Pact. Could be that it was previously deleted.
 *
 */
unsigned int pactffi_free_message_pact_handle(MessagePactHandle pact);

/**
 * External interface to verifier a provider
 *
 * * `args` - the same as the CLI interface, except newline delimited
 *
 * # Errors
 *
 * Errors are returned as non-zero numeric values.
 *
 * | Error | Description |
 * |-------|-------------|
 * | 1 | The verification process failed, see output for errors |
 * | 2 | A null pointer was received |
 * | 3 | The method panicked |
 * | 4 | Invalid arguments were provided to the verification process |
 *
 * # Safety
 *
 * Exported functions are inherently unsafe. Deal.
 */
int32_t pactffi_verify(const char *args);

/**
 * Get a Handle to a newly created verifier. You should call `pactffi_verifier_shutdown` when
 * done with the verifier to free all allocated resources.
 *
 * Deprecated: This function is deprecated. Use `pactffi_verifier_new_for_application` which allows the
 * calling application/framework name and version to be specified.
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * Returns NULL on error.
 */
struct VerifierHandle *pactffi_verifier_new(void);

/**
 * Get a Handle to a newly created verifier. You should call `pactffi_verifier_shutdown` when
 * done with the verifier to free all allocated resources
 *
 * # Safety
 *
 * This function is safe.
 *
 * # Error Handling
 *
 * Returns NULL on error.
 */
struct VerifierHandle *pactffi_verifier_new_for_application(const char *name, const char *version);

/**
 * Shutdown the verifier and release all resources
 */
void pactffi_verifier_shutdown(struct VerifierHandle *handle);

/**
 * Set the provider details for the Pact verifier. Passing a NULL for any field will
 * use the default value for that field.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_set_provider_info(struct VerifierHandle *handle,
                                        const char *name,
                                        const char *scheme,
                                        const char *host,
                                        unsigned short port,
                                        const char *path);

/**
 * Adds a new transport for the given provider. Passing a NULL for any field will
 * use the default value for that field.
 *
 * For non-plugin based message interactions, set protocol to "message" and set scheme
 * to an empty string or "https" if secure HTTP is required. Communication to the calling
 * application will be over HTTP to the default provider hostname.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_add_provider_transport(struct VerifierHandle *handle,
                                             const char *protocol,
                                             unsigned short port,
                                             const char *path,
                                             const char *scheme);

/**
 * Set the filters for the Pact verifier.
 *
 * If `filter_description` is not empty, it needs to be as a regular expression.
 *
 * `filter_no_state` is a boolean value. Set it to greater than zero to turn the option on.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_set_filter_info(struct VerifierHandle *handle,
                                      const char *filter_description,
                                      const char *filter_state,
                                      unsigned char filter_no_state);

/**
 * Set the provider state URL for the Pact verifier.
 *
 * `teardown` is a boolean value. If teardown state change requests should be made after an
 * interaction is validated (default is false). Set it to greater than zero to turn the
 * option on.
 * `body` is a boolean value. Sets if state change request data should be sent in the body
 * (> 0, true) or as query parameters (== 0, false). Set it to greater than zero to turn the
 * option on.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_set_provider_state(struct VerifierHandle *handle,
                                         const char *url,
                                         unsigned char teardown,
                                         unsigned char body);

/**
 * Set the options used by the verifier when calling the provider
 *
 * `disable_ssl_verification` is a boolean value. Set it to greater than zero to turn the option on.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
int pactffi_verifier_set_verification_options(struct VerifierHandle *handle,
                                              unsigned char disable_ssl_verification,
                                              unsigned long request_timeout);

/**
 * Enables or disables coloured output using ANSI escape codes in the verifier output. By default,
 * coloured output is enabled.
 *
 * `coloured_output` is a boolean value. Set it to greater than zero to turn the option on.
 *
 * # Safety
 *
 * This function is safe as long as the handle pointer points to a valid handle.
 *
 */
int pactffi_verifier_set_coloured_output(struct VerifierHandle *handle,
                                         unsigned char coloured_output);

/**
 * Enables or disables if no pacts are found to verify results in an error.
 *
 * `is_error` is a boolean value. Set it to greater than zero to enable an error when no pacts
 * are found to verify, and set it to zero to disable this.
 *
 * # Safety
 *
 * This function is safe as long as the handle pointer points to a valid handle.
 *
 */
int pactffi_verifier_set_no_pacts_is_error(struct VerifierHandle *handle, unsigned char is_error);

/**
 * Set the options used when publishing verification results to the Pact Broker
 *
 * # Args
 *
 * - `handle` - The pact verifier handle to update
 * - `provider_version` - Version of the provider to publish
 * - `build_url` - URL to the build which ran the verification
 * - `provider_tags` - Collection of tags for the provider
 * - `provider_tags_len` - Number of provider tags supplied
 * - `provider_branch` - Name of the branch used for verification
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
int pactffi_verifier_set_publish_options(struct VerifierHandle *handle,
                                         const char *provider_version,
                                         const char *build_url,
                                         const char *const *provider_tags,
                                         unsigned short provider_tags_len,
                                         const char *provider_branch);

/**
 * Set the consumer filters for the Pact verifier.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_set_consumer_filters(struct VerifierHandle *handle,
                                           const char *const *consumer_filters,
                                           unsigned short consumer_filters_len);

/**
 * Adds a custom header to be added to the requests made to the provider.
 *
 * # Safety
 *
 * The header name and value must point to a valid NULL terminated string and must contain
 * valid UTF-8.
 */
void pactffi_verifier_add_custom_header(struct VerifierHandle *handle,
                                        const char *header_name,
                                        const char *header_value);

/**
 * Adds a Pact file as a source to verify.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_add_file_source(struct VerifierHandle *handle, const char *file);

/**
 * Adds a Pact directory as a source to verify. All pacts from the directory that match the
 * provider name will be verified.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_add_directory_source(struct VerifierHandle *handle, const char *directory);

/**
 * Adds a URL as a source to verify. The Pact file will be fetched from the URL.
 *
 * If a username and password is given, then basic authentication will be used when fetching
 * the pact file. If a token is provided, then bearer token authentication will be used.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_url_source(struct VerifierHandle *handle,
                                 const char *url,
                                 const char *username,
                                 const char *password,
                                 const char *token);

/**
 * Adds a Pact broker as a source to verify. This will fetch all the pact files from the broker
 * that match the provider name.
 *
 * If a username and password is given, then basic authentication will be used when fetching
 * the pact file. If a token is provided, then bearer token authentication will be used.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_broker_source(struct VerifierHandle *handle,
                                    const char *url,
                                    const char *username,
                                    const char *password,
                                    const char *token);

/**
 * Adds a Pact broker as a source to verify. This will fetch all the pact files from the broker
 * that match the provider name and the consumer version selectors
 * (See `https://docs.pact.io/pact_broker/advanced_topics/consumer_version_selectors/`).
 *
 * The consumer version selectors must be passed in in JSON format.
 *
 * `enable_pending` is a boolean value. Set it to greater than zero to turn the option on.
 *
 * If the `include_wip_pacts_since` option is provided, it needs to be a date formatted in
 * ISO format (YYYY-MM-DD).
 *
 * If a username and password is given, then basic authentication will be used when fetching
 * the pact file. If a token is provided, then bearer token authentication will be used.
 *
 * # Safety
 *
 * All string fields must contain valid UTF-8. Invalid UTF-8
 * will be replaced with U+FFFD REPLACEMENT CHARACTER.
 *
 */
void pactffi_verifier_broker_source_with_selectors(struct VerifierHandle *handle,
                                                   const char *url,
                                                   const char *username,
                                                   const char *password,
                                                   const char *token,
                                                   unsigned char enable_pending,
                                                   const char *include_wip_pacts_since,
                                                   const char *const *provider_tags,
                                                   unsigned short provider_tags_len,
                                                   const char *provider_branch,
                                                   const char *const *consumer_version_selectors,
                                                   unsigned short consumer_version_selectors_len,
                                                   const char *const *consumer_version_tags,
                                                   unsigned short consumer_version_tags_len);

/**
 * Runs the verification.
 *
 * # Error Handling
 *
 * Errors will be reported with a non-zero return value.
 */
int pactffi_verifier_execute(struct VerifierHandle *handle);

/**
 * External interface to retrieve the options and arguments available when calling the CLI interface,
 * returning them as a JSON string.
 *
 * The purpose is to then be able to use in other languages which wrap the FFI library, to implement
 * the same CLI functionality automatically without manual maintenance of arguments, help descriptions
 * etc.
 *
 * # Example structure
 * ```json
 * {
 *   "options": [
 *     {
 *       "long": "scheme",
 *       "help": "Provider URI scheme (defaults to http)",
 *       "possible_values": [
 *         "http",
 *         "https"
 *       ],
 *       "default_value": "http"
 *       "multiple": false,
 *     },
 *     {
 *       "long": "file",
 *       "short": "f",
 *       "help": "Pact file to verify (can be repeated)",
 *       "multiple": true
 *     },
 *     {
 *       "long": "user",
 *       "help": "Username to use when fetching pacts from URLS",
 *       "multiple": false,
 *       "env": "PACT_BROKER_USERNAME"
 *     }
 *   ],
 *   "flags": [
 *     {
 *       "long": "disable-ssl-verification",
 *       "help": "Disables validation of SSL certificates",
 *       "multiple": false
 *     }
 *   ]
 * }
 * ```
 *
 * # Safety
 *
 * Exported functions are inherently unsafe.
 */
const char *pactffi_verifier_cli_args(void);

/**
 * Extracts the logs for the verification run. This needs the memory buffer log sink to be
 * setup before the verification is executed. The returned string will need to be freed with
 * the `free_string` function call to avoid leaking memory.
 *
 * Will return a NULL pointer if the logs for the verification can not be retrieved.
 */
const char *pactffi_verifier_logs(const struct VerifierHandle *handle);

/**
 * Extracts the logs for the verification run for the provider name. This needs the memory
 * buffer log sink to be setup before the verification is executed. The returned string will
 * need to be freed with the `free_string` function call to avoid leaking memory.
 *
 * Will return a NULL pointer if the logs for the verification can not be retrieved.
 */
const char *pactffi_verifier_logs_for_provider(const char *provider_name);

/**
 * Extracts the standard output for the verification run. The returned string will need to be
 * freed with the `free_string` function call to avoid leaking memory.
 *
 * * `strip_ansi` - This parameter controls ANSI escape codes. Setting it to a non-zero value
 * will cause the ANSI control codes to be stripped from the output.
 *
 * Will return a NULL pointer if the handle is invalid.
 */
const char *pactffi_verifier_output(const struct VerifierHandle *handle, unsigned char strip_ansi);

/**
 * Extracts the verification result as a JSON document. The returned string will need to be
 * freed with the `free_string` function call to avoid leaking memory.
 *
 * Will return a NULL pointer if the handle is invalid.
 */
const char *pactffi_verifier_json(const struct VerifierHandle *handle);

/**
 * Add a plugin to be used by the test. The plugin needs to be installed correctly for this
 * function to work.
 *
 * * `plugin_name` is the name of the plugin to load.
 * * `plugin_version` is the version of the plugin to load. It is optional, and can be NULL.
 *
 * Returns zero on success, and a positive integer value on failure.
 *
 * Note that plugins run as separate processes, so will need to be cleaned up afterwards by
 * calling `pactffi_cleanup_plugins` otherwise you will have plugin processes left running.
 *
 * # Safety
 *
 * `plugin_name` must be a valid pointer to a NULL terminated string. `plugin_version` may be null,
 * and if not NULL must also be a valid pointer to a NULL terminated string. Invalid
 * pointers will result in undefined behaviour.
 *
 * # Errors
 *
 * * `1` - A general panic was caught.
 * * `2` - Failed to load the plugin.
 * * `3` - Pact Handle is not valid.
 *
 * When an error errors, LAST_ERROR will contain the error message.
 */
unsigned int pactffi_using_plugin(PactHandle pact,
                                  const char *plugin_name,
                                  const char *plugin_version);

/**
 * Decrement the access count on any plugins that are loaded for the Pact. This will shutdown
 * any plugins that are no longer required (access count is zero).
 */
void pactffi_cleanup_plugins(PactHandle pact);

/**
 * Setup the interaction part using a plugin. The contents is a JSON string that will be passed on to
 * the plugin to configure the interaction part. Refer to the plugin documentation on the format
 * of the JSON contents.
 *
 * Returns zero on success, and a positive integer value on failure.
 *
 * * `interaction` - Handle to the interaction to configure.
 * * `part` - The part of the interaction to configure (request or response). It is ignored for messages.
 * * `content_type` - NULL terminated C string of the content type of the part.
 * * `contents` - NULL terminated C string of the JSON contents that gets passed to the plugin.
 *
 * # Safety
 *
 * `content_type` and `contents` must be a valid pointers to NULL terminated strings. Invalid
 * pointers will result in undefined behaviour.
 *
 * # Errors
 *
 * * `1` - A general panic was caught.
 * * `2` - The mock server has already been started.
 * * `3` - The interaction handle is invalid.
 * * `4` - The content type is not valid.
 * * `5` - The contents JSON is not valid JSON.
 * * `6` - The plugin returned an error.
 *
 * When an error errors, LAST_ERROR will contain the error message.
 */
unsigned int pactffi_interaction_contents(InteractionHandle interaction,
                                          enum InteractionPart part,
                                          const char *content_type,
                                          const char *contents);

/**
 * Determines if the string value matches the given matching rule. If the value matches OK,
 * will return a NULL pointer. If the value does not match, will return a error message as
 * a NULL terminated string. The error message pointer will need to be deleted with the
 * `pactffi_string_delete` function once it is no longer required.
 *
 * * matching_rule - pointer to a matching rule
 * * expected_value - value we expect to get as a NULL terminated string
 * * actual_value - value to match as a NULL terminated string
 * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true
 *
 * # Safety
 *
 * The matching rule pointer must be a valid pointer, and the value parameters must be
 * valid pointers to a NULL terminated strings.
 */
const char *pactffi_matches_string_value(const struct MatchingRule *matching_rule,
                                         const char *expected_value,
                                         const char *actual_value,
                                         uint8_t cascaded);

/**
 * Determines if the unsigned integer value matches the given matching rule. If the value matches OK,
 * will return a NULL pointer. If the value does not match, will return a error message as
 * a NULL terminated string. The error message pointer will need to be deleted with the
 * `pactffi_string_delete` function once it is no longer required.
 *
 * * matching_rule - pointer to a matching rule
 * * expected_value - value we expect to get
 * * actual_value - value to match
 * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true
 *
 * # Safety
 *
 * The matching rule pointer must be a valid pointer.
 */
const char *pactffi_matches_u64_value(const struct MatchingRule *matching_rule,
                                      uint64_t expected_value,
                                      uint64_t actual_value,
                                      uint8_t cascaded);

/**
 * Determines if the signed integer value matches the given matching rule. If the value matches OK,
 * will return a NULL pointer. If the value does not match, will return a error message as
 * a NULL terminated string. The error message pointer will need to be deleted with the
 * `pactffi_string_delete` function once it is no longer required.
 *
 * * matching_rule - pointer to a matching rule
 * * expected_value - value we expect to get
 * * actual_value - value to match
 * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true
 *
 * # Safety
 *
 * The matching rule pointer must be a valid pointer.
 */
const char *pactffi_matches_i64_value(const struct MatchingRule *matching_rule,
                                      int64_t expected_value,
                                      int64_t actual_value,
                                      uint8_t cascaded);

/**
 * Determines if the floating point value matches the given matching rule. If the value matches OK,
 * will return a NULL pointer. If the value does not match, will return a error message as
 * a NULL terminated string. The error message pointer will need to be deleted with the
 * `pactffi_string_delete` function once it is no longer required.
 *
 * * matching_rule - pointer to a matching rule
 * * expected_value - value we expect to get
 * * actual_value - value to match
 * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true
 *
 * # Safety
 *
 * The matching rule pointer must be a valid pointer.
 */
const char *pactffi_matches_f64_value(const struct MatchingRule *matching_rule,
                                      double expected_value,
                                      double actual_value,
                                      uint8_t cascaded);

/**
 * Determines if the boolean value matches the given matching rule. If the value matches OK,
 * will return a NULL pointer. If the value does not match, will return a error message as
 * a NULL terminated string. The error message pointer will need to be deleted with the
 * `pactffi_string_delete` function once it is no longer required.
 *
 * * matching_rule - pointer to a matching rule
 * * expected_value - value we expect to get, 0 == false and 1 == true
 * * actual_value - value to match, 0 == false and 1 == true
 * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true
 *
 * # Safety
 *
 * The matching rule pointer must be a valid pointer.
 */
const char *pactffi_matches_bool_value(const struct MatchingRule *matching_rule,
                                       uint8_t expected_value,
                                       uint8_t actual_value,
                                       uint8_t cascaded);

/**
 * Determines if the binary value matches the given matching rule. If the value matches OK,
 * will return a NULL pointer. If the value does not match, will return a error message as
 * a NULL terminated string. The error message pointer will need to be deleted with the
 * `pactffi_string_delete` function once it is no longer required.
 *
 * * matching_rule - pointer to a matching rule
 * * expected_value - value we expect to get
 * * expected_value_len - length of the expected value bytes
 * * actual_value - value to match
 * * actual_value_len - length of the actual value bytes
 * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true
 *
 * # Safety
 *
 * The matching rule, expected value and actual value pointers must be a valid pointers.
 * expected_value_len and actual_value_len must contain the number of bytes that the value
 * pointers point to. Passing invalid lengths can lead to undefined behaviour.
 */
const char *pactffi_matches_binary_value(const struct MatchingRule *matching_rule,
                                         const unsigned char *expected_value,
                                         uintptr_t expected_value_len,
                                         const unsigned char *actual_value,
                                         uintptr_t actual_value_len,
                                         uint8_t cascaded);

/**
 * Determines if the JSON value matches the given matching rule. If the value matches OK,
 * will return a NULL pointer. If the value does not match, will return a error message as
 * a NULL terminated string. The error message pointer will need to be deleted with the
 * `pactffi_string_delete` function once it is no longer required.
 *
 * * matching_rule - pointer to a matching rule
 * * expected_value - value we expect to get as a NULL terminated string
 * * actual_value - value to match as a NULL terminated string
 * * cascaded - if the matching rule has been cascaded from a parent. 0 == false, 1 == true
 *
 * # Safety
 *
 * The matching rule pointer must be a valid pointer, and the value parameters must be
 * valid pointers to a NULL terminated strings.
 */
const char *pactffi_matches_json_value(const struct MatchingRule *matching_rule,
                                       const char *expected_value,
                                       const char *actual_value,
                                       uint8_t cascaded);

#endif /* pact_ffi_h */
