#ifndef MOZA_H
#define MOZA_H

#include "private/macros.h"

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef uint8_t MOZA_BOOL;

#define MOZA_FALSE ((MOZA_BOOL)0)
#define MOZA_TRUE  ((MOZA_BOOL)1)

/**
 * @brief SDK error codes.
 */
typedef enum MOZA_ERRNO_
{
    /** @brief Unknown error. */
    MOZA_ERR_UNKNOWN = -1,

    /** @brief Operation succeeded. */
    MOZA_ERR_NO_ERROR = 0,

    /** @brief The device service process is not available. */
    MOZA_ERR_SERVICE_NOT_FOUND,
    /** @brief The SDK version does not match the device service version. */
    MOZA_ERR_SERVICE_VERSION_MISMATCH,

    /** @brief One or more arguments are invalid. */
    MOZA_ERR_INVALID_ARGUMENT,
    /** @brief The SDK has not been initialized. */
    MOZA_ERR_NOT_INITIALIZED,
    /** @brief The SDK has already been initialized. */
    MOZA_ERR_ALREADY_INITIALIZED,
    /** @brief The caller-provided buffer is too small. */
    MOZA_ERR_BUFFER_TOO_SMALL,
    /** @brief The requested device was not found. */
    MOZA_ERR_DEVICE_NOT_FOUND,
    /** @brief The requested device or HID device is not open. */
    MOZA_ERR_DEVICE_NOT_OPEN,
    /** @brief The supplied handle is invalid. */
    MOZA_ERR_INVALID_HANDLE,
    /** @brief The requested data is temporarily unavailable and no completed result can be returned yet. */
    MOZA_ERR_BUSY,
    /** @brief The operation timed out. */
    MOZA_ERR_TIMEOUT,
    /** @brief The operation is not supported. */
    MOZA_ERR_NOT_SUPPORTED,
    /** @brief The parameter read command reported an error. */
    MOZA_ERR_PARAMETER_READ_COMMAND_ERROR,
    /** @brief The parameter write command reported an error. */
    MOZA_ERR_PARAMETER_WRITE_COMMAND_ERROR,
    /** @brief The supplied index is out of bounds. */
    MOZA_ERR_INDEX_OUT_OF_BOUNDS,
    /** @brief The operation has been accepted asynchronously but is not completed yet. */
    MOZA_ERR_PENDING,
} MOZA_ERRNO;

/** @brief Unsigned size type used by the API. */
typedef uint32_t MOZA_SIZE;

/**
 * @brief Runtime-assigned device identifier.
 *
 * The SDK assigns this identifier at runtime rather than reading it directly from the device.
 * The same identifier may be reused for the same device object across disconnect and reconnect cycles.
 * The identifier is not persistent across SDK shutdown and re-initialization.
 */
typedef uint32_t MOZA_DEVICE_ID;

/**
 * @brief Log severity levels used by the API log callback.
 */
typedef enum MOZA_LOG_LEVEL_
{
    /** @brief Debug log message. */
    MOZA_LL_DEBUG = 0,
    /** @brief Informational log message. */
    MOZA_LL_INFO,
    /** @brief Warning log message. */
    MOZA_LL_WARNING,
    /** @brief Critical error log message. */
    MOZA_LL_CRITICAL,
    /** @brief Fatal log message. */
    MOZA_LL_FATAL,
} MOZA_LOG_LEVEL;

/**
 * @brief Log context delivered to MOZA_LOG_CALLBACK.
 *
 * This structure is reserved for internal diagnostics and compatibility.
 * Applications may read only the explicitly documented public fields.
 * Reserved fields remain for internal compatibility and must not be interpreted.
 */
typedef struct MOZA_LOG_CONTEXT_
{
    /** @brief Log severity level. */
    MOZA_LOG_LEVEL level;
    /** @brief UTF-8 log message buffer, not guaranteed to be null-terminated. */
    const char* message;
    /** @brief Log message length in bytes. */
    MOZA_SIZE messageSize;
    /** @brief UTF-8 log category buffer, not guaranteed to be null-terminated. */
    const char* category;
    /** @brief Log category length in bytes. */
    MOZA_SIZE categorySize;
    /** @brief Reserved fields for internal use only. */
    uintptr_t reserved[4];
} MOZA_LOG_CONTEXT;

/**
 * @brief Command identifier recognized by the API.
 *
 * The SDK package includes ApiDebugTool.exe, which displays the available commands for a device
 * and can be used to send commands. This tool can help applications locate the required command
 * identifiers and command names.
 */
typedef int32_t MOZA_COMMAND_ID;
/**
 * @brief Parameter identifier recognized by the API.
 *
 * The SDK package includes ApiDebugTool.exe, which displays the available parameters for a device
 * and can be used to fetch, get, and set parameter values. This tool can help applications locate
 * the required parameter identifiers and parameter names.
 */
typedef int32_t MOZA_PARAMETER_ID;

/** @brief Opaque device handle type. */
typedef struct MOZA_DEVICE_HANDLE_* MOZA_DEVICE_HANDLE;

#define MOZA_INVALID_DEVICE_HANDLE ((MOZA_DEVICE_HANDLE)0)

