#include "protocol/protocol.h"

#include <cstring>

namespace voicecat::protocol {

// --- FrameCodec::emit -------------------------------------------------------

void FrameCodec::emit(const uint8_t* payload, size_t len, std::vector<uint8_t>& out) {
    // Length header: big-endian u32.
    auto u32 = static_cast<uint32_t>(len);
    out.push_back(static_cast<uint8_t>((u32 >> 24) & 0xFF));
    out.push_back(static_cast<uint8_t>((u32 >> 16) & 0xFF));
    out.push_back(static_cast<uint8_t>((u32 >>  8) & 0xFF));
    out.push_back(static_cast<uint8_t>( u32         & 0xFF));
    out.insert(out.end(), payload, payload + len);
}

void FrameCodec::emit(const std::vector<uint8_t>& payload, std::vector<uint8_t>& out) {
    emit(payload.data(), payload.size(), out);
}

// --- FrameCodec::feed -------------------------------------------------------

bool FrameCodec::feed(const uint8_t* data, size_t len,
                      std::vector<std::vector<uint8_t>>& out_frames) {
    buf_.insert(buf_.end(), data, data + len);

    while (true) {
        if (buf_.size() < kLengthHeaderSize) {
            break;  // need more bytes for the header
        }

        // Decode big-endian u32 length.
        uint32_t frame_len =
            (static_cast<uint32_t>(buf_[0]) << 24) |
            (static_cast<uint32_t>(buf_[1]) << 16) |
            (static_cast<uint32_t>(buf_[2]) <<  8) |
             static_cast<uint32_t>(buf_[3]);

        if (frame_len > kMaxFrameBytes) {
            buf_.clear();
            return false;  // oversized frame — protocol error
        }

        size_t total = kLengthHeaderSize + static_cast<size_t>(frame_len);
        if (buf_.size() < total) {
            break;  // need more bytes for the body
        }

        // Extract the complete frame payload.
        out_frames.emplace_back(buf_.begin() + kLengthHeaderSize,
                                buf_.begin() + total);
        buf_.erase(buf_.begin(), buf_.begin() + total);
    }

    return true;
}

}  // namespace voicecat::protocol
