#include "ch32v30x_rtc.h"
#include "meshcore/meshframing.h"
#include "meshcore/packetstructs.h"
#include "group.h"
#include "lib/config.h"
#include "util/hexdump.h"
#include "util/log.h"
#include "string.h"

#define TAG "GroupMessage"

void sendGroupMessage (const GroupTextMessage *msg) {
    // Prepare values locally instead of modifying msg
    Channel *channel = &(persistent.channels[msg->keyIndex]);
    uint8_t flags = 0;
    int32_t timestamp = RTC_GetCounter();

    FrameStruct frame;
    frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_GRP_TXT | PAYLOAD_VERSION_0;
    frame.path.pathLen = 0;
    size_t offset = 0;
    frame.payload[offset++] = channel->hash;

    // Build encryption buffer directly on stack (no extra large buffer)
    uint8_t buf[180];  // enough for timestamp + flags + text
    size_t buf_offset = 0;

    memcpy (buf + buf_offset, &timestamp, sizeof (timestamp));
    buf_offset += sizeof (timestamp);

    buf[buf_offset++] = flags;

    size_t textLen = strlen ((const char *)msg->text);
    if (buf_offset + textLen > sizeof (buf)) {
        textLen = sizeof (buf) - buf_offset;
    }
    memcpy (buf + buf_offset, msg->text, textLen);
    buf_offset += textLen;

    hexdump ("TxDumpDec", buf, buf_offset);

    // Encrypt and MAC directly into frame payload after channelHash
    size_t olen = 0;

    encrypt_then_mac (channel->key, 16, buf, buf_offset, &frame.payload[offset], &olen);

    frame.payloadLen = olen + 1;  // +1 for channelHash

    channel->timestamp = timestamp;

    LoRaTransmit (&frame);
}

void makeSendGroupMessage (char *txt, uint8_t keyIndex) {
    GroupTextMessage msg;
    strcpy ((char *)msg.text, persistent.nodeName);
    strcat ((char *)msg.text, ": ");
    strcat ((char *)msg.text, txt);
    msg.keyIndex = keyIndex;
    sendGroupMessage (&msg);
    return;
}

void decodeGroupMessage (const FrameStruct *frame) {
    GroupTextMessage msg;
    memset (&msg, 0, sizeof (msg));
    if ((frame->header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
        MESH_LOGW (TAG, "Not a group text");
        return;
    }
    unsigned char index = 0;
    msg.channelHash = frame->payload[index++];
    unsigned char tmp[184];


    Channel *channel = NULL;

    uint8_t i = 0;
    do {
        channel = getChannel (msg.channelHash, i);
        if (channel == NULL) {
            MESH_LOGW (TAG, "Channel hash %d not found", msg.channelHash);
            return;
        }
        if (mac_then_decrypt (channel->key, 16, frame->payload + index, frame->payloadLen - index, tmp) != 0) {
            MESH_LOGW (TAG, "HMAC failed on grouphash key %d", msg.channelHash);
            i++;
            continue;
        } else {
            unsigned char plaintextLen = frame->payloadLen - index;
            index = 0;

            memcpy (&msg.timestamp, tmp + index, 4);
            index += 4;
            msg.flags = tmp[index++];

            memcpy (msg.text, tmp + index, plaintextLen - index);

            channel->timestamp = RTC_GetCounter();

            iprintf ("Message from channel %s: %s\n", channel->name, msg.text);
            break;
        }


    } while (channel != NULL);
}