#pragma once
// frame_codec.hpp
// 跨平台 TCP 帧读写工具。
// 帧格式（与 Ubuntu 侧 proto_frame.hpp 完全一致）：
//   [4字节 LE uint32: msg_type][4字节 LE uint32: payload_len][payload_len字节: UTF-8 JSON]

#include <cstdint>
#include <string>
#include <stdexcept>

#ifdef _WIN32
#  include <winsock2.h>
#  include <ws2tcpip.h>
   using sock_t = SOCKET;
#  define SOCK_INVALID INVALID_SOCKET
#  define SOCK_CLOSE(s) closesocket(s)
#else
#  include <sys/types.h>
#  include <sys/socket.h>
#  include <netinet/in.h>
#  include <arpa/inet.h>
#  include <unistd.h>
   using sock_t = int;
#  define SOCK_INVALID (-1)
#  define SOCK_CLOSE(s) ::close(s)
#endif

namespace vaw  // vehicle_agent_windows
{

// ---------------------------------------------------------------------------
// 枚举：与 Python frame_codec.py / proto_frame.hpp MsgType 完全一致
// ---------------------------------------------------------------------------
enum class MsgType : uint32_t {
    // 底盘域
    CHASSIS_GET_READINESS_REQ    = 1,
    CHASSIS_GET_READINESS_RSP    = 2,
    CHASSIS_MOTION_PRIMITIVE_REQ = 3,
    CHASSIS_MOTION_PRIMITIVE_RSP = 4,
    CHASSIS_EMERGENCY_BRAKE_REQ  = 5,
    CHASSIS_EMERGENCY_BRAKE_RSP  = 6,
    // 运控域
    CONTROL_GET_READINESS_REQ    = 11,
    CONTROL_GET_READINESS_RSP    = 12,
    CONTROL_EVALUATION_REQ       = 13,
    CONTROL_EVALUATION_RSP       = 14,
};

// ---------------------------------------------------------------------------
// 内部：精确读取 n 字节，不足则抛出 std::runtime_error
// ---------------------------------------------------------------------------
inline void recv_exactly(sock_t s, char* buf, uint32_t n)
{
    uint32_t received = 0;
    while (received < n) {
        int r = static_cast<int>(::recv(s, buf + received, static_cast<int>(n - received), 0));
        if (r <= 0) {
            throw std::runtime_error("连接已关闭或读取错误");
        }
        received += static_cast<uint32_t>(r);
    }
}

// ---------------------------------------------------------------------------
// 读一帧：返回 (msg_type, payload)，payload 可为空字符串
// ---------------------------------------------------------------------------
inline void recv_frame(sock_t s, MsgType& msg_type, std::string& payload)
{
    // 读 8 字节帧头
    char header[8];
    recv_exactly(s, header, 8);

    // 小端 uint32 反序列化
    auto le32 = [](const char* p) -> uint32_t {
        return static_cast<uint32_t>(static_cast<uint8_t>(p[0]))
             | (static_cast<uint32_t>(static_cast<uint8_t>(p[1])) << 8)
             | (static_cast<uint32_t>(static_cast<uint8_t>(p[2])) << 16)
             | (static_cast<uint32_t>(static_cast<uint8_t>(p[3])) << 24);
    };

    uint32_t type_val    = le32(header);
    uint32_t payload_len = le32(header + 4);

    msg_type = static_cast<MsgType>(type_val);

    if (payload_len == 0) {
        payload.clear();
        return;
    }

    payload.resize(payload_len);
    recv_exactly(s, &payload[0], payload_len);
}

// ---------------------------------------------------------------------------
// 写一帧：payload 可为空字符串
// ---------------------------------------------------------------------------
inline void send_frame(sock_t s, MsgType msg_type, const std::string& payload)
{
    uint32_t type_val    = static_cast<uint32_t>(msg_type);
    uint32_t payload_len = static_cast<uint32_t>(payload.size());

    // 小端序列化
    auto put_le32 = [](char* p, uint32_t v) {
        p[0] = static_cast<char>(v & 0xFF);
        p[1] = static_cast<char>((v >> 8) & 0xFF);
        p[2] = static_cast<char>((v >> 16) & 0xFF);
        p[3] = static_cast<char>((v >> 24) & 0xFF);
    };

    char header[8];
    put_le32(header,     type_val);
    put_le32(header + 4, payload_len);

    // 发帧头
    ::send(s, header, 8, 0);
    // 发 payload
    if (payload_len > 0) {
        ::send(s, payload.data(), static_cast<int>(payload_len), 0);
    }
}

}  // namespace vaw
