/* The C ABI for obby-client. Generated by cbindgen: do not edit by hand.
 *
 * Thread safety: a handle is not synchronised. Never use one handle from two threads at once, not
 * even for two calls that only read. Give each thread its own handle, or take your own lock. */

#ifndef OBBY_FFI_H
#define OBBY_FFI_H

/* Generated with cbindgen:0.29.4 */

/* Regenerate with: cbindgen --config bindings/obby-ffi/cbindgen.toml --crate obby-ffi --output bindings/obby-ffi/include/obby_ffi.h */

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

/**
 * What an [`ObbyEvent`] is.
 *
 * `Unknown` covers an event this ABI has no case for yet, which a caller reads with
 * [`obby_event_json`] rather than being blind to it.
 */
typedef enum obby_event_kind {
    /**
     * An event this ABI does not name. Read it with [`obby_event_json`].
     */
    OBBY_EVENT_KIND_UNKNOWN = 0,
    /**
     * The server acknowledged the capabilities we asked for.
     */
    OBBY_EVENT_KIND_CAPABILITIES_ACKNOWLEDGED,
    /**
     * Registration finished and the connection is usable.
     */
    OBBY_EVENT_KIND_REGISTERED,
    /**
     * One `005` token, with its value when it has one.
     */
    OBBY_EVENT_KIND_ISUPPORT_TOKEN,
    /**
     * SASL authentication succeeded.
     */
    OBBY_EVENT_KIND_LOGGED_IN,
    /**
     * SASL authentication failed.
     */
    OBBY_EVENT_KIND_SASL_FAILED,
    /**
     * The nick we asked for is taken.
     */
    OBBY_EVENT_KIND_NICK_IN_USE,
    /**
     * The model changed. The change itself is in [`obby_event_json`].
     */
    OBBY_EVENT_KIND_MODEL_CHANGED,
    /**
     * The link is dead and the host should redial.
     */
    OBBY_EVENT_KIND_LINK_DEAD,
    /**
     * Redial after this many milliseconds.
     */
    OBBY_EVENT_KIND_RECONNECT_AFTER,
    /**
     * Reconnection gave up.
     */
    OBBY_EVENT_KIND_RECONNECT_ABANDONED,
    /**
     * A command we labelled went unanswered.
     */
    OBBY_EVENT_KIND_COMMAND_TIMED_OUT,
    /**
     * The commands the server lets us use changed.
     */
    OBBY_EVENT_KIND_ALLOWED_COMMANDS_CHANGED,
    /**
     * A voice signalling frame. The frame is in [`obby_event_json`].
     */
    OBBY_EVENT_KIND_VOICE,
    /**
     * Someone started or stopped composing a message.
     */
    OBBY_EVENT_KIND_TYPING_CHANGED,
    /**
     * Someone we monitor came online or went offline.
     */
    OBBY_EVENT_KIND_PRESENCE_CHANGED,
    /**
     * A `standard-replies` FAIL, WARN or NOTE.
     */
    OBBY_EVENT_KIND_SERVER_REPLY,
    /**
     * A line the engine does not model. The message is in [`obby_event_json`].
     */
    OBBY_EVENT_KIND_RAW_LINE,
    /**
     * What we know about a bot changed.
     */
    OBBY_EVENT_KIND_BOTS_CHANGED,
    /**
     * The server minted a bearer token for one of its services.
     */
    OBBY_EVENT_KIND_AUTH_TOKEN,
} obby_event_kind;

/**
 * One value on an [`ObbyEvent`].
 *
 * An event only has the fields its kind defines, and [`obby_event_text`] answers null for the
 * rest. Numbers, including the booleans, are read with [`obby_event_number`].
 */
