#include "generic_vidicon.h"

#include <fstream>

#include "HCNetSDK.h"
#include "common/snowflake.h"
#include "common/sys_util.h"

namespace zsy
{
    GenericVidicon::~GenericVidicon()
    {
    }

    GenericVidicon::GenericVidicon(const VidiconProperties &config)
        : config(config)
    {
        SysUtil::createDirs(SysUtil::HOME_DIR + "\\temp");
    }

    std::shared_ptr<std::istream> GenericVidicon::read(const std::string &filePath)
    {
        if (!std::filesystem::exists(filePath))
        {
            LOGGER_ERROR("文件不存在：{}", filePath);
            return nullptr;
        }

        std::uintmax_t fileSize = 0;
        try
        {
            fileSize = std::filesystem::file_size(filePath);
        } catch (const std::filesystem::filesystem_error &e)
        {
            LOGGER_ERROR("获取文件大小失败 - {}", e.what());
            return nullptr;
        }
        // 打开文件
        std::ifstream file(filePath, std::ios::binary);
        if (!file.is_open())
        {
            LOGGER_ERROR("错误: 无法打开文件 {}", filePath);
            return nullptr;
        }

        std::string fileContent;
        fileContent.reserve(fileSize);

        char buffer[4096];
        while (file.read(buffer, sizeof(buffer)))
        {
            fileContent.append(buffer, sizeof(buffer));
        }

        // 处理最后一块可能不完整的数据
        if (file.gcount() > 0)
        {
            fileContent.append(buffer, file.gcount());
        }

        // 检查读取是否成功
        if (!file.eof())
        {
            LOGGER_ERROR("错误: 读取文件 '{}' 时发生错误", filePath);
            return nullptr;
        }

        // 关闭文件
        file.close();

        return std::make_shared<std::istringstream>(fileContent, std::ios_base::in | std::ios_base::binary);
    }

    void GenericVidicon::remove(const std::string &photographPath)
    {
        if (!photographPath.empty())
        {
            auto pathPtr = SysUtil::ch_vlt(photographPath.c_str());
            if (std::remove(pathPtr.get()) != 0)
            {
                auto [_,code,msg] = SysUtil::getError();
                LOGGER_ERROR("临时照片删除失败：{}，错误码：{}，错误信息：{}", photographPath, code, msg);
            } else
            {
                LOGGER_ERROR("临时照片删除成功：{}", photographPath);
            }
        }
    }

    std::shared_ptr<std::istream> GenericVidicon::photograph()
    {
        try
        {
            LOGGER_INFO("摄像机正在拍照，设备名称：{}", config.name);

            BOOL succ = NET_DVR_Init();
            if (!succ)
            {
                LOGGER_ERROR("摄像机初始化失败：{} {}", NET_DVR_GetLastError(), NET_DVR_GetErrorMsg());
                NET_DVR_Cleanup();
                return {};
            }
            auto logPath = SysUtil::ch_vlt((SysUtil::HOME_DIR + "\\logs").c_str());
            succ = NET_DVR_SetLogToFile(3, logPath.get(), true);
            if (!succ)
            {
                LOGGER_ERROR("摄像机日志设置失败：{} {}", NET_DVR_GetLastError(), NET_DVR_GetErrorMsg());
                NET_DVR_Cleanup();
                return {};
            }
            NET_DVR_DEVICEINFO_V30 DeviceInfoTmp{};

            auto ip = SysUtil::ch_vlt(config.ip.c_str());
            auto username = SysUtil::ch_vlt(config.username.c_str());
            auto passwd = SysUtil::ch_vlt(config.passwd.c_str());
            LONG lLoginID = NET_DVR_Login_V30(ip.get(),
                                              config.port,
                                              username.get(),
                                              passwd.get(), &DeviceInfoTmp);

            if (lLoginID == -1)
            {
                DWORD e = NET_DVR_GetLastError();
                auto m = NET_DVR_GetErrorMsg();
                LOGGER_ERROR("摄像机登录失败：{} {}", e, m);
                NET_DVR_Cleanup();
                return {};
            }

            NET_DVR_JPEGPARA JpgPara{};
            JpgPara.wPicSize = 0xff;
            JpgPara.wPicQuality = 0;
            const auto filename = "car_body_" + Snowflake::genIdStr() + ".jpg";
            std::string path = SysUtil::HOME_DIR + "\\temp\\" + filename;
            const auto path_ = SysUtil::ch_vlt(path.c_str());
            auto filePath = path_.get();
            if (!NET_DVR_CaptureJPEGPicture(lLoginID, 1, &JpgPara, filePath))
            {
                LOGGER_ERROR("摄像机拍照失败：{} {}", NET_DVR_GetLastError(), NET_DVR_GetErrorMsg());
                NET_DVR_Cleanup();
                return {};
            }
            LOGGER_INFO("摄像机拍照完成：{}", path);

            NET_DVR_Logout_V30(lLoginID);
            NET_DVR_Cleanup();

            auto content = read(path);

            remove(path);

            return content;
        } catch (std::exception &e)
        {
            LOGGER_ERROR("摄像机拍照失败：{}", e.what());
            return {};
        }
        catch (...)
        {
            LOGGER_ERROR("未知异常，摄像机拍照失败");
            return {};
        }
    }
} // zsy
