#include "ytj_vidicon.h"

namespace zsy
{
    YtjVidicon::YtjVidicon(std::string devSn, uint32_t timeout, uint32_t enableRecognize, std::shared_ptr<MQTTCli> mqttCli)
        : timeout(timeout), mqttCli(mqttCli), devSn(devSn)
    {
        if (enableRecognize)
        {
            mqttCli->subscribe("device/" + devSn + "/message/up/ivs_result", [this, devSn](const MQTTMsg &msg)
            {
                LOCK_BIZ(this->devSn)
                {
                    LOGGER_INFO("收到车牌识别结果：{}", msg.payload);
                    const auto [succ, id, licensePlate, image] = parseRecognizeResult(msg.payload);
                    Q_EMIT recognizeComplete(succ, id, licensePlate, image);
                }
                else
                {
                    LOGGER_WARN("重复识别，道闸：{}", devSn);
                }
            });
        }
        mqttCli->subscribe("device/" + devSn + "/message/up/snapshot", [this](const MQTTMsg &msg)
        {
            snapshot(msg);
        });
        mqttCli->subscribe("device/" + devSn + "/message/down/snapshot/reply", [this](const MQTTMsg &msg)
        {
            snapshotReply(msg);
        });
    }

    void YtjVidicon::snapshot(const MQTTMsg &msg)
    {
        const auto snapshotMsgOpt = JSON::parse<SnapshotResultMsg>(msg.payload);
        if (!snapshotMsgOpt)
        {
            LOGGER_ERROR("摄像机：{}，错误的消息格式：{}", devSn, msg.payload);
            return;
        }
        if (const auto &snapshot_msg = snapshotMsgOpt.value(); snapshot_msg.payload.state_code == 200)
        {
            LOGGER_INFO("摄像机：{}，道闸拍照成功", devSn);
            updatePhotoInfo(SnapshotStatus::Success, snapshot_msg.payload.image_content, snapshot_msg.payload.imageformat);
        } else
        {
            LOGGER_ERROR("摄像机：{}，道闸拍照失败，消息内容：{}", devSn, msg.payload);
            updatePhotoInfo(SnapshotStatus::Failed, snapshot_msg.payload.image_content, snapshot_msg.payload.imageformat);
        }
        photoInfoChangeCV.notify_one();
    }

    void YtjVidicon::snapshotReply(const MQTTMsg &msg)
    {
        LOGGER_INFO("收到道闸拍照消息回执：{}", msg.payload);
        const auto replyMsgOpt = JSON::parse<SnapshotReplyMsg>(msg.payload);
        if (!replyMsgOpt)
        {
            LOGGER_ERROR("摄像机：{}，错误的消息格式：{}", devSn, msg.payload);
            return;
        }
        if (replyMsgOpt.value().code == 200)
        {
            LOGGER_INFO("摄像机：{}，道闸拍照成功", devSn);
        } else
        {
            LOGGER_ERROR("摄像机：{}，道闸拍照失败，消息内容：{}", devSn, msg.payload);
        }
    }

    void YtjVidicon::updatePhotoInfo(SnapshotStatus status, const std::string &content, const std::string &format)
    {
        std::lock_guard lock(photoInfo_mtx);
        if (photoInfo.status != SnapshotStatus::Pending)
        {
            LOGGER_INFO("摄像机：{}，缓存已过期，无法更新", devSn);
            return;
        }
        photoInfo.status = status;
        photoInfo.imageformat = format;
        photoInfo.image_content = content;
    }

    std::string YtjVidicon::photograph()
    {
        LOCK_BIZ(devSn)
        {
            SnapshotRequestMsg msg{
                .sn = devSn
            };
            try
            {
                auto topic = "device/" + devSn + "/message/down/snapshot";
                auto data = JSON::toJsonStr(msg);

                LOGGER_INFO("摄像机：{}，正在拍照，{} {}", devSn, topic, data);
                std::unique_lock lock(photoInfo_mtx);
                photoInfo.status = SnapshotStatus::Pending;
                mqttCli->publish(topic, data);
                auto wait_for_succ = photoInfoChangeCV.wait_for(lock, std::chrono::seconds(timeout), [this, &msg]
                {
                    return photoInfo.status != SnapshotStatus::Pending;
                });
                if (!wait_for_succ)
                {
                    photoInfo.status = SnapshotStatus::Canceled;
                    LOGGER_INFO("摄像机：{}，等待照片超时", devSn);
                    return {};
                }
                if (photoInfo.status != SnapshotStatus::Success)
                {
                    LOGGER_ERROR("摄像机：{}，拍照失败", devSn);
                    return {};
                }
                return photoInfo.image_content;
            } catch (const std::exception &e)
            {
                LOGGER_INFO("拍照失败:{}", e.what());
            } catch (...)
            {
                LOGGER_ERROR("未知异常，拍照失败");
            }
            return {};
        }
        else
        {
            LOGGER_ERROR("摄像机：{}，正在拍照，无法使用", devSn);
            return {};
        }
    }

    std::tuple<bool, std::string, std::string, std::string> YtjVidicon::parseRecognizeResult(const std::string &jsonStr)
    {
        const auto resOpt = JSON::parse<RecognizeResultWrapper>(jsonStr);
        if (!resOpt)return std::make_tuple(false, "", "", "");
        const auto &recognize_result_wrapper = resOpt.value();
        auto id = recognize_result_wrapper.id;
        auto alarmInfoPlate = recognize_result_wrapper.payload.alarmInfoPlate;
        auto serialno = alarmInfoPlate.serialno;
        auto imageFile = alarmInfoPlate.result.plateResult.imageFile;
        auto license = alarmInfoPlate.result.plateResult.license;
        if (serialno.empty()
            || imageFile.empty()
            || license.empty()
            || license.find("无") != std::string::npos
        )
        {
            LOGGER_ERROR("车牌识别结果解析失败或车牌为：“无”");
            return std::make_tuple(false, "", "", "");
        }

        return std::make_tuple(true, id, license, imageFile);
    }
} // zsy