#include "general_loadometer.h"

#include "general_loadometer_decoder.h"
#include "common/spdlog/logging.h"
#include "common/utils/str_util.h"
#include "mqtt/mqtt_cli.h"


namespace zsy
{
    GeneralLoadometer::GeneralLoadometer(const LoadometerConfig &config)
        : Loadometer(config, std::make_shared<GeneralLoadometerDecoder>()), serialPort(nullptr)
    {
        if (config.connect_type() == LoadometerConfig_ConnectType_SP && config.has_serial_port())
        {
            const auto &serialPortConfig = config.serial_port();
            serialPort = QSharedPointer<SerialPort>(new SerialPort(SerialPort::DCB{
                                                                       serialPortConfig.port_name(),
                                                                       serialPortConfig.baud_rate(),
                                                                       serialPortConfig.data_bits(),
                                                                       serialPortConfig.stop_bits(),
                                                                       serialPortConfig.parity(),
                                                                       serialPortConfig.flow_control()
                                                                   },
                                                                   [this](const QByteArray &buf)
                                                                   {
                                                                       const std::vector<uint8_t> vec(buf.begin(), buf.end());
                                                                       return process(vec);
                                                                   }));
            connect(serialPort.get(), &SerialPort::sperr, this, &GeneralLoadometer::onSperr);
        } else
        {
            LOGGER_WARN("地磅 {} 不可用，未指定串口配置", config.name());
        }
    }

    bool GeneralLoadometer::canUse() const
    {
        return serialPort != nullptr && serialPort->canUse();
    }

    uint32_t GeneralLoadometer::process(const std::vector<uint8_t> &buf)
    {
        std::tuple<bool, uint32_t, int32_t> tuple;
        try
        {
            tuple = decoder->decode(buf);
        } catch (std::exception &e)
        {
            LOGGER_ERROR("地磅数据解析失败：{}", e.what());
            tuple = std::make_tuple(false, 0, 0);
        } catch (...)
        {
            LOGGER_ERROR("地磅数据解析失败：未知异常");
            tuple = std::make_tuple(false, 0, 0);
        }
        const auto [succ, size, weight] = tuple;
        if (succ)updateWeight(weight);
        return size;
    }

    void GeneralLoadometer::onSperr()
    {
        if (config.connect_type() == LoadometerConfig_ConnectType_SP && config.has_serial_port())
        {
            const auto &serialPortConfig = config.serial_port();
            LOGGER_INFO("正在重新打开串口，串口号：{}", serialPortConfig.port_name());
            disconnect(serialPort.get(), &SerialPort::sperr, this, &GeneralLoadometer::onSperr);
            serialPort.reset();
            serialPort = nullptr;
            serialPort = QSharedPointer<SerialPort>(new SerialPort(SerialPort::DCB{
                                                                       serialPortConfig.port_name(),
                                                                       serialPortConfig.baud_rate(),
                                                                       serialPortConfig.data_bits(),
                                                                       serialPortConfig.stop_bits(),
                                                                       serialPortConfig.parity(),
                                                                       serialPortConfig.flow_control()
                                                                   },
                                                                   [this](const QByteArray &buf)
                                                                   {
                                                                       const std::vector<uint8_t> vec(buf.begin(), buf.end());
                                                                       return process(vec);
                                                                   }));
            connect(serialPort.get(), &SerialPort::sperr, this, &GeneralLoadometer::onSperr);
        } else
        {
            LOGGER_WARN("地磅 {} 不可用，未指定串口配置", config.name());
        }
    }
} // zsy