/**
 * @brief SDK event types.
 */
typedef enum MOZA_EVENT_TYPE_
{
    /** @brief The connection to the device service has been closed. */
    MOZA_ET_SERVICE_CONNECTION_CLOSED = 0,

    /** @brief A device became available. */
    MOZA_ET_DEVICE_CONNECTED,
    /** @brief A device became unavailable. */
    MOZA_ET_DEVICE_DISCONNECTED,
    /** @brief A device parameter value changed. */
    MOZA_ET_DEVICE_PARAMETER_VALUE_CHANGED,
    /** @brief A device parameter operation reported an error. */
    MOZA_ET_DEVICE_PARAMETER_ERROR_OCCURRED,
    /** @brief A device command reply was received. */
    MOZA_ET_DEVICE_COMMAND_REPLIED,
    /** @brief A device command operation reported an error. */
    MOZA_ET_DEVICE_COMMAND_ERROR_OCCURRED,

    /** @brief A HID axis value changed. High-frequency axis events may be coalesced and rate-limited by the SDK. */
    MOZA_ET_HID_AXIS_DATA_CHANGED,
    /** @brief A HID button was pressed. Button numbers start from 1. */
    MOZA_ET_HID_BUTTON_PRESSED,
    /** @brief A HID button was released. Button numbers start from 1. */
    MOZA_ET_HID_BUTTON_RELEASED,
} MOZA_EVENT_TYPE;

/**
 * @brief Top-level MOZA device categories.
 */
typedef enum MOZA_DEVICE_CATEGORY_
{
    /** @brief Unknown or unsupported category. */
    MOZA_DC_UNKNOWN = 0,

    /** @brief Racing simulation devices. */
    MOZA_DC_RS,
    /** @brief Aircraft simulation devices. */
    MOZA_DC_AS,

} MOZA_DEVICE_CATEGORY;

/**
 * @brief MOZA device type bitfield.
 *        The meaning of the value depends on MOZA_DEVICE_CATEGORY.
 *        For example, if the category of a device is MOZA_DC_AS,
 *        then the value of the device type corresponds to MOZA_DEVICE_TYPE_AS
 */
typedef int MOZA_DEVICE_TYPE;

/**
 * @brief Racing simulation device types.
 */
typedef enum MOZA_DEVICE_TYPE_RS_
{
    /** @brief Unknown racing simulation device type. */
    MOZA_DT_RS_UNKNOWN = 0,
    /** @brief Racing simulation wheelbase device. */
    MOZA_DT_RS_WHEELBASE = 1 << 0,
    /** @brief Racing simulation motor device. */
    MOZA_DT_RS_MOTOR = 1 << 1,
    /** @brief Racing simulation steering wheel device. */
    MOZA_DT_RS_STEERING_WHEEL = 1 << 2,
    /** @brief Racing simulation dashboard device. */
    MOZA_DT_RS_DASHBOARD = 1 << 3,
    /** @brief Racing simulation pedal device. */
    MOZA_DT_RS_PEDAL = 1 << 4,
    /** @brief Racing simulation shifter device. */
    MOZA_DT_RS_SHIFTER = 1 << 5,
    /** @brief Racing simulation handbrake device. */
    MOZA_DT_RS_HANDBRAKE = 1 << 6,
    /** @brief Racing simulation hub/adapter device. */
    MOZA_DT_RS_HUB = 1 << 7,
    /** @brief Racing simulation emergency stop controller. */
    MOZA_DT_RS_ESTOP = 1 << 8,
    /** @brief Racing simulation factory test board. */
    MOZA_DT_RS_FACTORY_TEST = 1 << 9,
    /** @brief Racing simulation multifunction stalk device. */
    MOZA_DT_RS_STALK = 1 << 10,
    /** @brief Racing simulation display device. */
    MOZA_DT_RS_SCREEN = 1 << 11,
    /** @brief Racing simulation pedal vibration module. */
    MOZA_DT_RS_PEDAL_VIBRATION = 1 << 12,
    /** @brief Racing simulation farming control panel. */
    MOZA_DT_RS_FARMING_CONTROL_PANEL = 1 << 13,
    /** @brief Racing simulation motorcycle handlebar device. */
    MOZA_DT_RS_MOTORCYCLE_HANDLEBAR = 1 << 14
} MOZA_DEVICE_TYPE_RS;

/**
 * @brief Aircraft simulation device types.
 */
typedef enum MOZA_DEVICE_TYPE_AS_
{
    /** @brief Unknown aircraft simulation device type. */
    MOZA_DT_AS_UNKNOWN = 0,
    /** @brief Aircraft simulation wheelbase device. */
    MOZA_DT_AS_WHEELBASE = 1 << 0,
    /** @brief Aircraft simulation throttle device. */
    MOZA_DT_AS_THROTTLE = 1 << 1,
    /** @brief Aircraft simulation rudder device. */
    MOZA_DT_AS_RUDDER = 1 << 2,
    /** @brief Aircraft simulation motor device. */
    MOZA_DT_AS_MOTOR = 1 << 3,
    /** @brief Aircraft simulation stick device. */
    MOZA_DT_AS_STICK = 1 << 4,
    /** @brief Aircraft simulation throttle panel device. */
    MOZA_DT_AS_THROTTLE_PANEL = 1 << 5,
    /** @brief Aircraft simulation accessory device. */
    MOZA_DT_AS_OTHER = 1 << 6,
    /** @brief Aircraft simulation force feedback throttle device. */
    MOZA_DT_AS_FORCE_FEEDBACK_THROTTLE = 1 << 7,
    /** @brief Aircraft simulation control panel device. */
    MOZA_DT_AS_CONTROL_PANEL = 1 << 8,
    /** @brief Aircraft simulation display device. */
    MOZA_DT_AS_SCREEN = 1 << 11
} MOZA_DEVICE_TYPE_AS;

