#pragma once

#include <cstdint>

#include <QMetaType>
#include <QString>

#include "core/models/PayloadRef.h"

namespace softbus::core::models
{

enum class BusDirection
{
    Unknown,
    Upstream,
    Downstream,
};

enum class ProtocolType : std::uint16_t
{
    UNKNOWN = 0,
    MODBUS_RTU,
    MODBUS_ASCII,
    MODBUS_TCP,
    CAN_RAW,
    CAN_OPEN,
    UDP_CUSTOM,
};

inline uint qHash(ProtocolType key, uint seed = 0) noexcept
{
    return ::qHash(static_cast<std::uint16_t>(key), seed);
}

union ProtocolHeader
{
    struct Can
    {
        std::uint32_t cobId{0};
        bool isExtended{false};
        bool isRtr{false};
        std::uint8_t padding[2]{0, 0};
    } can;

    struct Modbus
    {
        std::uint8_t slaveId{0};
        std::uint8_t functionCode{0};
        std::uint8_t padding[6]{0, 0, 0, 0, 0, 0};
    } modbus;

    struct Net
    {
        std::uint32_t srcIp{0};
        std::uint16_t srcPort{0};
        std::uint16_t padding{0};
    } net;

    std::uint64_t alignmentPadding{0};
};

struct RawBusMessage
{
    int deviceId{-1};                    // Device instance id, -1 means unbound.
    std::uint32_t endpointHash{0};       // Physical endpoint/channel hash.
    ProtocolType protocol{ProtocolType::UNKNOWN};
    std::uint32_t logicalAddress{0};     // Slave ID / node ID for protocol routing.
    std::uint64_t routingKey{0};         // Stable key for MetadataRegistry lookup.
    ProtocolHeader header{};             // Out-of-band protocol header metadata.
    std::int64_t timestampMs{0};         // UTC unix timestamp in milliseconds.
    QString traceId;

    softbus::core::models::PayloadRef payload;
    BusDirection direction{BusDirection::Unknown};
};

} // namespace softbus::core::models

Q_DECLARE_METATYPE(softbus::core::models::RawBusMessage)
