#pragma once

#include <stdbool.h> // For bool type
#include <stddef.h>  // For size_t (though not directly used, common practice)

#ifdef __cplusplus
extern "C" {
#endif

// C header definitions
typedef struct {
    const char** strings;
    int count;
} StringArray;

typedef struct {
    const char* key;
    const char* value;
} KeyValuePair;

typedef struct {
    KeyValuePair* pairs;
    int count;
} Dictionary;

// --- Client Management ---

/**
 * @brief Creates a new Firefly client instance and connects to the server.
 * @param host Null-terminated UTF-8 string for the server hostname or IP.
 * @param port The server port number.
 * @return A handle (void*) representing the client instance, or NULL on failure.
 *         This handle must be passed to other functions and eventually freed with DestroyClient.
 */
void* CreateClient(const char* host, int port);

/**
 * @brief Disposes of the Firefly client instance and frees associated resources.
 * @param handle The client handle obtained from CreateClient.
 */
void DestroyClient(void* handle);

/**
 * @brief Authenticates the client connection with the server.
 * @param handle The client handle.
 * @param password Null-terminated UTF-8 string for the password.
 * @return true if authentication was successful, false otherwise.
 */
bool Authenticate(void* handle, const char* password);

// --- String Operations ---

/**
 * @brief Sets a string value for a given key.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the key.
 * @param value Null-terminated UTF-8 string for the value.
 * @return true if the operation was successful, false otherwise.
 */
bool StringSet(void* handle, const char* key, const char* value);

/**
 * @brief Gets the string value for a given key.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the key.
 * @return A pointer to a null-terminated UTF-8 string containing the value.
 *         This string is allocated by the library and MUST be freed by the caller using FreeString().
 *         Returns NULL if the key does not exist or an error occurs.
 */
char* StringGet(void* handle, const char* key);

/**
 * @brief Deletes a key.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the key to delete.
 * @return The number of keys deleted (usually 1 if the key existed, 0 otherwise), or 0 on error.
 */
int Delete(void* handle, const char* key);

/**
 * @brief Frees memory allocated by the library for returned strings (e.g., from StringGet).
 * @param str Pointer to the string allocated by the library.
 */
void FreeString(char* str);

// --- List Operations ---

/**
 * @brief Adds a value to the beginning (left side) of a list.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @param value Null-terminated UTF-8 string for the value to add.
 * @return The length of the list after the push operation, or 0 on error.
 */
int ListLeftPush(void* handle, const char* key, const char* value);

/**
 * @brief Adds a value to the end (right side) of a list.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @param value Null-terminated UTF-8 string for the value to add.
 * @return The length of the list after the push operation, or 0 on error.
 */
int ListRightPush(void* handle, const char* key, const char* value);

/**
 * @brief Removes and returns the first element (left side) of a list.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @return A pointer to a null-terminated UTF-8 string containing the popped value.
 *         This string is allocated by the library and MUST be freed by the caller using FreeString().
 *         Returns NULL if the list is empty or an error occurs.
 */
char* ListLeftPop(void* handle, const char* key);

/**
 * @brief Removes and returns the last element (right side) of a list.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @return A pointer to a null-terminated UTF-8 string containing the popped value.
 *         This string is allocated by the library and MUST be freed by the caller using FreeString().
 *         Returns NULL if the list is empty or an error occurs.
 */
char* ListRightPop(void* handle, const char* key);

/**
 * @brief Gets a range of elements from a list.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @param start The start index (0-based).
 * @param stop The stop index (0-based, inclusive). Use -1 to specify the end of the list.
 * @return A StringArray structure containing the elements in the specified range.
 *         The caller is responsible for freeing the memory allocated for the StringArray structure using FreeStringArray().
 *         Returns NULL if the key does not exist or an error occurs.
 */
StringArray ListRange(void* handle, const char* key, int start, int stop);

/**
 * @brief Gets the element at the specified index in a list.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @param index The 0-based index of the element.
 * @return A pointer to a null-terminated UTF-8 string containing the element.
 *         This string is allocated by the library and MUST be freed by the caller using FreeString().
 *         Returns NULL if the index is out of range or an error occurs.
 */
char* ListIndex(void* handle, const char* key, int index);

/**
 * @brief Sets the list element at the specified index.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @param index The 0-based index of the element to set.
 * @param value Null-terminated UTF-8 string for the new value.
 * @return true if the operation was successful, false if the index is out of range or an error occurs.
 */
bool ListSet(void* handle, const char* key, int index, const char* value);

/**
 * @brief Returns the index of the first occurrence of an element in a list.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @param element Null-terminated UTF-8 string for the element to find.
 * @param rank Optional rank for finding duplicates (not typically used/supported).
 * @param maxlen Optional max length to search (not typically used/supported).
 * @return The 0-based index of the element, or -1 if not found or on error.
 */
int ListPosition(void* handle, const char* key, const char* element, int rank, int maxlen);

/**
 * @brief Trims a list to contain only the specified range of elements.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @param start The start index (0-based).
 * @param stop The stop index (0-based, inclusive). Use -1 for end.
 * @return true if the operation was successful, false otherwise.
 */
bool ListTrim(void* handle, const char* key, int start, int stop);

/**
 * @brief Removes occurrences of elements from a list.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @param count Number of occurrences to remove:
 *              count > 0: Remove elements equal to 'element' moving from head to tail.
 *              count < 0: Remove elements equal to 'element' moving from tail to head.
 *              count = 0: Remove all elements equal to 'element'.
 * @param element Null-terminated UTF-8 string for the element to remove.
 * @return The number of elements removed, or 0 on error.
 */
int ListRemove(void* handle, const char* key, int count, const char* element);

/**
 * @brief Gets the length of a list.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the list key.
 * @return The length of the list, or 0 on error.
 */
int ListLength(void* handle, const char* key);

/**
 * @brief Frees a StringArray structure and its contents.
 * @param array Pointer to the StringArray structure to be freed.
 */
void FreeStringList(StringArray array);

// --- Hash Operations ---

/**
 * @brief Sets the value of a field within a hash.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the hash key.
 * @param field Null-terminated UTF-8 string for the field name.
 * @param value Null-terminated UTF-8 string for the value.
 * @return true if the operation was successful (field created or updated), false on error.
 */
bool HashSet(void* handle, const char* key, const char* field, const char* value);

/**
 * @brief Gets the value of a field within a hash.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the hash key.
 * @param field Null-terminated UTF-8 string for the field name.
 * @return A pointer to a null-terminated UTF-8 string containing the field's value.
 *         This string is allocated by the library and MUST be freed by the caller using FreeString().
 *         Returns NULL if the key or field does not exist or an error occurs.
 */
char* HashGet(void* handle, const char* key, const char* field);

/**
 * @brief Deletes a field from a hash.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the hash key.
 * @param field Null-terminated UTF-8 string for the field to delete.
 * @return true if the field was deleted, false if the field or key did not exist or on error.
 */
bool HashDelete(void* handle, const char* key, const char* field);

/**
 * @brief Checks if a field exists within a hash.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the hash key.
 * @param field Null-terminated UTF-8 string for the field name.
 * @return true if the field exists, false otherwise or on error.
 */
bool HashFieldExists(void* handle, const char* key, const char* field);

/**
 * @brief Gets all fields and values from a hash.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the hash key.
 * @return A Dictionary structure containing all fields and values in the hash.
 *         The caller is responsible for freeing the memory allocated for the Dictionary structure using FreeDictionary().
 *         Returns NULL if the key does not exist or an error occurs.
 */
Dictionary HashGetAll(void* handle, const char* key);

/**
 * @brief Sets multiple fields and values in a hash.
 * @param handle The client handle.
 * @param key Null-terminated UTF-8 string for the hash key.
 * @param fieldValuePairs Null-terminated UTF-8 string containing space-separated field-value pairs.
 *                        Example: "field1 value1 field2 value2 field3 value3"
 * @warning Values containing spaces are not properly handled by the basic parsing.
 * @return true if the operation was successful, false on error (e.g., odd number of items in pairs string).
 */
bool HashMultiSet(void* handle, const char* key, const char* fieldValuePairs);

/**
 * @brief Frees the memory allocated for a Dictionary structure.
 * @param dict Pointer to the Dictionary structure to be freed.
 */
void FreeDictionary(Dictionary dict);

// --- Raw Command Execution ---

/**
 * @brief Executes a raw command string with optional arguments.
 * @warning The argument parsing is basic (simple space split) and may not handle arguments with spaces correctly.
 *          Prefer using the specific typed functions (StringSet, ListLeftPush, etc.) for reliability.
 * @param handle The client handle.
 * @param command Null-terminated UTF-8 string for the command (e.g., "PING").
 * @param args Null-terminated UTF-8 string containing space-separated arguments (e.g., "mykey myvalue").
 * @return A pointer to a null-terminated UTF-8 string containing the raw server response.
 *         This string is allocated by the library and MUST be freed by the caller using FreeString().
 *         Returns NULL on error.
 */
char* ExecuteCommand(void* handle, const char* command, const char* args);

/**
 * @brief Gets all keys matching the specified pattern.
 * @param handle The client handle.
 * @param pattern Null-terminated UTF-8 string for the pattern to match against keys (e.g., "*" for all keys).
 * @return A pointer to a null-terminated UTF-8 string containing newline-delimited keys.
 *         This string is allocated by the library and MUST be freed by the caller using FreeString().
 *         Returns NULL if no keys are found or on error.
 */
char* Keys(void* handle, const char* pattern);

// --- Pipeline Operations ---

/**
 * @brief Enables or disables pipeline mode for the client.
 * @param handle The client handle.
 * @param enabled true to enable pipeline mode, false to disable.
 * @return true if the mode was set successfully, false on error.
 */
bool SetPipelineMode(void* handle, bool enabled);

/**
 * @brief Sets the maximum number of commands to batch in pipeline mode.
 * @param handle The client handle.
 * @param size The maximum number of commands to queue before sending.
 * @return true if the batch size was set successfully, false on error (e.g., invalid size).
 */
bool SetBatchSize(void* handle, int size);

/**
 * @brief Sends all queued commands to the server immediately.
 * @param handle The client handle.
 * @return A pointer to a null-terminated UTF-8 string containing the raw combined server response for all flushed commands.
 *         This string is allocated by the library and MUST be freed by the caller using FreeString().
 *         Returns NULL if the queue was empty or an error occurs.
 */
char* FlushPipeline(void* handle);

/**
 * @brief Gets the number of commands currently waiting in the pipeline queue.
 * @param handle The client handle.
 * @return The number of queued commands, or 0 on error.
 */
int GetQueuedCommandCount(void* handle);

/**
 * @brief Checks if pipeline mode is currently enabled for the client.
 * @param handle The client handle.
 * @return true if pipeline mode is enabled, false otherwise or on error.
 */
bool IsPipelineMode(void* handle);

/**
 * @brief Gets the current maximum batch size configured for pipeline mode.
 * @param handle The client handle.
 * @return The maximum batch size, or 0 on error.
 */
int GetBatchSize(void* handle);

#ifdef __cplusplus
}
#endif