/**
 * @file Syna.h
 * @brief C-ABI interface for Syna embedded database
 * 
 * Syna is an embedded, log-structured, columnar-mapped database engine
 * optimized for time-series data and AI/ML tensor extraction.
 * 
 * @example
 * ```c
 * #include "Syna.h"
 * 
 * int main() {
 *     // Open database
 *     if (SYNA_open("my.db") != SYNA_SUCCESS) {
 *         return 1;
 *     }
 *     
 *     // Write values
 *     SYNA_put_float("my.db", "temperature", 23.5);
 *     
 *     // Read values
 *     double temp;
 *     if (SYNA_get_float("my.db", "temperature", &temp) == SYNA_SUCCESS) {
 *         printf("Temperature: %f\n", temp);
 *     }
 *     
 *     // Close database
 *     SYNA_close("my.db");
 *     return 0;
 * }
 * ```
 */

#ifndef SYNA_H
#define SYNA_H

#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/* ============================================================================
 * Error Codes
 * ============================================================================ */

/** Operation completed successfully */
#define SYNA_SUCCESS         1

/** Generic/unspecified error */
#define SYNA_ERR_GENERIC     0

/** Database not found in registry (call SYNA_open first) */
#define SYNA_ERR_DB_NOT_FOUND    -1

/** Invalid path (null pointer or invalid UTF-8) */
#define SYNA_ERR_INVALID_PATH    -2

/** I/O error during file operations */
#define SYNA_ERR_IO              -3

/** Serialization/deserialization error */
#define SYNA_ERR_SERIALIZATION   -4

/** Key not found in database */
#define SYNA_ERR_KEY_NOT_FOUND   -5

/** Type mismatch (e.g., reading float from int key) */
#define SYNA_ERR_TYPE_MISMATCH   -6

/** Empty key is not allowed */
#define SYNA_ERR_EMPTY_KEY       -7

/** Key exceeds maximum length (65535 bytes) */
#define SYNA_ERR_KEY_TOO_LONG    -8

/** Internal panic (should not occur in normal operation) */
#define SYNA_ERR_INTERNAL_PANIC  -100

/* ============================================================================
 * Database Lifecycle Functions
 * ============================================================================ */

/**
 * Opens a database at the given path and registers it in the global registry.
 * 
 * If the database file exists, the index is rebuilt by scanning all entries.
 * If the file doesn't exist, a new empty database is created.
 * If the database is already open, this function returns success.
 * 
 * @param path  Null-terminated path to the database file
 * @return      SYNA_SUCCESS on success, error code on failure
 * 
 * @note The database must be closed with SYNA_close() when done.
 */
int32_t SYNA_open(const char* path);

/**
 * Closes a database and removes it from the global registry.
 * 
 * Flushes any pending writes to disk before closing.
 * 
 * @param path  Null-terminated path to the database file
 * @return      SYNA_SUCCESS on success, error code on failure
 */
int32_t SYNA_close(const char* path);

/* ============================================================================
 * Write Functions
 * ============================================================================ */

/**
 * Writes a float (f64) value to the database.
 * 
 * @param path   Null-terminated path to the database file
 * @param key    Null-terminated key string (max 65535 bytes)
 * @param value  The float value to store
 * @return       Byte offset where entry was written (>= 0), or error code (< 0)
 */
int64_t SYNA_put_float(const char* path, const char* key, double value);

/**
 * Writes an integer (i64) value to the database.
 * 
 * @param path   Null-terminated path to the database file
 * @param key    Null-terminated key string (max 65535 bytes)
 * @param value  The integer value to store
 * @return       Byte offset where entry was written (>= 0), or error code (< 0)
 */
int64_t SYNA_put_int(const char* path, const char* key, int64_t value);

/**
 * Writes a text (string) value to the database.
 * 
 * @param path   Null-terminated path to the database file
 * @param key    Null-terminated key string (max 65535 bytes)
 * @param value  Null-terminated text value to store
 * @return       Byte offset where entry was written (>= 0), or error code (< 0)
 */
