#ifndef SENTRY_VALUE_H_INCLUDED
#define SENTRY_VALUE_H_INCLUDED

#include "sentry_boot.h"
#include "sentry_json.h"
/**
 * Create a new Value from an owned string.
 */
sentry_value_t sentry__value_new_string_owned(char *s);

#ifdef SENTRY_PLATFORM_WINDOWS
/**
 * Create a new Value from a Wide String.
 */
sentry_value_t sentry__value_new_string_from_wstr(const wchar_t *s);
#endif

/**
 * Create a new String Value, with the hex-formatted value of `addr`.
 */
sentry_value_t sentry__value_new_addr(uint64_t addr);

/**
 * Creates a new String Value, with a hex representation of `bytes`.
 */
sentry_value_t sentry__value_new_hexstring(const uint8_t *bytes, size_t len);

/**
 * Creates a new String Value from the `uuid` that conforms to
 * the structure of a span ID.
 * See also `sentry__span_uuid_as_string`.
 */
sentry_value_t sentry__value_new_span_uuid(const sentry_uuid_t *uuid);

/**
 * Creates a new String Value from the `uuid` in a form meant for
 * ingestion as an internal ID.
 * See also `sentry_internal_uuid_as_string`.
 */
sentry_value_t sentry__value_new_internal_uuid(const sentry_uuid_t *uuid);

/**
 * Creates a new String Value from the `uuid`.
 * See also `sentry_uuid_as_string`.
 */
sentry_value_t sentry__value_new_uuid(const sentry_uuid_t *uuid);

/**
 * Creates a new Event with the given `event_id`.
 * Used by Crashpad to allow associating feedback with the crash event.
 */
sentry_value_t sentry__value_new_event_with_id(const sentry_uuid_t *event_id);

/**
 * Creates a new String Value from the given `level`.
 * This can be `debug`, `warning`, `error`, `fatal`, or `info`.
 */
sentry_value_t sentry__value_new_level(sentry_level_t level);

/**
 * Creates a new List Value with a capacity of `size`.
 */
sentry_value_t sentry__value_new_list_with_size(size_t size);

/**
 * Creates a new Object Value with a capacity of `size`.
 */
sentry_value_t sentry__value_new_object_with_size(size_t size);

/**
 * Iterates over the key/value pairs of an object value. The callback receives a
 * borrowed reference for each value. Does nothing if `value` is not an object.
 */
void sentry__value_foreach_key_value(sentry_value_t value,
    void (*callback)(const char *key, sentry_value_t value, void *userdata),
    void *userdata);

/**
 * Sets a value by an already-owned key.
 * Takes ownership of `key` and `v`.
 */
int sentry__value_set_by_key_owned(
    sentry_value_t value, char *key, size_t key_len, sentry_value_t v);

/**
 * Removes a value by key and returns the owned object key on success.
 * The caller must free the returned key.
 */
char *sentry__value_remove_and_take_key_n(
    sentry_value_t value, const char *key, size_t key_len);

/**
 * This will parse the Value into a UUID, or return a `nil` UUID on error.
 * See also `sentry_uuid_from_string`.
 */
sentry_uuid_t sentry__value_as_uuid(sentry_value_t value);

/**
 * This will create a simplified string representation of the value.
 * Lists, Objects and `null` will be converted to an empty string.
 */
char *sentry__value_stringify(sentry_value_t value);

/**
 * Performs a shallow clone.
 * On a frozen value this produces an unfrozen one.
 */
sentry_value_t sentry__value_clone(sentry_value_t value);

/**
 * Deep-merges object src into dst.
 *
 * For each key-value pair in the src object the same key in the dst object
 * will be set to the value from src.  If both the dst value and the src value
 * are objects themselves they are stepped into recursively instead of
 * overriding the entire dst object.
 *
 * If src is null nothing needs to be merged and this is handled gracefully,
 * otherwise if dst is any other type than an object or src is neither an
 * object nor null an error is returned.
 *
 * Returns 0 on success.
 */
int sentry__value_merge_objects(sentry_value_t dst, sentry_value_t src);

/**
 * Shallow-merges the top-level keys from src into dst, keeping keys that dst
 * already has.
 *
 * Unlike `sentry__value_merge_objects`, values are copied whole and are never
 * merged recursively, so a nested object in src cannot add fields to a
 * same-keyed object already present in dst.
 *
 * Returns 0 on success.
 */
int sentry__value_merge_objects_shallow(sentry_value_t dst, sentry_value_t src);

/**
 * Writes the given `value` into the `jsonwriter`.
 */
void sentry__jsonwriter_write_value(
    sentry_jsonwriter_t *jw, sentry_value_t value);

/**
 * Serializes `value` into JSON and optionally returns the byte length.
 */
char *sentry__value_to_json(sentry_value_t value, size_t *len_out);

/**
 * Adds a typed attribute to the attributes object.
 * No-op if the attribute already exists (preserves user precedence).
 * Takes ownership of `value`.
 */
void sentry__value_add_attribute(sentry_value_t attributes,
    sentry_value_t value, const char *type, const char *name);

/**
 * Deserialize a single sentry value from msgpack.
 *
 * The value must span the whole buffer; buffers containing multiple
 * sequential msgpack values (as in append-only streams like breadcrumb ring
 * files) are rejected with null and must be decoded with
 * `sentry__value_from_msgpack_stream`.
 *
 * The returned value must be released with `sentry_value_decref`.
 */
sentry_value_t sentry__value_from_msgpack(const char *buf, size_t buf_len);

/**
 * Deserialize a buffer of sequential msgpack values into a list.
 *
 * Unlike `sentry__value_from_msgpack`, the result is a list even when the
 * buffer holds a single value, so files written as append-only streams (e.g.
 * breadcrumb ring files) decode to a consistent shape. Returns null for an
 * empty buffer or when the first value fails to parse.
 *
 * The returned value must be released with `sentry_value_decref`.
 */
sentry_value_t sentry__value_from_msgpack_stream(
    const char *buf, size_t buf_len);

/**
 * Merges two breadcrumb lists in timestamp order, keeping at most `max` items.
 * Returns a new list with the merged breadcrumbs.
 */
sentry_value_t sentry__value_merge_breadcrumbs(
    sentry_value_t list_a, sentry_value_t list_b, size_t max);

#endif
