#include "plugins/protocols/modbus_rtu/mapper/ModbusRtuProtocolMapperPlugin.h"

#include "plugins/protocols/modbus_rtu/framer/ModbusRtuFraming.h"

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

namespace
{

class ModbusRtuMapperSession final : public softbus::core::plugin_system::IProtocolMapperSession
{
public:
    std::vector<softbus::core::models::DOMMessage> map(
        const softbus::core::models::RawBusMessage& rawContext,
        const softbus::message_bus::pipeline::protocol::ProtocolEnvelope& envelope) override
    {
        std::vector<softbus::core::models::DOMMessage> out;
        if (envelope.family != softbus::message_bus::pipeline::protocol::ProtocolFamily::ModbusRtu) {
            return out;
        }
        const auto* pdu = std::get_if<softbus::message_bus::pipeline::protocol::ModbusRtuPdu>(&envelope.pdu);
        if (!pdu) {
            return out;
        }

        if (const auto* resp =
                std::get_if<softbus::message_bus::pipeline::protocol::ReadHoldingRegistersResponse>(pdu)) {
            out.reserve(static_cast<std::size_t>(resp->registers.size()));
            for (int i = 0; i < resp->registers.size(); ++i) {
                softbus::core::models::DOMMessage msg;
                msg.messageId = QStringLiteral("%1.reg.%2")
                                    .arg(rawContext.routingKey == 0
                                             ? QString::number(rawContext.deviceId)
                                             : QString::number(rawContext.routingKey))
                                    .arg(i);
                msg.timestamp = rawContext.timestampMs;
                msg.value = static_cast<std::uint32_t>(resp->registers[static_cast<qsizetype>(i)]);
                msg.quality = softbus::core::models::DataQuality::GOOD;
                msg.attributes.insert(QStringLiteral("sourceEndpoint"), QString::number(rawContext.endpointHash));
                out.push_back(std::move(msg));
            }
            return out;
        }

        if (const auto* req =
                std::get_if<softbus::message_bus::pipeline::protocol::ReadHoldingRegistersRequest>(pdu)) {
            softbus::core::models::DOMMessage msg;
            msg.messageId = QStringLiteral("%1.req.read_holding")
                                .arg(rawContext.routingKey == 0
                                         ? QString::number(rawContext.deviceId)
                                         : QString::number(rawContext.routingKey));
            msg.timestamp = rawContext.timestampMs;
            msg.value = static_cast<std::uint32_t>(req->quantity);
            msg.quality = softbus::core::models::DataQuality::GOOD;
            msg.attributes.insert(QStringLiteral("sourceEndpoint"), QString::number(rawContext.endpointHash));
            msg.attributes.insert(QStringLiteral("frameType"), QStringLiteral("request"));
            msg.attributes.insert(QStringLiteral("startAddress"), static_cast<int>(req->startAddress));
            msg.attributes.insert(QStringLiteral("quantity"), static_cast<int>(req->quantity));
            out.push_back(std::move(msg));
        }
        return out;
    }

    void reset() override {}
};

class ModbusRtuProtocolMapperPlugin final : public softbus::core::plugin_system::IProtocolMapperPlugin
{
public:
    QString pluginId() const override { return QStringLiteral("modbus_rtu_mapper"); }
    softbus::core::models::ProtocolType protocolType() const override
    {
        return softbus::core::models::ProtocolType::MODBUS_RTU;
    }
    std::unique_ptr<softbus::core::plugin_system::IProtocolMapperSession> createMapperSession() override
    {
        return std::make_unique<ModbusRtuMapperSession>();
    }
};

} // namespace

std::shared_ptr<softbus::core::plugin_system::IProtocolMapperPlugin> makeModbusRtuProtocolMapperPlugin()
{
    return std::make_shared<ModbusRtuProtocolMapperPlugin>();
}

softbus::core::plugin_system::IProtocolMapperPlugin* createModbusRtuProtocolMapperPluginRaw()
{
    return new ModbusRtuProtocolMapperPlugin();
}

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

