// ============================================================================
// interop_router.cpp
// ============================================================================

#include "interop_router.h"
#include "radio_scheduler.h"
#include "config.h"

#include <cstring>

#ifdef ARDUINO
#include <Arduino.h>
#include "mesh_publish.h"
#include "meshtastic_emit.h"
#include "rnode_bridge.h"
#endif

#define IR_QUEUE_DEPTH   8
#define IR_MAX_PACKET    256

struct IrEntry {
    uint8_t bytes[IR_MAX_PACKET];
    size_t  len;
    bool    valid;
};

static IrEntry s_queue[IR_QUEUE_DEPTH];
static size_t  s_head = 0;
static size_t  s_tail = 0;
static InteropStats s_ir_stats;

void interop_router_init() {
    memset(s_queue, 0, sizeof(s_queue));
    memset(&s_ir_stats, 0, sizeof(s_ir_stats));
    s_head = s_tail = 0;
}

static bool queue_empty() { return s_head == s_tail; }
static bool queue_full() {
    return ((s_tail + 1) % IR_QUEUE_DEPTH) == s_head;
}

void interop_router_enqueue_pdl(const uint8_t* pkt, size_t len) {
    if (!pkt || len == 0 || len > IR_MAX_PACKET) return;
    if (queue_full()) {
        s_ir_stats.enq_dropped_full++;
        return;
    }
    memcpy(s_queue[s_tail].bytes, pkt, len);
    s_queue[s_tail].len = len;
    s_queue[s_tail].valid = true;
    s_tail = (s_tail + 1) % IR_QUEUE_DEPTH;
    s_ir_stats.enq_total++;
}

void interop_router_tick() {
    if (queue_empty()) return;
    if (radio_sched_current_mode() != RADIO_MODE_PDL) return;

    // Drain at most 2 packets per tick to avoid hogging the PDL window
    int budget = 2;
    while (!queue_empty() && budget-- > 0) {
        IrEntry& e = s_queue[s_head];
        if (e.valid) {
#ifdef ARDUINO
            if (mesh_publish_raw(e.bytes, e.len)) {
                s_ir_stats.flushed_to_pdl++;
            }
#else
            s_ir_stats.flushed_to_pdl++;
#endif
            e.valid = false;
        }
        s_head = (s_head + 1) % IR_QUEUE_DEPTH;
    }
}

bool interop_router_dispatch_tx(const uint8_t* pkt, size_t len) {
    if (!pkt || len < 2) { s_ir_stats.tx_dropped++; return false; }

    uint8_t proto = pkt[0];

    if (proto == INTEROP_PROTO_MESHTASTIC) {
#ifdef ARDUINO
        // Treat remainder as a NUL-terminated text msg
        char buf[200];
        size_t copy_len = (len - 1) < sizeof(buf) - 1 ? (len - 1) : sizeof(buf) - 1;
        memcpy(buf, pkt + 1, copy_len);
        buf[copy_len] = 0;
        bool ok = meshtastic_emit_text(buf);
        if (ok) s_ir_stats.tx_dispatched++; else s_ir_stats.tx_dropped++;
        return ok;
#else
        s_ir_stats.tx_dispatched++;
        return true;
#endif
    }

    if (proto == INTEROP_PROTO_RNODE) {
        if (len < 1 + 32 + 1) { s_ir_stats.tx_dropped++; return false; }
#ifdef ARDUINO
        char hex[33];
        memcpy(hex, pkt + 1, 32);
        hex[32] = 0;
        uint8_t plen = pkt[33];
        if (1 + 32 + 1 + plen > len) { s_ir_stats.tx_dropped++; return false; }
        bool ok = rnode_send_lxmf(hex, pkt + 34, plen);
        if (ok) s_ir_stats.tx_dispatched++; else s_ir_stats.tx_dropped++;
        return ok;
#else
        s_ir_stats.tx_dispatched++;
        return true;
#endif
    }

    s_ir_stats.tx_dropped++;
    return false;
}

void interop_router_get_stats(InteropStats* out) {
    if (out) *out = s_ir_stats;
}

#ifdef UNIT_TEST
extern "C" int interop_router_test_proto_select(uint8_t first_byte) {
    if (first_byte == INTEROP_PROTO_MESHTASTIC) return 1;
    if (first_byte == INTEROP_PROTO_RNODE)      return 2;
    return -1;
}
#endif