typedef enum obby_event_field {
    /**
     * The nick an event is about.
     */
    OBBY_EVENT_FIELD_NICK = 0,
    /**
     * The account we authenticated as.
     */
    OBBY_EVENT_FIELD_ACCOUNT,
    /**
     * A `005` token name.
     */
    OBBY_EVENT_FIELD_TOKEN,
    /**
     * A `005` token's value.
     */
    OBBY_EVENT_FIELD_VALUE,
    /**
     * The nick the server refused.
     */
    OBBY_EVENT_FIELD_REFUSED,
    /**
     * The nick being tried instead.
     */
    OBBY_EVENT_FIELD_TRYING,
    /**
     * Why something failed.
     */
    OBBY_EVENT_FIELD_REASON,
    /**
     * The command an event is about.
     */
    OBBY_EVENT_FIELD_COMMAND,
    /**
     * The channel or nick an event is about.
     */
    OBBY_EVENT_FIELD_TARGET,
    /**
     * The channel an event is about.
     */
    OBBY_EVENT_FIELD_CHANNEL,
    /**
     * A numeric or named reply code.
     */
    OBBY_EVENT_FIELD_CODE,
    /**
     * Human-readable text from the server.
     */
    OBBY_EVENT_FIELD_TEXT,
    /**
     * `fail`, `warn` or `note`.
     */
    OBBY_EVENT_FIELD_SEVERITY,
    /**
     * The capability names the server acknowledged, separated by spaces.
     */
    OBBY_EVENT_FIELD_NAMES,
    /**
     * How long to wait before redialling, in milliseconds. Read with [`obby_event_number`].
     */
    OBBY_EVENT_FIELD_AFTER_MS,
    /**
     * 1 when someone is composing, 0 when they stopped. Read with [`obby_event_number`].
     */
    OBBY_EVENT_FIELD_ACTIVE,
    /**
     * 1 when someone is online, 0 when they are not. Read with [`obby_event_number`].
     */
    OBBY_EVENT_FIELD_ONLINE,
    /**
     * The network service a token is for.
     */
    OBBY_EVENT_FIELD_SERVICE,
    /**
     * Where to present a token.
     */
    OBBY_EVENT_FIELD_ENDPOINT,
    /**
     * A bearer token. `Token` is already the name of a `005` token, which this is not.
     */
    OBBY_EVENT_FIELD_BEARER_TOKEN,
} obby_event_field;

/**
 * One connection's engine state.
 *
 * Created by [`obby_client_new`] and destroyed by [`obby_client_free`]. The caller only ever holds
 * a pointer to one; every operation on it goes through a function in this crate.
 */
typedef struct obby_client_t obby_client_t;

/**
 * One event, owned by the caller until [`obby_event_free`].
 *
 * The strings [`obby_event_text`] and [`obby_event_json`] return point into this event and die
 * with it, so copy anything that must outlive the call to free.
 */
typedef struct obby_event_t obby_event_t;

/**
 * An owned byte buffer handed out by [`obby_client_poll_transmit`].
 *
 * Freed with [`obby_client_free_bytes`], the only legal way to release it. An empty buffer is
 * always the zeroed value: a null `ptr` and a zero `len`, which is safe to free as a no-op.
 */
typedef struct obby_bytes_t {
    /**
     * The first byte, or null when `len` is zero.
     */
    uint8_t *ptr;
    /**
     * How many bytes `ptr` points to.
     */
    size_t len;
} obby_bytes_t;

/**
 * A client's settings, in C types.
 *
 * Only `nick` is required. Every pointer may be null, and a null means "use the default": the
 * nick for `username` and `realname`, no password, no SASL. A zero `retention` keeps the engine's
 * own message limit.
 *
 * [`obby_client_new_from_json`] takes the fields this omits, such as SASL credentials and the
 * alternate nicks to try when one is taken.
 */
typedef struct obby_config_t {
    /**
     * The nick to register with. Required.
     */
    const char *nick;
    /**
     * The username sent in `USER`, or null for the nick.
     */
    const char *username;
    /**
     * The realname sent in `USER`, or null for the nick.
     */
    const char *realname;
    /**
     * The server password sent as `PASS`, or null for none.
     */
    const char *password;
    /**
     * How many messages each channel and conversation keeps, or 0 for the default.
     */
    size_t retention;
} obby_config_t;

/**
 * Create a client from a JSON-encoded [`Config`], for a caller that wants a field
 * [`ObbyConfig`] does not have, such as SASL credentials or alternate nicks.
 *
 * Returns null when `config_json` is null, is not valid UTF-8, or does not parse as a `Config`.
 *
 * # Safety
 * `config_json` must be null or point to a NUL-terminated, valid UTF-8 C string, valid for reads
 * for the duration of this call.
 */
struct obby_client_t *obby_client_new_from_json(const char *config_json);

/**
 * Destroy a client created by [`obby_client_new`].
 *
 * # Safety
 * `client` must be null or a pointer returned by [`obby_client_new`] that has not already been
 * freed. It must not be used again after this call.///
 *
 * The handle must not be in use on another thread while this call runs.
 */