/**
 * @brief Device connection state.
 */
typedef enum MOZA_DEVICE_STATE_
{
    /** @brief State is unknown. */
    MOZA_DS_UNKNOWN = 0,
    /** @brief Device is connected and operating normally. */
    MOZA_DS_NORMAL,
    /** @brief Device is disconnected. */
    MOZA_DS_DISCONNECTED
} MOZA_DEVICE_STATE;

/**
 * @brief Variant value types used by MOZA_VALUE.
 */
typedef enum MOZA_VALUE_TYPE_
{
    /** @brief Invalid or uninitialized value. */
    MOZA_VT_INVALID = 0,
    /** @brief Null value. */
    MOZA_VT_NULL,
    /** @brief Signed integer value. */
    MOZA_VT_INT,
    /** @brief Unsigned integer value. */
    MOZA_VT_UINT,
    /** @brief Double-precision floating-point value. */
    MOZA_VT_DOUBLE,
    /** @brief Boolean value stored in MOZA_BOOL form. */
    MOZA_VT_BOOL,
    /** @brief UTF-8 string value stored as a C string. */
    MOZA_VT_STRING,
    /** @brief Binary blob value. */
    MOZA_VT_BINARY,
    /** @brief Heterogeneous list value. */
    MOZA_VT_LIST
} MOZA_VALUE_TYPE;

/**
 * @brief Supported HID axes.
 */
typedef enum MOZA_HID_AXIS_
{
    /** @brief X axis. */
    MOZA_HA_X = 0,
    /** @brief Y axis. */
    MOZA_HA_Y,
    /** @brief Z axis. */
    MOZA_HA_Z,
    /** @brief Rx axis. */
    MOZA_HA_RX,
    /** @brief Ry axis. */
    MOZA_HA_RY,
    /** @brief Rz axis. */
    MOZA_HA_RZ,
    /** @brief Slider axis. */
    MOZA_HA_SLIDER,
    /** @brief Dial axis. */
    MOZA_HA_DIAL,
    /** @brief Wheel axis. */
    MOZA_HA_WHEEL,
    /** @brief Hat switch axis. */
    MOZA_HA_HAT_SWITCH,

    /** @brief The maximum value of the MOZA_HID_AXIS enumeration */
    MOZA_HA_MAX,
} MOZA_HID_AXIS;

/** @brief Maximum number of HID buttons exposed by the API. */
#define MOZA_HID_MAX_BUTTON_COUNT 128
/** @brief Number of bytes required to store all HID button states as a bitset. */
#define MOZA_HID_BUTTON_BITSET_SIZE (MOZA_HID_MAX_BUTTON_COUNT / 8)
/** @brief Test whether a 1-based HID button number is pressed in a MOZA_HID_INPUT_STATE bitset. */
#define MOZA_HID_INPUT_STATE_IS_BUTTON_PRESSED(statePtr, buttonNumber) \
    (((statePtr) != 0 && (buttonNumber) >= 1 && (buttonNumber) <= MOZA_HID_MAX_BUTTON_COUNT) \
         ? ((((statePtr)->buttons[((buttonNumber) - 1) >> 3] >> (((buttonNumber) - 1) & 0x7)) & 0x1u) ? MOZA_TRUE : MOZA_FALSE) \
         : MOZA_FALSE)

#pragma pack(push, 1)

typedef struct MOZA_VALUE_ MOZA_VALUE;

/**
 * @brief Generic variant value container used by the C API.
 *
 * For heap-backed members (string/binary/list), ownership follows the API contract:
 * - values created by Moza_ValueCreate are owned by the caller and must be released with Moza_ValueDestroy
 * - values returned by synchronous APIs become caller-owned after return and must be released with Moza_ValueDestroy
 * - values referenced from MOZA_EVENT_DATA are owned by the SDK and remain valid only during the event callback
 */
typedef struct MOZA_VALUE_
{
    /** @brief Active value type. */
    MOZA_VALUE_TYPE type;

    union
    {
        /** @brief Signed integer payload. */
        int64_t intValue;
        /** @brief Unsigned integer payload. */
        uint64_t uintValue;
        /** @brief Floating-point payload. */
        double doubleValue;
        /** @brief Boolean payload. */
        MOZA_BOOL boolValue;

        struct
        {
            /** @brief UTF-8 C string buffer terminated by '\0'. */
            char* data;
            /** @brief String length excluding the trailing '\0'. */
            MOZA_SIZE size;
        } stringValue;

        struct
        {
            /** @brief Binary buffer pointer. */
            uint8_t* data;
            /** @brief Binary buffer size in bytes. */
            MOZA_SIZE size;
        } binaryValue;

        struct
        {
            /** @brief Pointer to list items. */
            MOZA_VALUE* items;
            /** @brief Number of items in the list. */
            MOZA_SIZE size;
        } listValue;
    } data;
} MOZA_VALUE;

