#ifndef WIFI_INJECT_H
#define WIFI_INJECT_H

// ============================================================================
// wifi_inject.h — 802.11 frame injection via esp_wifi_80211_tx()
//
// Wraps the ESP32 raw frame injection API with save/restore of the existing
// promiscuous-mode + channel-scan state so the sensor transparently returns
// to passive sniffing after delivery completes.
//
// Injection mode table (data-driven; add new modes without code changes):
//
//   INJECT_RAW (0x00)
//     payload = fully-formed 802.11 frame, blasted as-is N times.
//
//   INJECT_DEAUTH (0x01)
//     Builds a deauth frame template targeting the BSSID set via
//     wifi_inject_set_channel() + caller-supplied dest MAC in the first 6
//     bytes of the frame buffer.  repeat = burst count.
//
//   INJECT_BEACON_FLOOD (0x02)
//     payload = 802.11 beacon template body (starting at frame body, after
//     the 24-byte fixed management header). Builds a full beacon frame with
//     a random TA/BSSID each iteration, iterates repeat times.
//
//   INJECT_TEMPLATE_PARAMETERIZED (0x03)
//     payload contains a frame template + substitution descriptors.
//     Template wire format (see SubstDescriptor below): allows the manifest
//     to describe arbitrary frame families (deauth/beacon/probe/custom) at
//     the C2 level without firmware code changes.
//
// Modes 0x04..0xFF are reserved for future ground/maritime templates; the
// mode field is 1 byte (256 values) per the protocol spec.
//
// State save/restore:
//   - wifi_inject_save_state() captures current promiscuous filter +
//     active channel.
//   - wifi_inject_restore_state() restores them and re-arms the promiscuous
//     RX callback.
//   - wifi_inject_send() calls save_state / restore_state internally if
//     auto_restore is true (default). Callers doing a sequence of injects
//     can call save/restore manually.
// ============================================================================

#include <cstdint>
#include <cstddef>
#include <stdbool.h>

// ---------------------------------------------------------------------------
// Injection mode constants
// ---------------------------------------------------------------------------
#define INJECT_RAW                     0x00u
#define INJECT_DEAUTH                  0x01u
#define INJECT_BEACON_FLOOD            0x02u
#define INJECT_TEMPLATE_PARAMETERIZED  0x03u

// ---------------------------------------------------------------------------
// Template substitution descriptor (used by INJECT_TEMPLATE_PARAMETERIZED)
//
// The payload for this mode is:
//   [0..1]        num_subst (LE uint16_t) — number of SubstDescriptors
//   [2..2+N*8-1]  SubstDescriptors (8 bytes each)
//   [2+N*8..]     frame_template bytes
//
// SubstDescriptor (8 bytes):
//   [0..1]  offset  (LE uint16_t) — byte offset in frame_template to patch
//   [2]     len     — number of bytes to write (1..6)
//   [3]     src     — SubstSrc enum: what value to substitute
//   [4..7]  value   — literal 4-byte LE value (used when src == SUBST_LITERAL)
// ---------------------------------------------------------------------------
enum SubstSrc : uint8_t {
    SUBST_LITERAL      = 0x00,  // paste value[0..len-1] directly
    SUBST_RANDOM_BYTES = 0x01,  // fill with PRNG bytes (useful for TA/BSSID flood)
    SUBST_SENSOR_ID    = 0x02,  // paste sensor_id LE
    SUBST_BSSID        = 0x03,  // paste target_bssid from manifest (6B)
    SUBST_SEQ_NUM      = 0x04,  // rolling 802.11 sequence number (2B)
};

struct SubstDescriptor {
    uint16_t offset;
    uint8_t  len;
    uint8_t  src;    // SubstSrc
    uint8_t  value[4];
};

// ---------------------------------------------------------------------------
// Saved radio state (opaque to callers; exposed for idempotency test)
// ---------------------------------------------------------------------------
struct InjectorSavedState {
    uint8_t  channel;
    bool     promiscuous_en;
    bool     valid;
};

// ---------------------------------------------------------------------------
// Init / state management
// ---------------------------------------------------------------------------

// Initialise the injector. Sets up internal PRNG seed from esp_random().
// Must be called before any other wifi_inject_* function.
bool wifi_inject_init();

// Save current promiscuous + channel state to internal slot.
// Returns false if esp_wifi_get_channel() fails.
bool wifi_inject_save_state();

// Switch to the specified channel for frame injection.
// Returns false on esp_wifi_set_channel() error.
bool wifi_inject_set_channel(uint8_t ch);

// Inject frames according to mode:
//   frame    — frame bytes (interpretation depends on mode; see header above)
//   len      — byte count
//   mode     — INJECT_* constant
//   repeat   — number of times to transmit (0 = 1 transmission)
// Returns number of frames successfully sent; -1 on fatal error (bad mode,
// null frame, allocation failure).
// Internally calls save_state before injection and restore_state after.
int wifi_inject_send(uint8_t* frame, size_t len, uint8_t mode, uint16_t repeat);

// Restore channel and promiscuous state previously captured by save_state.
// Returns false if no valid state was saved.
bool wifi_inject_restore_state();

// Retrieve a copy of the last saved state (for tests / diagnostics).
InjectorSavedState wifi_inject_get_saved_state();

#endif // WIFI_INJECT_H