int64_t SYNA_put_text(const char* path, const char* key, const char* value);

/**
 * Writes a byte array to the database.
 * 
 * @param path   Null-terminated path to the database file
 * @param key    Null-terminated key string (max 65535 bytes)
 * @param data   Pointer to byte array to store
 * @param len    Length of the byte array
 * @return       Byte offset where entry was written (>= 0), or error code (< 0)
 */
int64_t SYNA_put_bytes(const char* path, const char* key, const uint8_t* data, size_t len);

/* ============================================================================
 * Read Functions
 * ============================================================================ */

/**
 * Reads the latest float value for a key.
 * 
 * @param path  Null-terminated path to the database file
 * @param key   Null-terminated key string
 * @param out   Pointer to store the retrieved value
 * @return      SYNA_SUCCESS on success, error code on failure
 * 
 * @note Returns SYNA_ERR_KEY_NOT_FOUND if key doesn't exist
 * @note Returns SYNA_ERR_TYPE_MISMATCH if value is not a float
 */
int32_t SYNA_get_float(const char* path, const char* key, double* out);

/**
 * Reads the latest integer value for a key.
 * 
 * @param path  Null-terminated path to the database file
 * @param key   Null-terminated key string
 * @param out   Pointer to store the retrieved value
 * @return      SYNA_SUCCESS on success, error code on failure
 * 
 * @note Returns SYNA_ERR_KEY_NOT_FOUND if key doesn't exist
 * @note Returns SYNA_ERR_TYPE_MISMATCH if value is not an integer
 */
int32_t SYNA_get_int(const char* path, const char* key, int64_t* out);

/**
 * Reads the latest text value for a key.
 * 
 * @param path     Null-terminated path to the database file
 * @param key      Null-terminated key string
 * @param out_len  Pointer to store the string length (excluding null terminator)
 * @return         Pointer to null-terminated string, or NULL on error/not found
 * 
 * @warning The returned pointer MUST be freed with SYNA_free_text()
 * 
 * @example
 * ```c
 * size_t len;
 * char* text = SYNA_get_text("my.db", "message", &len);
 * if (text) {
 *     printf("Message: %s (len=%zu)\n", text, len);
 *     SYNA_free_text(text, len);
 * }
 * ```
 */
char* SYNA_get_text(const char* path, const char* key, size_t* out_len);

/**
 * Frees memory allocated by SYNA_get_text().
 * 
 * @param ptr  Pointer returned by SYNA_get_text()
 * @param len  Length returned by SYNA_get_text() (excluding null terminator)
 * 
 * @note Safe to call with NULL pointer (no-op)
 */
void SYNA_free_text(char* ptr, size_t len);

/**
 * Reads the latest byte array value for a key.
 * 
 * @param path     Null-terminated path to the database file
 * @param key      Null-terminated key string
 * @param out_len  Pointer to store the array length
 * @return         Pointer to byte array, or NULL on error/not found
 * 
 * @warning The returned pointer MUST be freed with SYNA_free_bytes()
 * 
 * @example
 * ```c
 * size_t len;
 * uint8_t* data = SYNA_get_bytes("my.db", "binary_data", &len);
 * if (data) {
 *     // Use data...
 *     SYNA_free_bytes(data, len);
 * }
 * ```
 */
uint8_t* SYNA_get_bytes(const char* path, const char* key, size_t* out_len);

/**
 * Frees memory allocated by SYNA_get_bytes().
 * 
 * @param ptr  Pointer returned by SYNA_get_bytes()
 * @param len  Length returned by SYNA_get_bytes()
 * 
 * @note Safe to call with NULL pointer or zero length (no-op)
 */
void SYNA_free_bytes(uint8_t* ptr, size_t len);

