#ifndef FULLMODE_T1_H
#define FULLMODE_T1_H

/*  fullmode_t1.h — Firmware-side glue between cactus_fullmode lib and the
 *  existing model_manager / threat_correlator pipeline.
 *
 *  MODEL_BACKEND_CACTUS sentinel
 *  ─────────────────────────────
 *  model_manager.h has no backend-dispatch abstraction (every slot is TFLite).
 *  Rather than modify it, we expose a parallel infer function that mirrors the
 *  model_manager API signature exactly so its results can drop straight into
 *  correlator_feed() without changes to main.cpp — just one additional call
 *  block after the existing model_manager_infer_all_resident block.
 *
 *  Integration recipe (see INTEGRATION_NOTES.md for full detail):
 *
 *    // in setup(), after model_manager_init() and before correlator_init():
 *    fullmode_t1_init();
 *
 *    // in loop(), after the model_manager_infer_all_resident block:
 *    {
 *        static ModelInferenceResult fm_results[FULLMODE_T1_MAX_SLOTS];
 *        int fm_count = fullmode_t1_infer_all_resident(
 *            s_spectrum, SPECTRUM_BINS,
 *            fm_results, FULLMODE_T1_MAX_SLOTS);
 *        for (int i = 0; i < fm_count; i++) {
 *            if (fm_results[i].valid) correlator_feed(fm_results[i]);
 *        }
 *    }
 */

#include <stdint.h>
#include <stdbool.h>
#include "model_manager.h"   // for ModelInferenceResult + ModelPriority

// Sentinel backend identifier stored in ModelInferenceResult.slot_id upper nibble
// (0xC0 | cactus_slot_id). Allows the correlator or future dispatcher to tell
// which backend produced the result without any structural changes.
#define MODEL_BACKEND_CACTUS  0xC0u

// Maximum .cactus slots managed by fullmode_t1 (independent of TFLite slots)
#ifndef FULLMODE_T1_MAX_SLOTS
#  define FULLMODE_T1_MAX_SLOTS 4
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
 * fullmode_t1_init() — scan SPIFFS /models/*.cactus, call cactus_fm_init(),
 * load each file, log slot assignments.
 * Call from setup() after model_manager_init() and before correlator_init().
 */
void fullmode_t1_init(void);

/**
 * fullmode_t1_infer_all_resident() — run inference on every loaded .cactus slot.
 *
 * Mirrors model_manager_infer_all_resident() in signature so the loop in
 * main.cpp can call both back-to-back and feed results to correlator_feed().
 *
 * slot_id in each result is (MODEL_BACKEND_CACTUS | cactus_slot_id) to avoid
 * collisions with TFLite slot numbering.
 *
 * @param input_data  float spectrum array (SPECTRUM_BINS floats)
 * @param input_len   must equal the model's input_dim (128 for threat_classifier)
 * @param results     caller-allocated array of at least max_results entries
 * @param max_results maximum results to write
 * @return number of valid results written to results[]
 */
int fullmode_t1_infer_all_resident(const float* input_data,
                                   uint16_t     input_len,
                                   ModelInferenceResult* results,
                                   int          max_results);

/**
 * fullmode_t1_psram_used() — PSRAM bytes consumed by all .cactus slots.
 */
uint32_t fullmode_t1_psram_used(void);

#ifdef UNIT_TEST
/**
 * fullmode_t1_test_reset() — host-test only. Clears all tracked slots.
 */
void fullmode_t1_test_reset(void);

/**
 * fullmode_t1_test_seed_slot() — host-test only. Directly registers a slot
 * as if fullmode_t1_init()'s SPIFFS scan had loaded it, bypassing LittleFS
 * entirely (native builds have no filesystem). cactus_slot is whatever the
 * test's cactus_fm_load() stub returned for this model. Returns the new
 * slot's index (== fullmode_t1's own slot count before the call), or -1 if
 * FULLMODE_T1_MAX_SLOTS is already full.
 */
int fullmode_t1_test_seed_slot(int cactus_slot, int input_dim, int output_dim);
#endif

#ifdef __cplusplus
}
#endif

#endif /* FULLMODE_T1_H */
