#ifndef UAV_RELAY_H
#define UAV_RELAY_H

// ============================================================================
// T1 UAV Relay — STANAG 4586 binary frame → serial MAVLink bridge
//
// Heltec V4 acting as a LoRa-to-serial bridge for a connected ArduPilot
// drone radio modem. Receives 32-byte STANAG 4586 frames on the sensor
// mesh (distinct msg_type byte 0x0A = UAV_CMD), parses them, and emits
// a synthesized MAVLink message out UART TX to the drone.
//
// Compile-out:
//     #define PDL_ENABLE_UAV_RELAY  to build this module.
// When the macro is undefined, uav_relay_handle() is a no-op stub so
// firmware builds without UAV capability link unchanged.
// ============================================================================

#include <cstdint>
#include <cstddef>

// Distinct LoRa msg_type byte for UAV commands (not in config.h to keep
// the sensor protocol independent of UAV opt-in).
#define MSG_TYPE_UAV_CMD    0x0A
#define MSG_TYPE_UAV_ACK    0x0B
#define MSG_TYPE_UAV_TELEM  0x0C   // PDL_MSG_TYPE_UAV_TELEM (drone-companion/SPEC.md 2.3)
// FIXED 2026-07-30: PAIR_REQ/PAIR_RSP were 0x0D/0x0E per drone-companion/
// SPEC.md, which collide with mesh_routing.h's MSG_TYPE_MESH_ROUTE/
// MSG_TYPE_MESH_ACK -- both PDL_ENABLE_UAV_RELAY and PDL_ENABLE_MESH_ROUTING
// are compiled into env:heltec_wifi_lora_v4_uav_bridge. Moved to 0x1E/0x1F;
// drone-companion's config.h and SPEC.md were updated to match -- these are
// two separate codebases implementing the same wire protocol and MUST agree.
#define MSG_TYPE_UAV_PAIR_REQ  0x1E
#define MSG_TYPE_UAV_PAIR_RSP  0x1F

#define UAV_CMD_FRAME_SIZE    32
#define UAV_ACK_FRAME_SIZE    16
#define UAV_TELEM_FRAME_SIZE  32

// ── STANAG 4586 short codes (mirrors worker + gateway) ──
#define UAV_MSG_LOI_REQUEST             0x10
#define UAV_MSG_LOI_TRANSFER_ACK        0x11
#define UAV_MSG_EMERGENCY_COMMAND       0x06
#define UAV_MSG_POSITION_LLA            0x20
#define UAV_MSG_ATTITUDE                0x21
#define UAV_MSG_VSM_DATALINK_ASSIGN     0x40
#define UAV_MSG_VEHICLE_STEERING_CMD    0x50
#define UAV_MSG_WAYPOINT_LOAD           0x51
#define UAV_MSG_WAYPOINT_EXECUTE        0x55

// Ack status codes (STANAG-inspired, compact)
enum class UavAckCode : uint8_t {
    OK            = 0,
    BAD_CRC       = 1,
    BAD_HMAC      = 2,
    UNKNOWN_TYPE  = 3,
    POLICY_BLOCK  = 4,
    RELAY_BUSY    = 5,
    NO_MODEM      = 6,
};

// Parsed UAV command packet (owned copy of body bytes)
struct UavCmdPacket {
    uint8_t  msg_code;                      // STANAG short code
    uint16_t sequence;
    uint8_t  vehicle_hash[8];               // SHA-1 truncated
    uint32_t issued_at_mod;
    uint8_t  body[13];
    uint8_t  hmac_trunc[4];
};

// ── Telemetry beacon (drone -> mesh, every ~30s) ──────────────────────
// Wire format matches drone-companion/src/telemetry.h exactly (32 bytes,
// CRC-16-CCITT/XMODEM over bytes[0..30), NOT HMAC-authenticated -- this
// is periodic status broadcast, not an actuation command, so it doesn't
// carry the same authenticity requirement as a STANAG command frame.
struct UavTelemetryBeacon {
    uint16_t sequence;
    uint8_t  vehicle_hash[8];
    uint32_t issued_at_mod;
    int32_t  lat_e7;
    int32_t  lon_e7;
    int16_t  alt_m;
    uint16_t battery_mv;
    uint8_t  battery_pct;
    uint8_t  flight_mode;    // FlightModeAgnostic
    uint8_t  armed_flags;    // bit0=armed, bit1=gps_lock, bit2=low_batt
};