/**
 * @brief HID axis sample.
 */
typedef struct MOZA_HID_AXIS_DATA_
{
    /** @brief Raw axis value reported by the HID device. */
    int32_t rawValue;
    /** @brief Normalized axis value, typically in the range 0.0f to 1.0f. */
    float normalizedValue;
} MOZA_HID_AXIS_DATA;

/**
 * @brief Combined HID input state snapshot.
 *
 * Axis data is stored in the fixed axis array indexed by MOZA_HID_AXIS.
 * Button data is stored as a fixed-size bitset.
 * Button 1 corresponds to bit 0 of buttons[0].
 */
typedef struct MOZA_HID_INPUT_STATE_
{
    /** @brief Timestamp in microseconds of the last HID axis/button data update reflected by this snapshot. */
    int64_t timestamp;
    /** @brief Axis samples indexed by MOZA_HID_AXIS. */
    MOZA_HID_AXIS_DATA axes[MOZA_HA_MAX];
    /** @brief Button state bitset. Bit 0 of buttons[0] corresponds to button 1. */
    uint8_t buttons[MOZA_HID_BUTTON_BITSET_SIZE];
} MOZA_HID_INPUT_STATE;

/**
 * @brief Event payload delivered to MOZA_EVENT_CALLBACK.
 *
 * Any pointers inside this structure, including strings and MOZA_VALUE pointers,
 * are owned by the SDK and remain valid only during the callback.
 * The caller must copy any data that needs to outlive the callback.
 */
typedef struct MOZA_EVENT_DATA_
{
    /** @brief Event timestamp in microseconds since Unix epoch. */
    int64_t timestamp;
    /** @brief Event type discriminator for the union below. */
    MOZA_EVENT_TYPE type;

    union
    {
        /** @brief Service connection closed payload. The placeholder field carries no additional information. */
        struct
        {
            uint8_t reserved;
        } serviceConnectionClosed;

        struct
        {
            /** @brief Device identifier. */
            MOZA_DEVICE_ID deviceId;
        } deviceConnected;

        struct
        {
            /** @brief Device identifier. */
            MOZA_DEVICE_ID deviceId;
        } deviceDisconnected;

        struct
        {
            /** @brief Device identifier. */
            MOZA_DEVICE_ID deviceId;
            /** @brief Parameter identifier. */
            MOZA_PARAMETER_ID parameterId;
            /** @brief Parameter name. Valid only during the callback. */
            const char* parameterName;
            /** @brief Parameter value. Valid only during the callback. */
            const MOZA_VALUE* value;
        } parameterValueChanged;

        struct
        {
            /** @brief Device identifier. */
            MOZA_DEVICE_ID deviceId;
            /** @brief Parameter identifier. */
            MOZA_PARAMETER_ID parameterId;
            /** @brief Parameter name. Valid only during the callback. */
            const char* parameterName;
            /** @brief Error code associated with the parameter operation. */
            MOZA_ERRNO error;
        } parameterErrorOccurred;

        struct
        {
            /** @brief Device identifier. */
            MOZA_DEVICE_ID deviceId;
            /** @brief Command identifier. */
            MOZA_COMMAND_ID commandId;
            /** @brief Command name. Valid only during the callback. */
            const char* commandName;
            /** @brief Command reply value. Valid only during the callback. */
            const MOZA_VALUE* value;
        } commandReplied;

        struct
        {
            /** @brief Device identifier. */
            MOZA_DEVICE_ID deviceId;
            /** @brief Command identifier. */
            MOZA_COMMAND_ID commandId;
            /** @brief Command name. Valid only during the callback. */
            const char* commandName;
            /** @brief Error code associated with the command operation. */
            MOZA_ERRNO error;
        } commandErrorOccurred;

        struct
        {
            /** @brief Device identifier. */
            MOZA_DEVICE_ID deviceId;
            /** @brief HID device index under the device root. */
            uint8_t hidIndex;
            /** @brief Axis identifier. */
            MOZA_HID_AXIS axis;
            /** @brief Axis value sample. */
            MOZA_HID_AXIS_DATA value;
        } hidAxisDataChanged;

        struct
        {
            /** @brief Device identifier. */
            MOZA_DEVICE_ID deviceId;
            /** @brief HID device index under the device root. */
            uint8_t hidIndex;
            /** @brief Button number starting from 1. */
            int32_t buttonNumber;
        } hidButtonPressed, hidButtonReleased;
    } data;
} MOZA_EVENT_DATA;

/**
 * @brief Event callback function type.
 *
 * The event object and all pointer fields referenced by it remain valid only during the callback.
 */
typedef void (*MOZA_EVENT_CALLBACK)(const MOZA_EVENT_DATA*/*event*/, void*/*userData*/);