/* ============================================================================
 * Tensor Functions (AI/ML)
 * ============================================================================ */

/**
 * Retrieves the complete history of float values for a key as a contiguous array.
 * 
 * This function is optimized for AI/ML workloads where you need to feed
 * time-series data directly to frameworks like PyTorch or TensorFlow.
 * 
 * @param path     Null-terminated path to the database file
 * @param key      Null-terminated key string
 * @param out_len  Pointer to store the array length
 * @return         Pointer to contiguous f64 array, or NULL on error
 * 
 * @warning The returned pointer MUST be freed with SYNA_free_tensor()
 * 
 * @example
 * ```c
 * size_t len;
 * double* tensor = SYNA_get_history_tensor("my.db", "sensor", &len);
 * if (tensor) {
 *     // Use tensor data...
 *     SYNA_free_tensor(tensor, len);
 * }
 * ```
 */
double* SYNA_get_history_tensor(const char* path, const char* key, size_t* out_len);

/**
 * Frees memory allocated by SYNA_get_history_tensor().
 * 
 * @param ptr  Pointer returned by SYNA_get_history_tensor()
 * @param len  Length returned by SYNA_get_history_tensor()
 * 
 * @note Safe to call with NULL pointer or zero length (no-op)
 * @note Must only be called once per pointer
 */
void SYNA_free_tensor(double* ptr, size_t len);

/* ============================================================================
 * Delete Functions
 * ============================================================================ */

/**
 * Deletes a key from the database by appending a tombstone entry.
 * 
 * The key will no longer appear in SYNA_keys() and SYNA_get_*()
 * will return SYNA_ERR_KEY_NOT_FOUND.
 * 
 * @param path  Null-terminated path to the database file
 * @param key   Null-terminated key string to delete
 * @return      SYNA_SUCCESS on success, error code on failure
 * 
 * @note Writing to a deleted key "resurrects" it with the new value
 */
int32_t SYNA_delete(const char* path, const char* key);

/**
 * Checks if a key exists in the database and is not deleted.
 * 
 * @param path  Null-terminated path to the database file
 * @param key   Null-terminated key string to check
 * @return      1 if key exists, 0 if not, negative error code on failure
 */
int32_t SYNA_exists(const char* path, const char* key);

/* ============================================================================
 * Maintenance Functions
 * ============================================================================ */

/**
 * Compacts the database by rewriting only the latest non-deleted entries.
 * 
 * This operation reclaims disk space by removing:
 * - Deleted entries (tombstones)
 * - Old versions of keys (only latest value is kept)
 * 
 * @param path  Null-terminated path to the database file
 * @return      SYNA_SUCCESS on success, error code on failure
 * 
 * @warning After compaction, get_history() will only return the latest value
 */
int32_t SYNA_compact(const char* path);

/**
 * Returns a list of all non-deleted keys in the database.
 * 
 * @param path     Null-terminated path to the database file
 * @param out_len  Pointer to store the number of keys
 * @return         Array of null-terminated key strings, or NULL on error
 * 
 * @warning The returned array MUST be freed with SYNA_free_keys()
 * 
 * @example
 * ```c
 * size_t len;
 * char** keys = SYNA_keys("my.db", &len);
 * if (keys) {
 *     for (size_t i = 0; i < len; i++) {
 *         printf("Key: %s\n", keys[i]);
 *     }
 *     SYNA_free_keys(keys, len);
 * }
 * ```
 */
char** SYNA_keys(const char* path, size_t* out_len);

/**
 * Frees memory allocated by SYNA_keys().
 * 
 * @param keys  Array returned by SYNA_keys()
 * @param len   Length returned by SYNA_keys()
 * 
 * @note Safe to call with NULL pointer or zero length (no-op)
 * @note Must only be called once per pointer
 */
void SYNA_free_keys(char** keys, size_t len);

#ifdef __cplusplus
}
#endif

#endif /* SYNA_H */

