#pragma once

#include "message_protocol/MessageType.hpp"

#include <cstdint>
#include <cstring>
#include <optional>
#include <span>

namespace tw::msg {

/**
 * Fixed-size prefix carried by every message.
 *
 * `seq` correlates a reply with the request that produced it. SEQ_NONE marks a
 * message that expects no reply, which is the common case.
 */
struct MessageHeader {
    static constexpr uint32_t SEQ_NONE = 0;
    static constexpr size_t   SIZE     = sizeof(MessageType) + sizeof(uint32_t);

    MessageType type = 0;
    uint32_t    seq  = SEQ_NONE;

    /** Writes the header at the start of `target`, which must hold SIZE bytes. */
    void encode(std::span<std::byte> target) const {
        std::memcpy(target.data(), &type, sizeof(type));
        std::memcpy(target.data() + sizeof(type), &seq, sizeof(seq));
    }

    /** Reads a header from the start of `source`, or nothing if it is too short. */
    static std::optional<MessageHeader> decode(std::span<const std::byte> source) {
        if(source.size() < SIZE) {
            return {};
        }

        MessageHeader header;
        std::memcpy(&header.type, source.data(), sizeof(header.type));
        std::memcpy(&header.seq, source.data() + sizeof(header.type), sizeof(header.seq));

        return header;
    }
};

}
