#ifndef CACTUS_FULLMODE_H
#define CACTUS_FULLMODE_H

/*  cactus_fullmode.h — PlatformIO library wrapper for Full Mode .cactus inference
 *
 *  Reads the binary .cactus format (magic "CACTFM01", little-endian header JSON,
 *  followed by raw weight blobs) from SPIFFS, allocates all tensors in PSRAM via
 *  heap_caps_malloc(MALLOC_CAP_SPIRAM), and dispatches inference through the pure-C
 *  kernels in fullmode_kernels.c.
 *
 *  Supports up to CACTUS_FM_MAX_SLOTS concurrent models, up to
 *  CACTUS_FM_MAX_LAYERS layers per model, fp32 and int8-quantized linear layers,
 *  ReLU activations, and softmax output.  No STL in hot path.
 *
 *  PSRAM budget: CACTUS_FM_PSRAM_PER_SLOT bytes per slot (default 256 KB).
 *  Total worst-case: 4 * 256 KB = 1 MB (document this in INTEGRATION_NOTES.md).
 */

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

#ifdef __cplusplus
extern "C" {
#endif

// ---------------------------------------------------------------------------
// Tuneable constants — override via build_flags if needed
// ---------------------------------------------------------------------------
#ifndef CACTUS_FM_MAX_SLOTS
#  define CACTUS_FM_MAX_SLOTS   4
#endif

#ifndef CACTUS_FM_MAX_LAYERS
#  define CACTUS_FM_MAX_LAYERS  16
#endif

#ifndef CACTUS_FM_PSRAM_PER_SLOT
#  define CACTUS_FM_PSRAM_PER_SLOT  (256 * 1024)
#endif

// Maximum JSON header size for any .cactus file (parsed once at load time)
#ifndef CACTUS_FM_MAX_HEADER_JSON
#  define CACTUS_FM_MAX_HEADER_JSON  2048
#endif

// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------

/**
 * cactus_fm_init() — allocate shared scratch arena in PSRAM.
 * Call once from setup(), before any load/infer.
 * Returns true on success.
 */
bool cactus_fm_init(void);

/**
 * cactus_fm_load() — load a .cactus file from LittleFS.
 * @param spiffs_path  e.g. "/models/threat_classifier.cactus"
 * @return slot id (0..CACTUS_FM_MAX_SLOTS-1), or -1 on failure.
 */
int cactus_fm_load(const char* spiffs_path);

/**
 * cactus_fm_infer() — run forward pass on a loaded slot.
 * @param slot       slot id returned by cactus_fm_load()
 * @param in         input float array (length in_len)
 * @param in_len     must equal the model's input_shape[0]
 * @param out        caller-allocated output float array (length out_len)
 * @param out_len    must be >= model's output_shape[0]
 * @return true if inference succeeded and out[] is valid
 */
bool cactus_fm_infer(int slot,
                     const float* in,  size_t in_len,
                     float*       out, size_t out_len);

/**
 * cactus_fm_unload() — free all PSRAM for a slot.
 * Returns true if the slot was loaded and is now freed.
 */
bool cactus_fm_unload(int slot);

/**
 * cactus_fm_psram_used() — total PSRAM bytes currently held by all loaded slots.
 */
size_t cactus_fm_psram_used(void);

#ifdef __cplusplus
}
#endif

#endif /* CACTUS_FULLMODE_H */