void obby_client_free(struct obby_client_t *client);

/**
 * Tell the engine the transport is up. See [`obby_client::Client::handle_connected`].
 *
 * # Safety
 * `client` must be null or a valid, non-freed pointer from [`obby_client_new`].
 *
 * The handle must not be in use on another thread while this call runs.
 */
void obby_client_handle_connected(struct obby_client_t *client);

/**
 * Tell the engine its transport died. See [`obby_client::Client::handle_disconnected`].
 *
 * # Safety
 * `client` must be null or a valid, non-freed pointer from [`obby_client_new`].
 *
 * The handle must not be in use on another thread while this call runs.
 */
void obby_client_handle_disconnected(struct obby_client_t *client);

/**
 * Feed bytes read from the transport.
 *
 * A null `data` is only valid when `len` is zero; any other null-with-nonzero-length call is
 * treated as if nothing were fed, rather than read out of bounds.
 *
 * # Safety
 * `client` must be null or valid. When `len` is greater than zero, `data` must point to at least
 * `len` readable bytes, valid for the duration of this call.
 *
 * The handle must not be in use on another thread while this call runs.
 */
void obby_client_handle_bytes(struct obby_client_t *client, const uint8_t *data, size_t len);

/**
 * Drain one pending outbound buffer, or the empty [`ObbyBytes`] when there is none.
 *
 * # Safety
 * `client` must be null or a valid, non-freed pointer from [`obby_client_new`].
 *
 * The handle must not be in use on another thread while this call runs.
 */
struct obby_bytes_t obby_client_poll_transmit(struct obby_client_t *client);

/**
 * Free a buffer returned by [`obby_client_poll_transmit`].
 *
 * The only legal way to release one. Freeing the zeroed value (null `ptr`, zero `len`) is a no-op.
 *
 * # Safety
 * `bytes` must be a value returned by [`obby_client_poll_transmit`] that has not already been
 * freed, or the zeroed value.///
 */
void obby_client_free_bytes(struct obby_bytes_t bytes);

/**
 * Drain every pending event as one JSON array, `"[]"` when there are none.
 *
 * Returns null only when `client` is null; a working client always produces valid JSON.
 *
 * # Safety
 * `client` must be null or a valid, non-freed pointer from [`obby_client_new`].
 *
 * The handle must not be in use on another thread while this call runs.
 */
char *obby_client_poll_events_json(struct obby_client_t *client);

/**
 * Free a string returned by [`obby_client_poll_events_json`] or [`obby_client_model_json`].
 *
 * The only legal way to release one. Never pass the pointer returned by [`obby_client_version`]
 * here: that one is static and owned by the library, not by the caller.
 *
 * # Safety
 * `s` must be null, or a pointer returned by [`obby_client_poll_events_json`] or
 * [`obby_client_model_json`] that has not already been freed.///
 */
void obby_client_free_string(char *s);

/**
 * Advance the clock. See [`obby_client::Client::tick`].
 *
 * # Safety
 * `client` must be null or a valid, non-freed pointer from [`obby_client_new`].
 *
 * The handle must not be in use on another thread while this call runs.
 */
void obby_client_tick(struct obby_client_t *client, uint64_t monotonic_ms, uint64_t unix_ms);

/**
 * When the engine next has something to do, if ever.
 *
 * Returns `true` and writes the deadline to `*out_ms` when one is pending; returns `false`
 * otherwise, writing zero to `*out_ms` when it is non-null so the caller never reads uninitialised
 * memory either way.
 *
 * # Safety
 * `client` must be null or valid. `out_ms` must be null or point to a writable `u64` valid for the
 * duration of this call.///
 *
 * The handle must not be in use on another thread while this call runs.
 */
bool obby_client_poll_timeout(struct obby_client_t *client, uint64_t *out_ms);

/**
 * Submit any command, as JSON.
 *
 * Every command has this form; the ones a client sends constantly also have a function of their
 * own, such as [`obby_client_join`].
 *
 * Returns `true` when it parsed and was submitted, `false` when `client` or `command_json` is
 * null, `command_json` is not valid UTF-8, or it does not parse as a `Command`.
 *
 * # Safety
 * `client` must be null or valid. `command_json` must be null or point to a NUL-terminated, valid
 * UTF-8 C string, valid for reads for the duration of this call.
 *
 * The handle must not be in use on another thread while this call runs.
 */
