#pragma once
// 定义ModbusRTU PDU 类型 包括
// 异常响应、
// 读保持寄存器请求、
// 读保持寄存器响应、不支持的PDU
#include <cstdint>

#include <QChar>
#include <QString>
#include <QStringList>
#include <QVector>
#include <type_traits>
#include <variant>  // 用于定义variant类型 variant类型可以存储多种类型的数据

namespace softbus::message_bus::pipeline::protocol
{

struct ModbusExceptionPdu
{
    std::uint8_t unitId{0};
    std::uint8_t function{0};
    std::uint8_t exceptionCode{0};
};
// 01 功能码 读线圈 
struct ReadCoilsRequest
{
    std::uint8_t unitId{0};
    std::uint16_t startAddress{0};
    std::uint16_t quantity{0};
};
// 01 功能码 读线圈响应
struct ReadCoilsResponse
{
    std::uint8_t unitId{0};
    QVector<std::uint8_t> coils;
};

// 02 功能码 读离散输入
struct ReadDiscreteInputsRequest
{
    std::uint8_t unitId{0};
    std::uint16_t startAddress{0};
    std::uint16_t quantity{0};
};
// 02 功能码 读离散输入响应
struct ReadDiscreteInputsResponse
{
    std::uint8_t unitId{0};
    QVector<std::uint8_t> discreteInputs;
};

// 03 功能码 读保持寄存器
struct ReadHoldingRegistersRequest
{
    std::uint8_t  unitId{0};
    std::uint16_t startAddress{0};
    std::uint16_t quantity{0};
};

// 03 功能码 读保持寄存器响应
struct ReadHoldingRegistersResponse
{
    std::uint8_t             unitId{0};
    QVector<std::uint16_t> registers;
};

// 04 功能码 读输入寄存器
struct ReadInputRegistersRequest
{
    std::uint8_t unitId{0};
    std::uint16_t startAddress{0};
    std::uint16_t quantity{0};
};
// 04 功能码 读输入寄存器响应
struct ReadInputRegistersResponse
{
    std::uint8_t unitId{0};
    QVector<std::uint16_t> inputRegisters;
};

// 05 功能码 写单个线圈
struct WriteSingleCoilRequest
{
    std::uint8_t unitId{0};
    std::uint16_t address{0};
    std::uint8_t value{0};
};
// 05 功能码 写单个线圈响应
struct WriteSingleCoilResponse
{
    std::uint8_t unitId{0};
    std::uint16_t address{0};
    std::uint8_t value{0};
};      
// 06 功能码 写单个寄存器
struct WriteSingleRegisterRequest
{
    std::uint8_t unitId{0};
    std::uint16_t address{0};
    std::uint16_t value{0};
};
// 06 功能码 写单个寄存器响应
struct WriteSingleRegisterResponse
{
    std::uint8_t unitId{0};
    std::uint16_t address{0};
    std::uint16_t value{0};
};
// 15 功能码 写多个线圈
struct WriteMultipleCoilsRequest
{
    std::uint8_t unitId{0};
    std::uint16_t startAddress{0};
    std::uint16_t quantity{0};
    QVector<std::uint8_t> values;
};
// 15 功能码 写多个线圈响应
struct WriteMultipleCoilsResponse
{
    std::uint8_t unitId{0};
    std::uint16_t startAddress{0};
    std::uint16_t quantity{0};
    QVector<std::uint8_t> values;
};

// 16 功能码 写多个寄存器
struct WriteMultipleRegistersRequest
{
    std::uint8_t unitId{0};
    std::uint16_t startAddress{0};
    std::uint16_t quantity{0};
    QVector<std::uint16_t> values;
};
// 16 功能码 写多个寄存器响应
struct WriteMultipleRegistersResponse
{
    std::uint8_t unitId{0};
    std::uint16_t startAddress{0};
    std::uint16_t quantity{0};
    QVector<std::uint16_t> values;
};

struct ModbusRtuUnsupportedPdu
{
    std::uint8_t unitId{0};
    std::uint8_t functionCode{0};
};

using ModbusRtuPdu = std::variant<ModbusExceptionPdu,
                                  ReadCoilsRequest,
                                  ReadCoilsResponse,
                                  ReadDiscreteInputsRequest,
                                  ReadDiscreteInputsResponse,
                                  ReadHoldingRegistersRequest,
                                  ReadHoldingRegistersResponse,
                                  ReadInputRegistersRequest,
                                  ReadInputRegistersResponse,
                                  WriteSingleCoilRequest,
                                  WriteSingleCoilResponse,
                                  WriteSingleRegisterRequest,
                                  WriteSingleRegisterResponse,
                                  WriteMultipleCoilsRequest,
                                  WriteMultipleCoilsResponse,
                                  WriteMultipleRegistersRequest,
                                  WriteMultipleRegistersResponse,
                                  ModbusRtuUnsupportedPdu>;
//

inline QString toText(const ModbusRtuPdu& pdu)
{
    return std::visit([](const auto& value) -> QString {
        using T = std::decay_t<decltype(value)>;

        auto bytesToHex = [](const QVector<std::uint8_t>& bytes) -> QString {
            QStringList parts;
            parts.reserve(bytes.size());
            for (const std::uint8_t b : bytes) {
                parts.push_back(QStringLiteral("0x%1").arg(b, 2, 16, QChar('0')));
            }
            return QStringLiteral("[%1]").arg(parts.join(QStringLiteral(", ")));
        };
        auto wordsToHex = [](const QVector<std::uint16_t>& words) -> QString {
            QStringList parts;
            parts.reserve(words.size());
            for (const std::uint16_t w : words) {
                parts.push_back(QStringLiteral("0x%1").arg(w, 4, 16, QChar('0')));
            }
            return QStringLiteral("[%1]").arg(parts.join(QStringLiteral(", ")));
        };

        if constexpr (std::is_same_v<T, ModbusExceptionPdu>) {
            return QStringLiteral("ModbusExceptionPdu: unitId=%1, function=0x%2, exceptionCode=0x%3")
                .arg(value.unitId)
                .arg(value.function, 2, 16, QChar('0'))
                .arg(value.exceptionCode, 2, 16, QChar('0'));
        }
        if constexpr (std::is_same_v<T, ReadCoilsRequest>) {
            const ReadCoilsRequest& request = value;
            return QStringLiteral("ReadCoilsRequest: unitId=%1, startAddress=%2, quantity=%3")
                .arg(request.unitId)
                .arg(request.startAddress)
                .arg(request.quantity);
        }
        if constexpr (std::is_same_v<T, ReadCoilsResponse>) {
            return QStringLiteral("ReadCoilsResponse: unitId=%1, coils=%2")
                .arg(value.unitId)
                .arg(bytesToHex(value.coils));
        }
        if constexpr (std::is_same_v<T, ReadDiscreteInputsRequest>) {
            return QStringLiteral("ReadDiscreteInputsRequest: unitId=%1, startAddress=%2, quantity=%3")
                .arg(value.unitId)
                .arg(value.startAddress)
                .arg(value.quantity);
        }
        if constexpr (std::is_same_v<T, ReadDiscreteInputsResponse>) {
            return QStringLiteral("ReadDiscreteInputsResponse: unitId=%1, discreteInputs=%2")
                .arg(value.unitId)
                .arg(bytesToHex(value.discreteInputs));
        }
        if constexpr (std::is_same_v<T, ReadHoldingRegistersRequest>) {
            return QStringLiteral("ReadHoldingRegistersRequest: unitId=%1, startAddress=%2, quantity=%3")
                .arg(value.unitId)
                .arg(value.startAddress)
                .arg(value.quantity);
        }
        if constexpr (std::is_same_v<T, ReadHoldingRegistersResponse>) {
            return QStringLiteral("ReadHoldingRegistersResponse: unitId=%1, registers=%2")
                .arg(value.unitId)
                .arg(wordsToHex(value.registers));
        }
        if constexpr (std::is_same_v<T, ReadInputRegistersRequest>) {
            return QStringLiteral("ReadInputRegistersRequest: unitId=%1, startAddress=%2, quantity=%3")
                .arg(value.unitId)
                .arg(value.startAddress)
                .arg(value.quantity);
        }
        if constexpr (std::is_same_v<T, ReadInputRegistersResponse>) {
            return QStringLiteral("ReadInputRegistersResponse: unitId=%1, inputRegisters=%2")
                .arg(value.unitId)
                .arg(wordsToHex(value.inputRegisters));
        }
        if constexpr (std::is_same_v<T, WriteSingleCoilRequest>) {
            return QStringLiteral("WriteSingleCoilRequest: unitId=%1, address=%2, value=0x%3")
                .arg(value.unitId)
                .arg(value.address)
                .arg(value.value, 2, 16, QChar('0'));
        }
        if constexpr (std::is_same_v<T, WriteSingleCoilResponse>) {
            return QStringLiteral("WriteSingleCoilResponse: unitId=%1, address=%2, value=0x%3")
                .arg(value.unitId)
                .arg(value.address)
                .arg(value.value, 2, 16, QChar('0'));
        }
        if constexpr (std::is_same_v<T, WriteSingleRegisterRequest>) {
            return QStringLiteral("WriteSingleRegisterRequest: unitId=%1, address=%2, value=0x%3")
                .arg(value.unitId)
                .arg(value.address)
                .arg(value.value, 4, 16, QChar('0'));
        }
        if constexpr (std::is_same_v<T, WriteSingleRegisterResponse>) {
            return QStringLiteral("WriteSingleRegisterResponse: unitId=%1, address=%2, value=0x%3")
                .arg(value.unitId)
                .arg(value.address)
                .arg(value.value, 4, 16, QChar('0'));
        }
        if constexpr (std::is_same_v<T, WriteMultipleCoilsRequest>) {
            return QStringLiteral("WriteMultipleCoilsRequest: unitId=%1, startAddress=%2, quantity=%3, values=%4")
                .arg(value.unitId)
                .arg(value.startAddress)
                .arg(value.quantity)
                .arg(bytesToHex(value.values));
        }
        if constexpr (std::is_same_v<T, WriteMultipleCoilsResponse>) {
            return QStringLiteral("WriteMultipleCoilsResponse: unitId=%1, startAddress=%2, quantity=%3, values=%4")
                .arg(value.unitId)
                .arg(value.startAddress)
                .arg(value.quantity)
                .arg(bytesToHex(value.values));
        }
        if constexpr (std::is_same_v<T, WriteMultipleRegistersRequest>) {
            return QStringLiteral("WriteMultipleRegistersRequest: unitId=%1, startAddress=%2, quantity=%3, values=%4")
                .arg(value.unitId)
                .arg(value.startAddress)
                .arg(value.quantity)
                .arg(wordsToHex(value.values));
        }
        if constexpr (std::is_same_v<T, WriteMultipleRegistersResponse>) {
            return QStringLiteral("WriteMultipleRegistersResponse: unitId=%1, startAddress=%2, quantity=%3, values=%4")
                .arg(value.unitId)
                .arg(value.startAddress)
                .arg(value.quantity)
                .arg(wordsToHex(value.values));
        }
        if constexpr (std::is_same_v<T, ModbusRtuUnsupportedPdu>) {
            return QStringLiteral("ModbusRtuUnsupportedPdu: unitId=%1, functionCode=0x%2")
                .arg(value.unitId)
                .arg(value.functionCode, 2, 16, QChar('0'));
        }
        return QStringLiteral("Unknown");
    }, pdu);
}

} // namespace softbus::message_bus::pipeline::protocol

