#include "barrier_vidicon.h"
#include "application.h"
#include "common/date_util.h"
#include "nlohmann/json.hpp"
#include "common/sys_util.h"
#include "common/snowflake.h"


namespace zsy
{
    void BarrierVidicon::saveImageToFile(const std::string &decodedImageData, const std::string &filePath)
    {
        try
        {
            // 以二进制写入模式打开文件
            std::ofstream file(filePath, std::ios::binary | std::ios::trunc);

            // 检查文件是否成功打开
            if (!file.is_open())
            {
                throw std::system_error(errno, std::generic_category(), "无法打开文件");
            }

            // 写入解码后的图像数据
            file.write(decodedImageData.data(), decodedImageData.size());

            // 检查写入是否成功
            if (!file.good())
            {
                throw std::system_error(errno, std::generic_category(), "写入文件失败");
            }
        } catch (const std::exception &e)
        {
            LOGGER_ERROR("图片保存失败");
        } catch (...)
        {
            LOGGER_ERROR("未知异常，图片保存失败");
        }
    }

    BarrierVidicon::~BarrierVidicon()
    {
    }

    BarrierVidicon::BarrierVidicon(const VidiconProperties &config)
        : config(config)
          , hasNewContent(false)
    {
        // SysUtil::createDirs(SysUtil::HOME_DIR + "\\temp");
        Application::eventManager->subscribe(MqttCli::TYPE_LOCAL + "/device/" + config.ip + "/message/up/snapshot", [this](const EventManager::Event &event)
        {
            if (!event.data.has_value())
            {
                LOGGER_ERROR("错误的消息格式");
                return;
            }
            auto jsonData = event.data.value();

            LOGGER_INFO("收到道闸拍照结果：{}", jsonData.dump());
            const auto res = jsonData.get<PhotographResult>();

            imageContent = res.payload.image_content;
            hasNewContent.store(true, std::memory_order_release);
        });
        Application::eventManager->subscribe(MqttCli::TYPE_LOCAL + "/device/" + config.ip + "/message/down/snapshot/reply", [this](const EventManager::Event &event)
        {
            if (!event.data.has_value())
            {
                LOGGER_ERROR("错误的消息格式");
                return;
            }
            auto jsonData = event.data.value();

            LOGGER_INFO("收到道闸拍照消息回执：{}", jsonData.dump());
        });
    }

    std::shared_ptr<std::istream> BarrierVidicon::photograph()
    {
        try
        {
            LOGGER_INFO("摄像机正在拍照，设备名称：{}", config.name);
            const long timestamp = static_cast<long>(DateUtil::timestamp() / 1000);
            nlohmann::json j{
                {"id", "photograph" + std::to_string(timestamp)},
                {"sn", config.ip},
                {"name", "snapshot"},
                {"version", "1.0"},
                {"timestamp", timestamp},
                {
                    "payload", {
                        {"type", "snapshot"},
                        {"body", nlohmann::json::object()},
                    }
                }
            };
            auto topic = "device/" + config.ip + "/message/down/snapshot";
            auto data = j.dump();

            LOGGER_INFO("拍照：{} {}", topic, data);

            try
            {
                auto cli = Application::mqttCliHolder->localCli();
                if (cli)
                {
                    hasNewContent.store(false);
                    imageContent = "";
                    cli->publish(topic, data, 0);
                    uint8_t i = 0;
                    do
                    {
                        i++;
                        LOGGER_INFO("等待照片：{}", i);
                        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
                    } while (i <= 10 && !hasNewContent.load(std::memory_order_acquire));

                    const auto filename = "car_body_" + Snowflake::genIdStr() + ".jpg";
                    auto content = SysUtil::base64_decode(imageContent);

                    if (imageContent == "")
                    {
                        LOGGER_ERROR("未收到图片");
                        return nullptr;
                    }

                    return std::make_shared<std::istringstream>(content, std::ios_base::in | std::ios_base::binary);
                } else
                {
                    LOGGER_ERROR("未找到 MQTT 本地客户端");
                }
            } catch (const std::exception &e)
            {
                LOGGER_INFO("拍照失败:{}", e.what());
            } catch (...)
            {
                LOGGER_ERROR("未知异常，拍照失败");
            }
            return nullptr;
        } catch (std::exception &e)
        {
            LOGGER_ERROR("摄像机拍照失败：{}", e.what());
            return nullptr;
        } catch (...)
        {
            LOGGER_ERROR("未知异常，摄像机拍照失败");
            return nullptr;
        }
    }
}