bool obby_client_command_from_json(struct obby_client_t *client, const char *command_json);

/**
 * Read the whole model as JSON, for a host that wants the full state rather than the changes.
 *
 * Returns null only when `client` is null; a working client always produces valid JSON.
 *
 * # Safety
 * `client` must be null or a valid, non-freed pointer from [`obby_client_new`].
 *
 * The handle must not be in use on another thread while this call runs.
 */
char *obby_client_model_json(struct obby_client_t *client);

/**
 * The crate version, as a static, NUL-terminated string.
 *
 * This pointer is owned by the library and lives for the process's lifetime: never pass it to
 * [`obby_client_free_string`].
 */
const char *obby_client_version(void);

/**
 * Create a client.
 *
 * Returns null when `config` is null, or when its `nick` is null or not valid UTF-8.
 *
 * # Safety
 * `config` must be null or point to a readable [`ObbyConfig`] whose string fields are each null or
 * a NUL-terminated, valid UTF-8 C string, all valid for reads for the duration of this call.
 */
struct obby_client_t *obby_client_new(const struct obby_config_t *config);

/**
 * Join a channel, with `key` for a channel that needs one, or null.
 *
 * # Safety
 * `client` must be null or valid. Each string must be null or a NUL-terminated, valid UTF-8 C
 * string, valid for reads for the duration of this call.
 *
 * The handle must not be in use on another thread while this call runs.
 */
bool obby_client_join(struct obby_client_t *client, const char *channel, const char *key);

/**
 * Leave a channel, with `reason` shown to the others in it, or null.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_part(struct obby_client_t *client, const char *channel, const char *reason);

/**
 * Say something to a channel or a person.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_send_message(struct obby_client_t *client, const char *target, const char *text);

/**
 * Send a notice, which by convention must never be auto-replied to.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_send_notice(struct obby_client_t *client, const char *target, const char *text);

/**
 * Send a `CTCP ACTION`, the third-person form.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_send_action(struct obby_client_t *client, const char *target, const char *text);

/**
 * Change our nick.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_set_nick(struct obby_client_t *client, const char *nick);

/**
 * Set or clear a channel's topic. A null `topic` asks for the current one.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_set_topic(struct obby_client_t *client, const char *channel, const char *topic);

/**
 * Go away with a message, or come back by passing null.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_set_away(struct obby_client_t *client, const char *message);

/**
 * Quit, with a reason or null.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_quit(struct obby_client_t *client, const char *reason);

/**
 * Say we are typing, so others can show it. `state` must be `"active"`, `"paused"` or `"done"`.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_set_typing(struct obby_client_t *client, const char *target, const char *state);

/**
 * React to a message with an emoji.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_add_reaction(struct obby_client_t *client,
                              const char *target,
                              const char *msgid,
                              const char *emoji);

/**
 * Take a reaction back.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_remove_reaction(struct obby_client_t *client,
                                 const char *target,
                                 const char *msgid,
                                 const char *emoji);

/**
 * Ask the server to delete a message, with `reason` when it wants one, or null.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_redact_message(struct obby_client_t *client,
                                const char *target,
                                const char *msgid,
                                const char *reason);

/**
 * Tell the server how far we have read, as milliseconds since the Unix epoch.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_mark_read(struct obby_client_t *client, const char *target, uint64_t at_ms);

/**
 * Ask for older messages than the ones we hold. A null `before_msgid` asks for the most recent.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_fetch_history(struct obby_client_t *client,
                               const char *target,
                               const char *before_msgid,
                               uint16_t limit);

/**
 * Set one of our own metadata keys, or clear it with a null `value`.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_set_metadata(struct obby_client_t *client, const char *key, const char *value);

/**
 * Ask to be told when these metadata keys change on anyone we can see.
 *
 * # Safety
 * As [`obby_client_join`]. `keys` must be null or point to `count` valid, NUL-terminated C
 * strings, valid for reads for the duration of this call; an element that is null or not valid
 * UTF-8 is skipped rather than failing the whole call.
 */
bool obby_client_subscribe_metadata(struct obby_client_t *client,
                                    const char *const *keys,
                                    size_t count);

