#include "general_loadometer_decoder.h"

#include "common/spdlog/logging.h"
#include "common/utils/str_util.h"

namespace zsy
{
    std::tuple<bool, int32_t> GeneralLoadometerDecoder::resolve(const std::vector<uint8_t> &buf)
    {
        double weight = 0.0;

        uint8_t parityCode = buf[1];
        for (uint8_t i = 2; i < 9; i++)
        {
            parityCode ^= buf[i];
        }
        if (std::string{static_cast<char>(buf[9]), static_cast<char>(buf[10])} != StrUtil::toHex(parityCode))
        {
            const auto startPoint = buf.begin();
            const auto endPoint = startPoint + 12;
            LOGGER_WARN("地磅数据校验失败，已丢弃：{}", StrUtil::toHex(std::vector(startPoint, endPoint)));
            return std::make_tuple(false, 0);
        } else
        {
            double tempData = 0.0;
            for (uint8_t i = 2; i < 8; i++)
            {
                tempData += (buf[i] - '0') * std::pow<uint32_t>(10, 7 - i);
            }
            // 处理小数点
            weight = tempData / std::pow<uint32_t>(10, buf[8] - '0');
            // 负数
            if (buf[1] == '-')
            {
                weight = -weight;
            }
        }
        // LOGGER_DEBUG("解析到地磅数据：{}", weight);
        return std::make_tuple(true, static_cast<int32_t>(weight));
    }

    std::tuple<bool, uint32_t, int32_t> GeneralLoadometerDecoder::decode(const std::vector<uint8_t> &buf)
    {
        const auto length = buf.size();

        // 数据不足继续等待
        if (length < FrameLen)
        {
            // LOGGER_DEBUG("数据不足，等待更多数据1");
            return std::make_tuple(false, 0, 0);
        }

        // 移除错误数据
        if (constexpr auto stopByteOffset = FrameLen - 1; buf[0] != StartByte || buf[stopByteOffset] != StopByte)
        {
            for (uint32_t i = 0; i < length; i++)
            {
                if (i + stopByteOffset >= length)
                {
                    // LOGGER_DEBUG("数据不足，等待更多数据2");
                    break;
                }
                if (buf[i] == StartByte)
                {
                    if (buf[i + stopByteOffset] != StopByte)
                    {
                        continue;
                    }

                    // 已找到完整数据帧
                    const auto startPoint = buf.begin();
                    const auto endPoint = startPoint + i;
                    LOGGER_WARN("地磅数据格式错误，已丢弃：{}", StrUtil::toHex(std::vector(startPoint, endPoint)));

                    const auto [succ, weight] = resolve(std::vector(endPoint, endPoint + stopByteOffset));
                    return std::make_tuple(succ, i + FrameLen, weight);
                }
            }
            // 数据不足继续等待
            return std::make_tuple(false, 0, 0);
        }

        auto [succ, weight] = resolve(buf);
        return std::make_tuple(succ, FrameLen, weight);
    }
} // zsy