#ifndef RNODE_BRIDGE_H
#define RNODE_BRIDGE_H

// ============================================================================
// rnode_bridge.{h,cpp}
//
// Reticulum (RNS) RNode-compatible LoRa transport.  We implement just the
// L1 packet framing + KISS-over-LoRa headers required to hand inbound RNS
// packets up to a co-located T2 gateway running real RNS.  TX of true RNS
// announces and LXMF requires a full implementation that doesn't fit on
// device — so for v1 we expose:
//
//   * RX  — fully working: parse the on-air L1 frame, KISS-decode the
//           inner packet, hand it up to the PDL mesh wrapped as a
//           MSG_TYPE_INTEROP_RX.
//   * TX  — KISS frame builder + L1 header is implemented; rnode_announce()
//           and rnode_send_lxmf() compose the bytes correctly but emit a
//           runtime warning that announce/LXMF state is NOT maintained on
//           device — the destination_hash must be supplied by the operator
//           via NVS or command (the operator-side T2 typically tells the
//           sensor what hash to announce-relay on its behalf).
//
// PHY (RNode default):
//   * Frequency 915.000 MHz (slot offset configurable via NVS)
//   * BW 125 kHz, SF 7, CR 4/5, sync 0x14, no fixed preamble
//
// References:
//   github.com/markqvist/Reticulum  — RNS wire format
//   github.com/markqvist/RNode_Firmware — KISS framing
// ============================================================================

#include <cstdint>
#include <cstddef>

#define RNODE_NVS_NS         "pdl_rnode"
#define RNODE_NVS_ENABLED    "enabled"   // u8

// PHY
#define RNODE_FREQ_MHZ       915.000f
#define RNODE_BW_KHZ         125.0f
#define RNODE_SF             7
#define RNODE_CR             5
#define RNODE_SYNC           0x14
#define RNODE_PREAMBLE       8

// KISS framing constants (TNC2 standard)
#define KISS_FEND            0xC0
#define KISS_FESC            0xDB
#define KISS_TFEND           0xDC
#define KISS_TFESC           0xDD
#define KISS_CMD_DATA        0x00

// Reticulum L1 header — FIXED 2026-07-30, was 18 bytes and did not match
// real RNS wire format (confirmed by reading RNS.Packet.pack() in the
// actual `RNS` Python reference implementation, pip install rns): flags
// and hops are TWO separate bytes, and context comes AFTER destination_
// hash, not right after flags. The 18-byte version silently misread every
// inbound field by one position past the header_type byte (its "context"
// was really the real protocol's hops byte, and its payload offset ate
// the real context byte as the first payload byte) -- this had zero test
// coverage before test_rnode_bridge.cpp, so the bug was never caught:
//   [0]      flags            (1 byte)  see RNS.Packet.get_packed_flags()
//   [1]      hops             (1 byte)
//   [2..17]  destination_hash (16 bytes)
//   [18]     context          (1 byte)
//   [19..N]  payload
#define RNODE_L1_HEADER_LEN  19
#define RNODE_DEST_HASH_LEN  16

// Maximum on-air payload — RNode standard MTU is 500 bytes
#define RNODE_MAX_PACKET     500

// ---------------------------------------------------------------------------
// Lifecycle
// ---------------------------------------------------------------------------
bool rnode_init();

// Enable/disable the Reticulum path at runtime AND persist to NVS. Needed
// because rnode_init() latches the NVS value into a static at boot, so an
// NVS-only write leaves every rnode_* entry point still early-returning until
// the next reboot.
void rnode_set_enabled(bool enabled);

// True when the Reticulum path is active. NOTE: rnode_is_enabled() below is a
// DEAD DECLARATION with no definition anywhere in the tree — this is the real
// accessor, and it was previously defined in rnode_bridge.cpp without ever
// being declared here, so nothing outside that file could call it.
bool rnode_is_rn_enabled();
bool rnode_is_enabled();

// Send a REAL, wire-compatible RNS self-announce (see reticulum_identity.h)
// for this sensor's OWN destination (app_name.aspect1.aspect2...) -- FIXED
// 2026-07-30, replacing a v1 that required the operator to supply an
// arbitrary destination hash to "announce," which was never valid RNS
// usage (an announce proves the sender holds the private key for the
// destination being announced -- a node can only announce its own
// identity, never one it doesn't hold the key for). app_data may be
// nullptr/0. Returns false if not enabled, the announce doesn't fit, or
// the scheduler cannot arrange a TX window.
bool rnode_announce(const char* app_name, const char* const* aspects, int n_aspects,
                    const uint8_t* app_data, size_t app_data_len);

// Send an LXMF-shaped payload. Wraps in L1 header + KISS framing. Same
// caveats as rnode_announce.
bool rnode_send_lxmf(const char* dest_hash_hex,
                     const uint8_t* data, size_t len);

// Inbound packet handler: KISS-decode, L1-parse, forward up to PDL mesh
// as MSG_TYPE_INTEROP_RX.
int rnode_handle_packet(const uint8_t* buf, size_t len);

// Stats
struct RnodeStats {
    uint32_t tx_announces;
    uint32_t tx_lxmf;
    uint32_t tx_failures;
    uint32_t rx_packets;
    uint32_t rx_decode_failures;
};
void rnode_get_stats(RnodeStats* out);

// Pure, testable core of rnode_announce(): builds the real RNS announce
// (via rns_build_announce()) and KISS-encodes it, given caller-supplied
// randomness/timestamp instead of gathering them internally. Public so
// main.cpp/tests can call it without needing ARDUINO's esp_fill_random()/
// RTC. See rnode_announce() for the ARDUINO-only wrapper that gathers
// real randomness and calls this.
size_t rnode_build_announce_frame(const char* app_name, const char* const* aspects, int n_aspects,
                                  const uint8_t* app_data, size_t app_data_len,
                                  const uint8_t random_hash10[10],
                                  uint8_t* out, size_t out_len);

#ifdef UNIT_TEST
// Test helpers — independent of radio/NVS
extern "C" size_t rnode_test_kiss_encode(const uint8_t* in, size_t in_len,
                                         uint8_t* out, size_t out_len);
extern "C" size_t rnode_test_kiss_decode(const uint8_t* in, size_t in_len,
                                         uint8_t* out, size_t out_len);
extern "C" size_t rnode_test_build_l1(uint8_t flags, uint8_t hops,
                                      const uint8_t* dest_hash, uint8_t context,
                                      const uint8_t* payload, size_t plen,
                                      uint8_t* out, size_t out_len);
#endif

#endif // RNODE_BRIDGE_H
