#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::message_bus::pipeline::PipelineContext& 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.stableKey.isEmpty() ? QString::number(rawContext.deviceId)
                                                                         : rawContext.stableKey)
                                    .arg(i);
                msg.timestamp = rawContext.timestamp.toMSecsSinceEpoch();
                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"), rawContext.endpoint);
                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.stableKey.isEmpty() ? QString::number(rawContext.deviceId)
                                                                    : rawContext.stableKey);
            msg.timestamp = rawContext.timestamp.toMSecsSinceEpoch();
            msg.value = static_cast<std::uint32_t>(req->quantity);
            msg.quality = softbus::core::models::DataQuality::GOOD;
            msg.attributes.insert(QStringLiteral("sourceEndpoint"), rawContext.endpoint);
            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"); }
    bool supports(const QString& protocolHint) const override
    {
        return isModbusRtuHint(protocolHint);
    }
    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