enum class FlightModeAgnostic : uint8_t {
    UNKNOWN   = 0,
    MANUAL    = 1,
    STABILIZE = 2,
    ALTHOLD   = 3,
    GUIDED    = 4,
    AUTO      = 5,
    RTL       = 6,
    LAND      = 7,
    EMERGENCY = 8,
};

// ── Public API (always present; no-op when PDL_ENABLE_UAV_RELAY is off) ──

// Initialize UAV relay subsystem. FIXED 2026-07-30: now also loads any
// NVS-persisted HMAC root from a prior pairing (see uav_pairing.h) and
// opens the pairing window on cold boot if none is persisted yet -- this
// used to require an explicit hmac_key argument with no real caller ever
// providing one, meaning the allowlist stayed permanently empty. The
// hmac_key argument still works exactly as before for explicit/test
// injection and takes priority over whatever was loaded from NVS. Sets up
// UART pins for the drone modem link.
void uav_relay_init(const uint8_t* hmac_key_16, size_t hmac_key_len);

// Sets this sensor's own identity, used as the vehicle_hash in outgoing
// PAIR_RSP frames. Call once from main.cpp with enrollment_get_sensor_id()
// -- kept as an injected value rather than a direct enrollment.cpp
// dependency from this module, same convention command_handler.cpp uses
// for its own s_own_sensor_id.
void uav_relay_set_own_sensor_id(uint32_t sensor_id);

// Handle a received PAIR_REQ frame (MSG_TYPE_UAV_PAIR_REQ, 0x1E): runs it
// through uav_pairing_process_request(), and if that yields a response
// (parse succeeded, even if rejected as PAIR_MODE_REQUIRED), transmits the
// PAIR_RSP over the mesh and -- on a successful pairing -- immediately
// refreshes this module's own in-RAM HMAC key so subsequent commands
// verify correctly without requiring a reboot. This is what main.cpp's
// dispatch calls when it sees MSG_TYPE_UAV_PAIR_REQ.
void uav_relay_handle_pair_request(const uint8_t* data, size_t len);

// Parse a 32-byte LoRa frame into a UavCmdPacket. Returns true on success.
// Safe with any buffer; returns false if len != 32.
bool uav_relay_parse(const uint8_t* data, size_t len, UavCmdPacket& out);

// Full RX entrypoint: parse, verify, route to MAVLink, and transmit an
// ACK over LoRa (16-byte frame). This is what the main.cpp switch statement
// calls when it sees MSG_TYPE_UAV_CMD (0x0A).
void uav_relay_handle(const uint8_t* data, size_t len);

// Emit a UAV ACK (16 bytes) over LoRa. Public so other modules can signal
// policy-block results back to the gateway.
void uav_relay_send_ack(uint16_t sequence, UavAckCode code);

// ── Telemetry uplink: drone -> T1 -> mesh (T2/C2) ──────────────────────
// The software-only equivalent of a SiK telemetry radio's drone-to-ground
// status link, built entirely on the existing LoRa mesh -- no new
// hardware. T1 receives a drone-companion-equipped drone's periodic
// telemetry beacon (position/battery/mode/armed-status), CRC-validates
// it, and relays it verbatim onward over its own mesh-facing link so a
// T2 gateway (also a mesh peer) can pick it up and forward to C2. This is
// what main.cpp's dispatch calls when it sees MSG_TYPE_UAV_TELEM (0x0C).
void uav_relay_handle_telemetry(const uint8_t* data, size_t len);

// Parse a 32-byte telemetry beacon. Returns true + fills out on success
// (correct length, correct msg_type, valid CRC16). Public for unit tests
// and for callers that want the decoded fields rather than a raw relay.
bool uav_relay_parse_telemetry(const uint8_t* data, size_t len, UavTelemetryBeacon& out);

#endif // UAV_RELAY_H
