#ifndef JAMMING_DETECTOR_H
#define JAMMING_DETECTOR_H

// ============================================================================
// Tier-1 RID Sensor — Counter-RF / Active Jamming Detector
//
// Detects potential jamming across three independent evidence channels:
//
//   Channel A — LoRa packet loss rate
//     Maintains a sliding window of TX/RX outcomes.  If the loss rate exceeds
//     JAMMING_LOSS_RATE_THRESHOLD for JAMMING_LOSS_WINDOW_CYCLES consecutive
//     observation cycles, reason code 1 (high_loss) is raised.
//
//   Channel B — WiFi channel-RSSI standard deviation
//     Maintains a per-channel RSSI history across all 13 WiFi channels.  When
//     the cross-channel std-dev exceeds JAMMING_RSSI_STDDEV_THRESHOLD the
//     spectrum is considered abnormally uneven; reason code 2
//     (spectrum_anomaly) is raised.
//
//   Channel C — Noise-floor drift
//     Tracks a long-term baseline RSSI.  A sudden rise larger than
//     JAMMING_NOISE_FLOOR_JUMP_DBM (default 30 dBm) triggers reason code 3
//     (noise_floor_jump).
//
// When any channel triggers, the module broadcasts a one-shot mesh alert
// (MSG_TYPE_JAMMING_ALERT = 0x1A, 8 bytes) via mesh_publish_raw(), then
// suppresses further alerts for JAMMING_ALERT_COOLDOWN_S seconds.
//
// Reason codes (also returned via jamming_is_alarmed()):
//   0 = ok
//   1 = high_loss
//   2 = spectrum_anomaly
//   3 = noise_floor_jump
//
// #ifdef ARDUINO guards isolate mesh_publish_raw() calls so the module
// compiles under the native (host) test environment.
// ============================================================================

#include <cstdint>
#include <cstdbool>

// ---- Tunable thresholds ---------------------------------------------------
// Fraction of packets lost before high-loss alarm (0.0 – 1.0 scale * 100)
#define JAMMING_LOSS_RATE_THRESHOLD      70   // 70 % loss

// Number of observation slots in the packet-loss window
#define JAMMING_LOSS_WINDOW_SLOTS        20

// Cross-channel RSSI std-dev threshold (dBm units, integer)
#define JAMMING_RSSI_STDDEV_THRESHOLD    25

// Noise-floor jump that triggers alarm (dBm, positive = rise)
#define JAMMING_NOISE_FLOOR_JUMP_DBM     30

// Minimum interval between alarm broadcasts (seconds)
#define JAMMING_ALERT_COOLDOWN_S         60

// Number of WiFi channels tracked
#define JAMMING_WIFI_CHANNEL_COUNT       13

// Wire format: MSG_TYPE_JAMMING_ALERT = 0x1A  (do NOT define here — goes in
// config.h; integrator adds #define MSG_TYPE_JAMMING_ALERT 0x1A)
#define JAMMING_ALERT_MSG_TYPE           0x1Au
#define JAMMING_ALERT_PACKET_SIZE        8

// Reason code constants
#define JAMMING_REASON_OK                0u
#define JAMMING_REASON_HIGH_LOSS         1u
#define JAMMING_REASON_SPECTRUM_ANOMALY  2u
#define JAMMING_REASON_NOISE_FLOOR_JUMP  3u

// ---------------------------------------------------------------------------
// Initialize the jamming detector.  Must be called from setup().
// Resets all history buffers and clears the alarm state.
// ---------------------------------------------------------------------------
void jamming_init();

// ---------------------------------------------------------------------------
// Feed one observation.  Call this:
//   - From the WiFi sniffer callback / channel-scan loop for RSSI samples.
//   - From the LoRa TX/RX completion handler with packet_received_ok.
// Parameters:
//   channel           — WiFi channel (1–13); ignored for LoRa observations
//                       (use channel = 0 to feed LoRa packet outcome only)
//   rssi              — measured RSSI in dBm (e.g. -85)
//   packet_received_ok — true if the associated LoRa packet was received
//                        without error; false for a lost/corrupt packet
// ---------------------------------------------------------------------------
void jamming_observe(uint8_t channel, int16_t rssi, bool packet_received_ok);

// ---------------------------------------------------------------------------
// Query current alarm state.
// Returns true if any jamming channel is currently triggered.
// If reason_code is non-null it is set to the highest-priority active reason
// (3 > 2 > 1 > 0).
// ---------------------------------------------------------------------------
bool jamming_is_alarmed(uint8_t* reason_code);

#endif // JAMMING_DETECTOR_H