/**
 * @brief Log callback function type.
 *
 * The callback receives forwarded internal SDK/DeviceSDK log records.
 * The log context and all pointer fields referenced by it remain valid only during the callback.
 * The text buffers are not guaranteed to be null-terminated, so applications should use
 * the corresponding size fields when copying or formatting them.
 */
typedef void (*MOZA_LOG_CALLBACK)(const MOZA_LOG_CONTEXT*/*context*/, void*/*userData*/);

/**
 * @brief Basic device information snapshot.
 */
typedef struct MOZA_DEVICE_INFO_
{
    /** @brief Unique device identifier. */
    MOZA_DEVICE_ID id;
    /** @brief UTF-8 device name. */
    char name[64];
    /** @brief UTF-8 USB port name (path), or an empty string if unavailable. */
    char portName[256];
    /** @brief USB vendor identifier, or 0 if unavailable. */
    uint16_t vendorId;
    /** @brief USB product identifier, or 0 if unavailable. */
    uint16_t productId;
    /** @brief Device category. */
    MOZA_DEVICE_CATEGORY category;
    /** @brief Category-specific device type value. */
    MOZA_DEVICE_TYPE type;
    /** @brief Current device state. */
    MOZA_DEVICE_STATE state;
    /** @brief Number of HID devices currently found under the same device root. */
    uint8_t hidDeviceCount;
    /** @brief Reserved field. */
    void* reserved;
} MOZA_DEVICE_INFO;

/**
 * @brief Basic HID device information snapshot.
 */
typedef struct MOZA_HID_DEVICE_INFO_
{
    /** @brief USB vendor identifier. */
    uint16_t vendorId;
    /** @brief USB product identifier. */
    uint16_t productId;
    /** @brief HID interface number, or -1 if unavailable. */
    int8_t interfaceNumber;
    /** @brief HID collection number, or -1 if unavailable. */
    int8_t collectionNumber;
    /** @brief UTF-8 Product name buffer. */
    char productName[64];
    /** @brief Number of parsed generic desktop axes. */
    uint8_t axisCount;
    /** @brief Number of parsed buttons. */
    uint8_t buttonCount;
} MOZA_HID_DEVICE_INFO;

/**
 * @brief Basic device parameter information snapshot.
 *
 * ApiDebugTool.exe included with the SDK can be used to browse the parameter list shown by the
 * device and to test fetch, get, and set operations interactively.
 */
typedef struct MOZA_PARAMETER_INFO_
{
    /** @brief Parameter identifier. */
    MOZA_PARAMETER_ID id;
    /** @brief UTF-8 parameter name buffer. */
    char name[64];
    /** @brief Whether the parameter supports get/fetch operations. */
    MOZA_BOOL readable;
    /** @brief Whether the parameter supports set operations. */
    MOZA_BOOL writable;
    /** @brief Reserved field. */
    void* reserved;
} MOZA_PARAMETER_INFO;

/**
 * @brief Basic device command information snapshot.
 *
 * ApiDebugTool.exe included with the SDK can be used to browse the command list shown by the
 * device and to test command sending interactively.
 */
typedef struct MOZA_COMMAND_INFO_
{
    /** @brief Command identifier. */
    MOZA_COMMAND_ID id;
    /** @brief UTF-8 command name buffer. */
    char name[64];
    /** @brief Number of request arguments. */
    uint8_t requestArgumentsCount;
    /** @brief Number of response arguments. */
    uint8_t responseArgumentsCount;
    /** @brief Reserved field. */
    void* reserved;
} MOZA_COMMAND_INFO;

#pragma pack(pop)

/**
 * @brief Initializes the SDK.
 *
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_Initialize();

/**
 * @brief Returns the SDK version number encoded by MOZA_SDK_MAKE_VERSION.
 *
 * This function can be used to compare the runtime SDK version against the
 * compile-time version macros.
 *
 * @return Encoded SDK version number.
 */
MOZA_SDK_EXPORT uint32_t Moza_GetSdkVersionNumber();

/**
 * @brief Returns the SDK version string.
 *
 * The returned pointer refers to static SDK-owned storage and must not be modified or freed.
 *
 * @return SDK version string in `major.minor.patch.tweak` form.
 */
MOZA_SDK_EXPORT const char* Moza_GetSdkVersionString();

/**
 * @brief Shuts down the SDK and releases all resources.
 */
MOZA_SDK_EXPORT void Moza_Shutdown();

