#ifndef PAYLOAD_BUFFER_H
#define PAYLOAD_BUFFER_H

// ============================================================================
// payload_buffer.h — Multi-chunk LoRa→PSRAM payload staging
//
// Receives MSG_TYPE_PAYLOAD_CHUNK = 0x14 packets over LoRa, assembles them
// into contiguous PSRAM buffers, and exposes a query/release API for the
// delivery gate.
//
// Chunk wire format (24B header + up to 200B data):
//   [0]        = 0x14  (MSG_TYPE_PAYLOAD_CHUNK)
//   [1..4]     = payload_id   (LE uint32_t)
//   [5..6]     = total_chunks (LE uint16_t)
//   [7..8]     = chunk_idx    (LE uint16_t, 0-based)
//   [9..12]    = total_size   (LE uint32_t, bytes of complete payload)
//   [13..16]   = chunk_crc32  (LE uint32_t, CRC32/BZIP2 of this chunk data only)
//   [17..23]   = reserved (7 bytes)
//   [24..]     = chunk data (variable, up to 200 bytes)
//
// Constraints:
//   - Max 2 concurrent in-flight payloads.
//   - Max 256 KB per payload.
//   - Full-payload CRC32 is verified when all chunks arrive (XOR of
//     per-chunk CRC32s is NOT used — a second-pass CRC over the complete
//     buffer guards against reorder / duplicate chunk injection).
//   - PSRAM allocated via heap_caps_malloc(MALLOC_CAP_SPIRAM).
//
// See auth_gate.h for the Ed25519 delivery gate that controls payload release.
// ============================================================================

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

// Limits
#define PAYLOAD_CHUNK_HDR_LEN       24      // fixed header size
#define PAYLOAD_CHUNK_MAX_DATA      200     // max bytes of chunk data
#define PAYLOAD_CONCURRENT_MAX      2       // max simultaneously staged payloads
#define PAYLOAD_MAX_SIZE            (256 * 1024)  // 256 KB hard cap

// Status codes returned from payload_buffer_handle_chunk
typedef enum : uint8_t {
    PB_OK              = 0,  // chunk accepted
    PB_COMPLETE        = 1,  // this chunk completed the payload; CRC verified
    PB_BAD_HDR         = 2,  // packet too short or wrong msg type
    PB_FULL            = 3,  // max concurrent payloads reached
    PB_TOO_LARGE       = 4,  // total_size > PAYLOAD_MAX_SIZE
    PB_BAD_CHUNK_CRC   = 5,  // per-chunk CRC32 mismatch
    PB_BAD_FINAL_CRC   = 6,  // complete-payload CRC32 mismatch (payload dropped)
    PB_DUPLICATE       = 7,  // chunk_idx already received for this payload
    PB_ALLOC_FAIL      = 8,  // heap_caps_malloc failed (out of PSRAM)
} PayloadBufStatus;

// ---------------------------------------------------------------------------
// Initialise the payload buffer system. Safe to call multiple times (resets
// all slots and frees any lingering PSRAM allocations).
// ---------------------------------------------------------------------------
void payload_buffer_init();

// ---------------------------------------------------------------------------
// Feed a raw chunk packet (buf points to the full wire frame including the
// 0x14 byte at buf[0]).  Returns a PayloadBufStatus code.
// On PB_COMPLETE the assembled payload is retained in PSRAM and accessible
// via payload_buffer_get() until the caller calls payload_buffer_release().
// ---------------------------------------------------------------------------
PayloadBufStatus payload_buffer_handle_chunk(const uint8_t* buf, size_t len);

// ---------------------------------------------------------------------------
// Access the complete reassembled payload for payload_id.
// *data_out is set to a pointer into PSRAM (valid until release is called).
// *len_out  is set to total_size as reported by the sender.
// Returns false if the payload is unknown, still in-flight, or failed CRC.
// ---------------------------------------------------------------------------
bool payload_buffer_get(uint32_t payload_id,
                        const uint8_t** data_out,
                        size_t*         len_out);

// ---------------------------------------------------------------------------
// Release the PSRAM buffer for payload_id, freeing the slot for reuse.
// No-op if payload_id is unknown.
// ---------------------------------------------------------------------------
void payload_buffer_release(uint32_t payload_id);

#endif // PAYLOAD_BUFFER_H
