#ifndef MYTHOS_BRIDGE_H
#define MYTHOS_BRIDGE_H

// ============================================================================
// mythos_bridge.h — Direct WiFi client for the Mythos federated-retraining
// gateway's HTTP API (ADDITIVE, off by default).
//
// Today T1 only receives model-weight updates via a chunked LoRa broadcast
// (talon_federated.cpp), which requires waiting for a full multi-hop relay
// cycle. mythos-fedretrain-gateway (the Pi5 T2 daemon) also exposes plain
// HTTP: GET /api/fed/corrections/pending — human-operator label corrections
// queued via OpenForge C2. When T1 happens to hold its own WiFi connection
// (see wifi_status_server.h), it can pull these directly over 2.4GHz instead
// of waiting on the LoRa path — faster, and works even when no LoRa gateway
// is in range but WiFi is.
//
// FIXED 2026-07-30: corrections are now actually APPLIED, not just counted.
// Read gateway/fed_gateway.py in the mythos-fedretrain repo directly --
// label_from/label_to in the /api/fed/corrections/pending response are
// plain integers (aggregator.add_correction()'s parameters, same value
// range as talon_federated's FedDelta.label_from/label_to byte fields) and
// there is no other label vocabulary defined anywhere in this system, so
// they ARE T1's own ClassLabel indices -- the "arbitrary indices, no
// defined mapping" caveat that used to be here was written without having
// read the gateway source; the mapping is the identity mapping, now that
// it's actually been checked. Only indices < NUM_CLASSES (the 7 real
// classifier outputs) are ever remapped; CLASS_RID_BLE_DECODED (7) /
// CLASS_RID_WIFI_DECODED (8) are direct-decoded message content, not
// classifier output, so a correction against them is meaningless and is
// silently ignored.
//
// NOTE: mythos-fedretrain's get_pending_corrections() has consume-once
// semantics (each correction is popped off the gateway's queue the moment
// it's served) -- before this fix, every correction T1 ever polled for was
// fetched, counted, and then permanently discarded, since nothing captured
// label_from/label_to. That data loss is what this fix closes.
//
// The gradient-PUSH side (POST /api/fed/delta) still requires on-device
// gradient computation, which talon_federated.h already documents as
// v2/deferred -- not attempted here; this fix is specifically the
// consume-a-human-correction path, which needs no on-device training.
//
// Join via the serial console (mirrors WIFI_CONNECT's pattern):
//   MYTHOS_CONNECT <host> <port>
// ============================================================================

#include <cstdint>
#include <cstddef>

// Minimal, honest-scope parse: counts `"id":` occurrences in a corrections-
// array JSON response body to report how many are pending. Kept as a
// simple standalone counter (e.g. for logging); mythos_bridge_tick() itself
// now uses mythos_bridge_parse_and_apply_corrections() below instead, since
// that also needs to walk the same body. Pure (no HTTP/Arduino dependency)
// -- safe to unit test directly without a real Mythos gateway.
uint32_t mythos_bridge_count_corrections(const char* body);

// Parses every {"label_from":N,"label_to":M} pair in a corrections-array
// JSON body (same lightweight text-scan style as the counter above, no
// JSON library) and applies each to the in-RAM correction table consulted
// by mythos_bridge_apply_correction(). Returns how many were actually
// applied (out-of-range label_from/label_to, i.e. >= NUM_CLASSES, are
// silently skipped -- see the design note above for why). Pure -- safe to
// unit test directly.
uint32_t mythos_bridge_parse_and_apply_corrections(const char* body);

// Looks up raw_label (a fresh classifier_infer() result) in the correction
// table and returns the corrected label -- identity (raw_label unchanged)
// for anything no correction has ever touched, or for raw_label >=
// NUM_CLASSES (direct-decoded classes, never classifier output). Call this
// on every classifier result before using it for anything -- see the
// classification block in main.cpp. Pure -- safe to unit test directly.
uint8_t mythos_bridge_apply_correction(uint8_t raw_label);

void mythos_bridge_init();
void mythos_bridge_tick();
void mythos_bridge_connect(const char* host, uint16_t port);

struct MythosBridgeStats {
    bool     configured;        // MYTHOS_CONNECT has been issued
    uint32_t poll_count;
    uint32_t poll_failures;
    uint32_t corrections_seen_total;
    uint32_t corrections_applied_total;
    uint32_t last_poll_ms;
};

void mythos_bridge_get_stats(MythosBridgeStats* out);

#ifdef UNIT_TEST
// White-box reset of the module-local correction remap table and stats --
// no public "factory reset" API exists on a real sensor (a correction is
// meant to persist for the sensor's uptime), so tests need this to isolate
// cases from each other. Mirrors the *_test_reset() convention used
// elsewhere in this repo (e.g. uav_pairing_test_reset()).
void mythos_bridge_test_reset();
#endif

#endif // MYTHOS_BRIDGE_H