/**
 * @brief Registers the global event callback.
 *
 * The callback receives service, device, parameter, command, and HID events.
 * Event data and any pointer fields inside it remain valid only during the callback.
 * The callback is invoked asynchronously in serialized order.
 * Long-running callback work may delay later event delivery.
 *
 * @param callback Event callback function. NULL clears the callback.
 * @param userData Caller-defined pointer passed back to the callback.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_SetEventCallback(MOZA_EVENT_CALLBACK callback, void* userData);

/**
 * @brief Registers the global log callback.
 *
 * This callback receives internal log records forwarded from the underlying DeviceSDK.
 * Register the callback before Moza_Initialize if initialization-time logs are needed.
 * Passing NULL clears the callback and suppresses forwarded log output.
 *
 * @param callback Log callback function. NULL clears the callback.
 * @param userData Caller-defined pointer passed back to the callback.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_SetLogCallback(MOZA_LOG_CALLBACK callback, void* userData);

/**
 * @brief Configures the minimum dispatch interval for HID axis change events.
 *
 * A value of 0 disables interval throttling and keeps event coalescing only.
 * The interval applies per device identifier, HID index, and axis combination.
 * Button events are not affected.
 *
 * @param intervalMs Minimum interval in milliseconds between dispatched HID axis events for the same axis.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_SetHidAxisEventMinInterval(MOZA_SIZE intervalMs);

/**
 * @brief Creates a heap-backed variable-size value object.
 *
 * Supported types are MOZA_VT_STRING, MOZA_VT_BINARY and MOZA_VT_LIST only.
 *
 * For MOZA_VT_STRING, @p size is the string capacity excluding the trailing '\0'.
 * For MOZA_VT_BINARY, @p size is the byte length.
 * For MOZA_VT_LIST, @p size is the number of list items.
 *
 * If @p value already owns heap memory, that memory is released first.
 * Newly created list items are initialized to MOZA_VT_INVALID.
 *
 * @param type Value type to create, see brief description above.
 * @param value Output value object.
 * @param size Capacity/element count for the target type.
 * @return MOZA_TRUE on success, otherwise MOZA_FALSE.
 */
MOZA_SDK_EXPORT MOZA_BOOL Moza_ValueCreate(MOZA_VALUE_TYPE type, MOZA_VALUE* value, MOZA_SIZE size);

/**
 * @brief Deep-copies a MOZA_VALUE.
 *
 * If @p destination already owns heap memory, that memory is released first.
 * Passing the same object for @p source and @p destination is allowed and is treated as a no-op.
 *
 * @param source Source value to copy from.
 * @param destination Destination value to receive the copied content.
 * @return MOZA_TRUE on success, otherwise MOZA_FALSE.
 */
MOZA_SDK_EXPORT MOZA_BOOL Moza_ValueCopy(const MOZA_VALUE* source, MOZA_VALUE* destination);

/**
 * @brief Destroys heap memory owned by a MOZA_VALUE.
 *
 * This function is used for caller-owned values that can contain string, binary, or list data.
 * Passing NULL is allowed.
 *
 * @param value Value object to destroy.
 */
MOZA_SDK_EXPORT void Moza_ValueDestroy(MOZA_VALUE* value);