/**
 * Ask the server everything it will say about someone.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_whois(struct obby_client_t *client, const char *nick);

/**
 * Rename a channel, keeping everyone in it and everything said in it. `reason` may be null.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_rename_channel(struct obby_client_t *client,
                                const char *channel,
                                const char *new_name,
                                const char *reason);

/**
 * Make an invitation link. A null `channel` invites to the network; `description` may be null too.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_create_invite_link(struct obby_client_t *client,
                                    const char *channel,
                                    const char *description);

/**
 * Ask for the invitation links we have made.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_list_invite_links(struct obby_client_t *client);

/**
 * Withdraw an invitation link.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_delete_invite_link(struct obby_client_t *client, const char *share_id);

/**
 * Redeem an invitation code. Only before registering, which is the point of it.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_redeem_invite_code(struct obby_client_t *client, const char *code);

/**
 * Mint a bearer token for one of the network's services, such as its file host.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_generate_token(struct obby_client_t *client, const char *service);

/**
 * Watch these nicks, so the server says when they come and go.
 *
 * # Safety
 * As [`obby_client_subscribe_metadata`], with `nicks` in place of `keys`.
 */
bool obby_client_watch_nicks(struct obby_client_t *client, const char *const *nicks, size_t count);

/**
 * Stop watching these nicks.
 *
 * # Safety
 * As [`obby_client_subscribe_metadata`], with `nicks` in place of `keys`.
 */
bool obby_client_unwatch_nicks(struct obby_client_t *client,
                               const char *const *nicks,
                               size_t count);

/**
 * Send a voice signalling frame to a room. `signal_json` is one frame in the shape
 * [`obby_client::Signal`] serialises to, and a frame this ABI cannot read is refused.
 *
 * Every other binding takes the frame as a typed value; C has no type to take, so it takes the
 * JSON.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_send_voice_signal(struct obby_client_t *client,
                                   const char *channel,
                                   const char *signal_json);

/**
 * Send one raw protocol line, without the trailing CRLF, for anything this ABI does not name.
 *
 * # Safety
 * As [`obby_client_join`].
 */
bool obby_client_send_raw_line(struct obby_client_t *client, const char *line);

/**
 * Take the next event, or null when there are none.
 *
 * The caller owns what comes back and releases it with [`obby_event_free`].
 *
 * # Safety
 * `client` must be null or a valid, non-freed pointer from [`obby_client_new`].
 *
 * The handle must not be in use on another thread while this call runs.
 */
struct obby_event_t *obby_client_poll_event(struct obby_client_t *client);

/**
 * What kind of event this is.
 *
 * A null event reads as [`ObbyEventKind::Unknown`], so a caller that skipped the null check gets a
 * kind it already has to handle rather than a crash.
 *
 * # Safety
 * `event` must be null or a valid, non-freed pointer from [`obby_client_poll_event`].
 */
enum obby_event_kind obby_event_get_kind(const struct obby_event_t *event);

/**
 * One of the event's string fields, or null when this event has no such field.
 *
 * The pointer borrows from the event and is invalid once [`obby_event_free`] runs.
 *
 * # Safety
 * `event` must be null or a valid, non-freed pointer from [`obby_client_poll_event`].
 */
const char *obby_event_text(const struct obby_event_t *event, enum obby_event_field field);

/**
 * One of the event's numeric fields, written to `out`.
 *
 * Returns false, and leaves `out` alone, when this event has no such field.
 *
 * # Safety
 * `event` must be null or a valid, non-freed pointer from [`obby_client_poll_event`]. `out` must
 * be null or point to a writable `uint64_t`.
 */
bool obby_event_number(const struct obby_event_t *event,
                       enum obby_event_field field,
                       uint64_t *out);

/**
 * The whole event as JSON, for the parts this ABI does not flatten into fields.
 *
 * The pointer borrows from the event and is invalid once [`obby_event_free`] runs.
 *
 * # Safety
 * `event` must be null or a valid, non-freed pointer from [`obby_client_poll_event`].
 */
const char *obby_event_json(const struct obby_event_t *event);

/**
 * Release an event.
 *
 * # Safety
 * `event` must be null, or a pointer from [`obby_client_poll_event`] that has not already been
 * passed here. Every string read from it is invalid afterwards.
 */
void obby_event_free(struct obby_event_t *event);

#endif  /* OBBY_FFI_H */