/**
 * @brief Gets the current device list.
 *
 * If @p infos is NULL, the function writes the required element count to @p infosSize.
 * If @p infos is not NULL and the supplied capacity is too small, the function writes the
 * required count to @p infosSize and returns MOZA_ERR_BUFFER_TOO_SMALL.
 *
 * @param infos Output array of device info records, or NULL to query required count.
 * @param infosSize On input, capacity of @p infos in elements. On output, required/returned count.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceGetList(MOZA_DEVICE_INFO infos[], MOZA_SIZE* infosSize);

/**
 * @brief Queries device information by device identifier.
 *
 * @param deviceId Device identifier.
 * @param info Output device information.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceGetInfoById(MOZA_DEVICE_ID deviceId, MOZA_DEVICE_INFO* info);

/**
 * @brief Opens a device and creates a device handle.
 *
 * Repeated opens of the same device identifier are allowed.
 * Each successful call returns an independent handle that refers to the same device.
 * Each returned handle must be closed independently with Moza_DeviceClose.
 * Closing one handle does not invalidate other handles opened for the same device identifier.
 *
 * @param deviceId Device identifier.
 * @param handle Output device handle.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceOpen(MOZA_DEVICE_ID deviceId, MOZA_DEVICE_HANDLE* handle);

/**
 * @brief Closes a device handle.
 *
 * @param handle Device handle to close.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceClose(MOZA_DEVICE_HANDLE handle);

/**
 * @brief Finds a parameter identifier by parameter name.
 *
 * @param handle Open device handle.
 * @param parameterName Parameter name.
 * @param parameterId Output parameter identifier.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterGetIdByName(MOZA_DEVICE_HANDLE handle,
                                                           const char*        parameterName,
                                                           MOZA_PARAMETER_ID* parameterId);

/**
 * @brief Queries parameter information by parameter identifier.
 *
 * @param handle Open device handle.
 * @param parameterId Parameter identifier.
 * @param info Output parameter information.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterGetInfoById(MOZA_DEVICE_HANDLE   handle,
                                                           MOZA_PARAMETER_ID    parameterId,
                                                           MOZA_PARAMETER_INFO* info);

/**
 * @brief Queries parameter information by parameter name.
 *
 * @param handle Open device handle.
 * @param parameterName Parameter name.
 * @param info Output parameter information.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterGetInfoByName(MOZA_DEVICE_HANDLE   handle,
                                                             const char*          parameterName,
                                                             MOZA_PARAMETER_INFO* info);

/**
 * @brief Gets the full parameter information list supported by an open device.
 *
 * ApiDebugTool.exe included with the SDK can also be used to inspect the same parameter list and
 * to test fetch, get, and set operations interactively.
 *
 * If @p infos is NULL, the function writes the required element count to @p infosSize.
 * If @p infos is not NULL and the supplied capacity is too small, the function writes the
 * required count to @p infosSize and returns MOZA_ERR_BUFFER_TOO_SMALL.
 *
 * @param handle Open device handle.
 * @param infos Output array of parameter information records, or NULL to query the required count.
 * @param infosSize On input, capacity of @p infos in elements. On output, required/returned count.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterGetList(MOZA_DEVICE_HANDLE  handle,
                                                       MOZA_PARAMETER_INFO infos[],
                                                       MOZA_SIZE*          infosSize);

/**
 * @brief Asynchronously requests that the SDK refresh the latest value for a parameter.
 *
 * This function returns after the fetch request is accepted and does not wait for the
 * parameter value reply. Use Moza_DeviceParameterFetchSync if a blocking wait is needed.
 *
 * @param handle Open device handle.
 * @param parameterId Parameter identifier.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterFetch(MOZA_DEVICE_HANDLE handle, MOZA_PARAMETER_ID parameterId);

/**
 * @brief Gets the current cached value for a parameter without waiting.
 *
 * The returned MOZA_VALUE becomes caller-owned and must be destroyed with Moza_ValueDestroy
 * when it contains heap-backed data.
 *
 * If the cached value is not available yet, the function returns MOZA_ERR_BUSY.
 * In that case, the SDK also sends a parameter fetch request once in the background.
 * The later result can be observed through the MOZA_ET_DEVICE_PARAMETER_VALUE_CHANGED event.
 * Use Moza_DeviceParameterGetValueSync to block until a value reply is received or the call times out.
 *
 * @param handle Open device handle.
 * @param parameterId Parameter identifier.
 * @param value Output value.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterGetValue(MOZA_DEVICE_HANDLE handle,
                                                        MOZA_PARAMETER_ID  parameterId,
                                                        MOZA_VALUE*        value);

/**
 * @brief Synchronously fetches a parameter value and waits for the value reply.
 *
 * This function sends a fetch request and blocks until the parameter value reply is received
 * or the timeout expires.
 *
 * When @p value is not NULL, the returned MOZA_VALUE becomes caller-owned and must be destroyed
 * with Moza_ValueDestroy when it contains heap-backed data.
 *
 * @param handle Open device handle.
 * @param parameterId Parameter identifier.
 * @param timeoutMs Timeout in milliseconds. Pass a negative value to wait indefinitely.
 * @param value Optional output value. Pass NULL to ignore the returned parameter value.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterFetchSync(MOZA_DEVICE_HANDLE handle,
                                                         MOZA_PARAMETER_ID  parameterId,
                                                         int32_t            timeoutMs,
                                                         MOZA_VALUE*        value);

/**
 * @brief Synchronously gets a parameter value, waiting for a refresh when needed.
 *
 * This function first checks the current cached value. If no cached value is available, it sends
 * a fetch request and blocks until the parameter value reply is received or the timeout expires.
 *
 * The returned MOZA_VALUE becomes caller-owned and must be destroyed with Moza_ValueDestroy
 * when it contains heap-backed data.
 *
 * @param handle Open device handle.
 * @param parameterId Parameter identifier.
 * @param timeoutMs Timeout in milliseconds. Pass a negative value to wait indefinitely.
 * @param value Output value.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterGetValueSync(MOZA_DEVICE_HANDLE handle,
                                                            MOZA_PARAMETER_ID  parameterId,
                                                            int32_t            timeoutMs,
                                                            MOZA_VALUE*        value);

/**
 * @brief Asynchronously sets the value of a writable parameter.
 *
 * This function returns after the set request is accepted and does not wait for the
 * parameter value reply. Use Moza_DeviceParameterSetValueSync if a blocking wait is needed.
 *
 * @param handle Open device handle.
 * @param parameterId Parameter identifier.
 * @param value Input value.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterSetValue(MOZA_DEVICE_HANDLE handle,
                                                        MOZA_PARAMETER_ID  parameterId,
                                                        const MOZA_VALUE*  value);

/**
 * @brief Synchronously sets the value of a writable parameter and waits for the value reply.
 *
 * This function sends the set request and blocks until the parameter value reply is received
 * or the timeout expires.
 *
 * When @p resultValue is not NULL, the returned MOZA_VALUE becomes caller-owned and must be
 * destroyed with Moza_ValueDestroy when it contains heap-backed data.
 *
 * @param handle Open device handle.
 * @param parameterId Parameter identifier.
 * @param value Input value.
 * @param timeoutMs Timeout in milliseconds. Pass a negative value to wait indefinitely.
 * @param resultValue Optional output value. Pass NULL to ignore the returned parameter value.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceParameterSetValueSync(MOZA_DEVICE_HANDLE handle,
                                                            MOZA_PARAMETER_ID  parameterId,
                                                            const MOZA_VALUE*  value,
                                                            int32_t            timeoutMs,
                                                            MOZA_VALUE*        resultValue);

/**
 * @brief Asynchronously sends a device command by command identifier.
 *
 * This function returns after the command request is accepted and does not wait for the
 * command reply. Use Moza_DeviceCommandSendSync if a blocking wait is needed.
 *
 * @param handle Open device handle.
 * @param commandId Command identifier.
 * @param arguments Command arguments packed in a single MOZA_VALUE. Use MOZA_VT_LIST for
 * multiple arguments. Pass NULL when there are no arguments.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceCommandSend(MOZA_DEVICE_HANDLE handle,
                                                  MOZA_COMMAND_ID    commandId,
                                                  const MOZA_VALUE*  arguments);

/**
 * @brief Synchronously sends a device command by command identifier and waits for the reply.
 *
 * When @p resultValue is not NULL, the returned MOZA_VALUE becomes caller-owned and must be
 * destroyed with Moza_ValueDestroy when it contains heap-backed data.
 *
 * @param handle Open device handle.
 * @param commandId Command identifier.
 * @param arguments Command arguments packed in a single MOZA_VALUE. Use MOZA_VT_LIST for
 * multiple arguments. Pass NULL when there are no arguments.
 * @param timeoutMs Timeout in milliseconds. Pass a negative value to wait indefinitely.
 * @param resultValue Optional output reply value. Pass NULL to ignore the reply payload.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceCommandSendSync(MOZA_DEVICE_HANDLE handle,
                                                      MOZA_COMMAND_ID    commandId,
                                                      const MOZA_VALUE*  arguments,
                                                      int32_t            timeoutMs,
                                                      MOZA_VALUE*        resultValue);

/**
 * @brief Queries command information by command identifier.
 *
 * @param handle Open device handle.
 * @param commandId Command identifier.
 * @param info Output command information.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceCommandGetInfoById(MOZA_DEVICE_HANDLE handle,
                                                         MOZA_COMMAND_ID    commandId,
                                                         MOZA_COMMAND_INFO* info);

/**
 * @brief Queries command information by command name.
 *
 * @param handle Open device handle.
 * @param commandName Command name.
 * @param info Output command information.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceCommandGetInfoByName(MOZA_DEVICE_HANDLE handle,
                                                           const char*        commandName,
                                                           MOZA_COMMAND_INFO* info);

/**
 * @brief Gets the full command information list supported by an open device.
 *
 * ApiDebugTool.exe included with the SDK can also be used to inspect the same command list and
 * to test command sending interactively.
 *
 * If @p infos is NULL, the function writes the required element count to @p infosSize.
 * If @p infos is not NULL and the supplied capacity is too small, the function writes the
 * required count to @p infosSize and returns MOZA_ERR_BUFFER_TOO_SMALL.
 *
 * @param handle Open device handle.
 * @param infos Output array of command information records, or NULL to query the required count.
 * @param infosSize On input, capacity of @p infos in elements. On output, required/returned count.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceCommandGetList(MOZA_DEVICE_HANDLE handle,
                                                     MOZA_COMMAND_INFO  infos[],
                                                     MOZA_SIZE*         infosSize);

/**
 * @brief Gets the HID devices associated with an open device.
 *
 * If @p infos is NULL, the function writes the required element count to @p infosSize.
 * If @p infos is not NULL and the supplied capacity is too small, the function writes the
 * required count to @p infosSize and returns MOZA_ERR_BUFFER_TOO_SMALL.
 *
 * The returned HID index identifies an entry in this list and is used by the other HID functions.
 *
 * @param handle Open device handle.
 * @param infos Output array of HID device information records, or NULL to query the required count.
 * @param infosSize On input, capacity of @p infos in elements. On output, required/returned count.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceHidGetList(MOZA_DEVICE_HANDLE   handle,
                                                 MOZA_HID_DEVICE_INFO infos[],
                                                 MOZA_SIZE*           infosSize);

/**
 * @brief Opens a HID device by index from Moza_DeviceHidGetList.
 *
 * @param handle Open device handle.
 * @param hidIndex HID device index in the root HID list.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceHidOpen(MOZA_DEVICE_HANDLE handle, uint8_t hidIndex);

/**
 * @brief Closes a HID device by index.
 *
 * @param handle Open device handle.
 * @param hidIndex HID device index in the root HID list.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceHidClose(MOZA_DEVICE_HANDLE handle, uint8_t hidIndex);

/**
 * @brief Gets a HID input state snapshot.
 *
 * The HID device must already be opened with Moza_DeviceHidOpen.
 * The function fills all supported axis values and button states.
 * The returned snapshot includes the timestamp of the last HID axis/button update reflected by the data.
 * Use MOZA_HID_INPUT_STATE_IS_BUTTON_PRESSED to test whether a button is currently pressed.
 *
 * @param handle Open device handle.
 * @param hidIndex HID device index in the root HID list.
 * @param inputState Output HID input state snapshot.
 * @return MOZA_ERR_NO_ERROR on success.
 */
MOZA_SDK_EXPORT MOZA_ERRNO Moza_DeviceHidGetInputState(MOZA_DEVICE_HANDLE    handle,
                                                       uint8_t               hidIndex,
                                                       MOZA_HID_INPUT_STATE* inputState);

#ifdef __cplusplus
}
#endif

#endif // MOZA_H
