#include "CameraHandle.h"
#include "TaskRunnable.h"
#include "AlgorithmTaskManage.h"
#include "ScopeSemaphoreExit.h"
#include <QRegularExpression>
CameraHandle::CameraHandle(){
    
}
CameraHandle::CameraHandle(QString &url, QString &httpUrl, QString &sSn, int &channel,
                           int imageSave,float &heightReference,vides_data::responseConfig &devConfig)
    : hDevice(-1),
      url(url),
      loginParam(new SXSDKLoginParam()),
      sxMediaFaceImageReq(new SXMediaFaceImageReq()),
      sSn(sSn),
      channel(channel),
      httpUrl(httpUrl),
      dev_snap_syn_timer(new QTimer()),
      image_save(imageSave),
      faceCount(0),
      semaphore(1),
      heightReference(heightReference),
      devConfig(devConfig)
{
    connect(this, SIGNAL(afterDownloadFile(int,int,QString)), this, SLOT(pushRecordToCloud(int,int,QString)),Qt::QueuedConnection);
    
    
    faceMapWorker.setX(0);
    faceMapWorker.setY(0);
    
}
CameraHandle::~CameraHandle() {
    
    semaphore.acquire();
    
    
    Common & instace= Common::getInstance();
    dev_snap_syn_timer->stop();
    
    ScopeSemaphoreExit guard([this]() {
        semaphore.release();  // 释放信号量
    });
    instace.deleteObj(dev_snap_syn_timer);
    instace.deleteObj(loginParam);
    instace.deleteObj(sxMediaFaceImageReq);
    
    for(auto iter = parkMap.begin(); iter != parkMap.end(); ++iter) {
        instace.deleteObj( iter->second);
    }
    parkMap.clear();
    XSDK_DevLogout(this->hDevice);
    
}

int CameraHandle::sdkDevLoginSyn(QString sDevId, int nDevPort, QString sUserName, QString sPassword, int nTimeout) {
    QByteArray byteArray = sDevId.toUtf8();
    char* cDevid=byteArray.data();
    
    strcpy(loginParam->sDevId, cDevid);
    
    loginParam->nDevPort=nDevPort;
    
    QByteArray byteName = sUserName.toUtf8();
    char* cName=byteName.data();
    
    strcpy(loginParam->sUserName, cName);
    
    if(sPassword.length()>0){
        QByteArray bytePassword = sPassword.toUtf8();
        strcpy(loginParam->sPassword, bytePassword.constData());
    }else{
        strcpy(loginParam->sPassword, "");
    }
    loginParam->nCnnType=EDEV_CNN_TYPE_AUTO;
    int loginResult =XSDK_DevLoginSyn(loginParam,nTimeout);
    if(loginResult<0){
        qInfo() << QString("SN(%1): 登录设备失败").arg(sSn);;
        return loginResult;
    }
    this->hDevice=loginResult;
    return loginResult;
}

int XNetSDK_MediaCallBack(XSDK_HANDLE hMedia, int nDataType, int nDataLen, int nParam2, int nParam3, const char* szString, void* pData, int64 pDataInfo, int nSeq, void* pUserData, void* pMsg){
    CameraHandle* cameraHandle=static_cast<CameraHandle*>(pUserData);
    std::map<QString, QString> &data=cameraHandle->getCurrentData();
    QString dName=data.at("downloadFileName");
    QByteArray bFname =dName.toUtf8();
    const char* cFname=bFname.data();
    int sId= data.at("id").toInt();
    // 打印I帧信息
    if (EXSDK_DATA_FORMATE_FRAME == nDataType)
    {
        // 帧信息
        SXSDK_FRAME_INFO* pFrame = (SXSDK_FRAME_INFO*)pDataInfo;
        MediaFaceImage* mediaFaceImage= MediaFaceImage::getInstance();
        
        if (pFrame->nType == XSDK_FRAME_TYPE_VIDEO && pFrame->nSubType == XSDK_FRAME_TYPE_VIDEO_I_FRAME)
        {
            //printf("[%d]::OnFrame[Len:%d][Type:%d/%d][%04d-%02d-%02d %02d:%02d:%02d-%03d]\r\n", hMedia, pFrame->nLength, pFrame->nType, pFrame->nSubType, pFrame->nYear, pFrame->nMonth, pFrame->nDay, pFrame->nHour, pFrame->nMinute, pFrame->nSecond, (int)(pFrame->nTimeStamp % 1000));
        }
        
        if (cameraHandle->getMediaHandle() > 0 && cameraHandle->getMediaHandle()== hMedia)
        {
            if (pFrame->nSubType == XSDK_ENCODE_VIDEO_JPEG)
            {
                
                mediaFaceImage->AbFile(cFname, pFrame->pContent, pFrame->nFrameLength);
            }
            else
            {
                // 不带公司私有头数据，(裸H264 或 H265 或 g711a 或 aac)
                // printf("Frame-Content:[Len:%d][%p]\r\n", pFrame->nFrameLength, pFrame->pContent);
                // 带公司私有头数据
                mediaFaceImage->AbFile(cFname, pFrame->pHeader, pFrame->nLength);
            }
        }
        
    }
    else if (ESXSDK_MEDIA_START_REAL_PLAY == nDataType
             || ESXSDK_MEDIA_START_FACE_IMAGE == nDataType
             || ESXSDK_MEDIA_START_RECORD_PLAY == nDataType
             || ESXSDK_MEDIA_DOWN_RECORD_FILE == nDataType
             || ESXSDK_MEDIA_DOWN_IMAGES_FILE == nDataType
             || ESXSDK_MEDIA_START_TALK == nDataType
             )
    {
        int& nResult = nDataLen;
        
    }
    else if (EXCMD_MONITOR_DATA == nDataType
             || EXCMD_DOWNLOAD_DATA == nDataType
             || EXCMD_PLAY_DATA == nDataType
             || EXCMD_TALK_CU_PU_DATA == nDataType
             || EXCMD_TALK_PU_CU_DATA == nDataType
             )
    {
        // 2秒打印一次
        /*IF_Printf_Timeout(2)
            {
                printf("[%d]::OnMedia[%d][DataLen:%d]\r\n", hMedia, nDataType, nDataLen);
            }*/
        
        if (EXCMD_DOWNLOAD_DATA == nDataType)
        {
            qInfo()<<"EXCMD_DOWNLOAD_DATA"<<nDataType;
            
            /*if (g_hRecordDownload > 0 && g_hRecordDownload == hMedia)
                {
                    std::string::size_type pos = g_test.sDownloadFileName.rfind('.');
                    std::string strSuffix = g_test.sDownloadFileName.substr(pos + 1, pos + 2);
                    
                    if (STRCMP(strSuffix.c_str(), "jpg") == 0)
                    {
                        const char* pWriteData = (const char*)pData;
                        if(stInit == 0)
                        {
                            pWriteData += 16;
                            nDataLen -= 16;
                            
                            ++stInit;
                        }
                        
                        XFILE::ABFile(g_test.sDownloadFileName.c_str(), pWriteData, nDataLen);
                    }
                    else
                    {
                        // 不带公司私有头数据，(裸H264 或 H265 或 g711a 或 aac)
                        // printf("Frame-Content:[Len:%d][%p]\r\n", pFrame->nFrameLength, pFrame->pContent);
                        // 带公司私有头数据
                        XFILE::ABFile(g_test.sDownloadFileName.c_str(), pData, nDataLen);
                    }
                }
            }*/
        }
    }
    else  if (EXSDK_DATA_MEDIA_ON_PLAY_STATE == nDataType)
    {
        //int& nState = nDataLen;
        //printf("[%d]::OnMediaStateChannged[nState:%d]\r\n", hMedia, nState);
        
        if (nDataLen == EState_Media_DataEnd)
        {
            if (cameraHandle->getMediaHandle() > 0)
            {
                XSDK_MediaStop(cameraHandle->getMediaHandle());
                cameraHandle->setMediaHandle(0);
                QString mp4FileName =dName;
                mp4FileName.replace(QRegularExpression("\\.[^\\.]*$"), ".mp4");
                data["downloadFileName"]=mp4FileName;
                
                QProcess ffmpegProcess;
                QStringList arguments;
                arguments << "-i" << dName <<"-c:v" << "copy" << mp4FileName;
                
                ffmpegProcess.start("ffmpeg", arguments);
                // 等待 ffmpeg 进程结束
                if (ffmpegProcess.waitForFinished(20000)) {
                    //QFile::remove(dName);
                    qInfo() << "ffmpeg process finished successfully.";
                } else {
                    qInfo() << "Error: ffmpeg process did not finish.";
                }
                
                // 销毁 QProcess 对象
                ffmpegProcess.close();
                QFileInfo fileInfo(mp4FileName);
                QString fileName = fileInfo.fileName();
                QString ossUrl=data.at("ossUrl");
                ossUrl.append("/").append(fileName);
                std::map<int, vides_data::responseRecognitionData>datas =cameraHandle->getVideoCurrentData();
                QString recognitionType;
                if(datas.count(sId)>0){
                    recognitionType=datas.at(sId).recognitionType;
                }
                emit cameraHandle->afterDownloadFile(sId,recognitionType.toInt(),ossUrl);
            }
        }
    }
    
}
int CameraHandle::sdkDevSetAlarmListener(XSDK_HANDLE hDevice, int bListener) {
    return XSDK_DevSetAlarmListener(hDevice,bListener);
}

int CameraHandle::getChannel(){
    return channel;
}
int CameraHandle::getHdevice() {
    return hDevice;
}

void CameraHandle::setCarConfidenceMaxAndMin(float carConfidenceMax,float carConfidenceMin){
    this->carConfidenceMax=carConfidenceMax;
    this->carConfidenceMin=carConfidenceMin;
}


void CameraHandle::getCurrentFrame(std::vector<uchar> &buffer){
    MediaFaceImage* mediaFaceImage= MediaFaceImage::getInstance();
    mediaFaceImage->CameraImage(this->hDevice,this->channel,buffer);
}
//相机参数更新
void CameraHandle::cameraParameterUpdate(vides_data::responseConfig &cloudConfig){
    bool forMat=false;
    if(devConfig.mainFormat.updateAt!=cloudConfig.mainFormat.updateAt){
        devConfig.mainFormat=cloudConfig.mainFormat;
        forMat=true;
    }
    if(devConfig.extraFormat.updateAt!=cloudConfig.extraFormat.updateAt){
        devConfig.extraFormat=cloudConfig.extraFormat;
        forMat=true;
    }
    if(forMat){
        deviceReboot();
    }
    if(devConfig.camera.updateAt!=cloudConfig.camera.updateAt){
        if(devConfig.camera.username!=cloudConfig.camera.username ||
                devConfig.camera.password!=cloudConfig.camera.password ){
            QString ip=QString::fromUtf8(loginParam->sDevId);
            MainWindow::sp_this->clearOfflineCameraHandle(ip,loginParam->nDevPort);
        }else {
            this->heightReference=cloudConfig.camera.heightReference;
            this->image_save=cloudConfig.camera.imageSave;
            if(this->devConfig.camera.devSnapSynTimer!= cloudConfig.camera.devSnapSynTimer){
                dev_snap_syn_timer->stop(); // 停止当前定时器
                dev_snap_syn_timer->setInterval(cloudConfig.camera.devSnapSynTimer); // 设置新的定时器时间
                dev_snap_syn_timer->start(); // 启动定时器
            }
        }
        
    }
    
    float carConfidenceMax=cloudConfig.licensePlateConfig.carConfidenceMax;
    float carConfidenceMin=cloudConfig.licensePlateConfig.carConfidenceMin;
    this->setCarConfidenceMaxAndMin(carConfidenceMax,carConfidenceMin);
    
}

void CameraHandle::initFaceFrequency(uint64 face_frequency){
    this->face_frequency=face_frequency;
}

void CameraHandle::initSdkRealTimeDevSnapSyn(int syn_timer,uint64 face_frequency)
{
    connect(dev_snap_syn_timer, &QTimer::timeout, this, [this]() {
        this->sdkRealTimeDevSnapSyn();
    },Qt::QueuedConnection);
    this->face_frequency=face_frequency;
    dev_snap_syn_timer->start(syn_timer);
}

void CameraHandle::sdkRealTimeDevSnapSyn() {
    QThreadPool* threadPool = QThreadPool::globalInstance();
    auto taskSyn = [this]() {
        sdkDevSnapSyn(this->hDevice, this->channel);
    };
    
    if (threadPool->activeThreadCount() >= threadPool->maxThreadCount()) {
        qInfo() << QString("SN(%1): 任务积压，跳过本次执行").arg(sSn);
        return;
    }
    auto taskRunnable = new TaskRunnable(taskSyn, hDevice, this->channel, RunFunction::SdkDevSnapSyn);
    
    threadPool->start(taskRunnable);
}
QString CameraHandle::getSSn(){
    return sSn;
}
int CameraHandle::getMediaHandle(){
    return mediaHandle;
}
void CameraHandle::setMediaHandle(int mediaHandle){
    this->mediaHandle=mediaHandle;
}

std::map<QString, QString>&CameraHandle::getCurrentData(){
    return currentData;
}
std::map<int, vides_data::responseRecognitionData>&CameraHandle::getVideoCurrentData(){
    return videoCurrentData;
}
vides_data::responseConfig &CameraHandle::getDeviceConfig(){
    return devConfig;
}

void CameraHandle::sdkDownloadFileByTime(XSDK_HANDLE hDevice,int id,
                                         QString startTimer, QString endTime){
    if(mediaHandle>0){
        XSDK_MediaStop(mediaHandle);
        this->mediaHandle=0;
    }
    currentData["id"]=QString::number(id);
    Common & instace= Common::getInstance();
    QString videoPath=instace.getVideoOut();
    QDateTime now = QDateTime::currentDateTime();
    QString szTime = now.toString("yyyy_MM_dd_hh_mm_ss");
    QString newSn=sSn;
    newSn.append("_");
    newSn.append(szTime);
    //downloadFileName=QString("%1/%2.h264").arg(videoPath, szTime);
    currentData["downloadFileName"] =QString("%1%2.h264").arg(videoPath, newSn);
    
    SXMediaRecordReq param = { 0 };
    
    QByteArray bStart =startTimer.toUtf8();
    const char* cStart=bStart.data();
    
    QByteArray bEnd=endTime.toUtf8();
    const char* cEnd=bEnd.data();
    strcpy(param.sBeginTime, cStart);	// 请求的开始时间（必填）
    strcpy(param.sEndTime, cEnd);		// 请求的结束时间（必填）
    param.nChannel = channel;						// 通道号（必填）
    param.nStreamType = 0;				// 码流类型（必填）
    param.nRequestType = EXSDK_DATA_FORMATE_FRAME;	// 源数据输出（选填）,详见nRequestType说明
    //param.result = sdkInitCallback;			// 结果回调（必填）
    SMsgReceiver sms(nullptr,XNetSDK_MediaCallBack,this);
    param.result=sms;
    qInfo() << "XSDK_MediaRecordDownload hDevice:"<<this->hDevice;
    
    this->mediaHandle = XSDK_MediaRecordDownload(this->hDevice, &param, 0, 4000);
    if ( this->mediaHandle  < 0)
    {
        qInfo() << "XSDK_MediaRecordDownload Failed:"<< this->mediaHandle ;
        
        return ;
    }
    
    
}
int CameraHandle::callbackFunction(XSDK_HANDLE hObject, QString &szString) {
    if (!semaphore.tryAcquire()) {
        qInfo() <<  QString("SN(%1): sdkDevSnapSyn:正在执行线程").arg(sSn);
        return -1;
    }
    ScopeSemaphoreExit guard([this]() {
        semaphore.release();  // 释放信号量
    });
    QByteArray && byJson = szString.toLocal8Bit();
    const char * cJson= byJson.data();
    XSDK_CFG::AlarmInfo alarmInfo;
    if (0 == alarmInfo.Parse(cJson))
    {
        const char* buf = alarmInfo.Event.ToString();
        qInfo() << "buf:"<<buf;
        qInfo() << "OnDevAlarmCallback[Dev:" << hObject << "]"
                << "\r\nEvent:" << alarmInfo.Event.Value()
                << "\r\nChannel:" << alarmInfo.Channel.Value()
                << "\r\nStartTime:" << alarmInfo.StartTime.Value()
                << "\r\nStatus:" << alarmInfo.Status.Value();
        
    }
    else
    {
        qInfo() << "OnDevAlarmCallback[Dev:" << hObject << "][Event:" << szString << "]";
    }
    cv::Mat image;
    MediaFaceImage* mediaFaceImage= MediaFaceImage::getInstance();
    qint64 currentTime= QDateTime::currentSecsSinceEpoch();
    mediaFaceImage->FaceImageCallBack(hObject,this->channel,image,sSn);
    
    if (image.empty())
    {
        qInfo() << "Failed to read the image";
        return -1;
    }
    if (image.rows <= 0 || image.cols <= 0 || image.channels() <= 0) {
        qInfo() << "图像尺寸或通道数不正确，需排查原因";
        return -1;
    }
    qInfo() << "callbackFunction request to: " << sSn;
    updateImage(image, currentTime);
}

void CameraHandle::sdkDevSnapSyn(XSDK_HANDLE hDevice, int nChannel){
    
    if(hDevice<=0){
        qInfo() << QString("SN(%1): 相机断线").arg(sSn);
        return;
    }
    if (!semaphore.tryAcquire()) {
        qInfo() << QString("SN(%1): callbackFunction:正在执行线程").arg(sSn);;
        return ;
    }
    ScopeSemaphoreExit guard([this]() {
        semaphore.release();  // 释放信号量
    });
    Common & instace= Common::getInstance();
    cv::Mat image;
    MediaFaceImage* mediaFaceImage= MediaFaceImage::getInstance();
    qint64 currentTime= QDateTime::currentSecsSinceEpoch();
    int ret=mediaFaceImage->FaceImageCallBack(hDevice,nChannel, image,sSn);
    if (ret < 0) {
        offlineCount++; // 累加计数器
        if (offlineCount >= 3) { // 判断是否连续3次返回0
            qInfo() <<QString("SN(%1): 设备离线").arg(sSn);
            QString ip=QString::fromUtf8(loginParam->sDevId);
            bool is_ping=instace.pingAddress(ip);
            qDebug() << sSn<<":ping 的结果"<<is_ping;
            
            if(is_ping){
                deviceReboot();
            }else {
                QString ip=QString::fromUtf8(loginParam->sDevId);
                MainWindow::sp_this->clearOfflineCameraHandle(ip,loginParam->nDevPort);
            }
            // 执行离线处理逻辑
            // TODO: 可以在此处更新设备状态、发送告警通知等
            // 重置计数器，以便下次再次检测连续离线
            offlineCount = 0;
            
            return;
        }
    } else {
        // 如果不连续，则重置计数器
        offlineCount = 0;
    }
    if (image.empty())
    {
        qInfo()<<QString("SN(%1): Failed to read the image").arg(sSn);
        return ;
    }
    if (image.rows <= 0 || image.cols <= 0 || image.channels() <= 0) {
        qInfo()<<QString("SN(%1): 图像尺寸或通道数不正确，需排查原因").arg(sSn);
        
        return ;
    }
    updateImage(image, currentTime);
}

void CameraHandle::matToBase64(const cv::Mat &image, QByteArray &base64Data) {
    std::vector<unsigned char> buffer;
    std::vector<int> params{cv::IMWRITE_JPEG_QUALITY, 90};
    cv::imencode(".jpg", image, buffer, params);
    base64Data = QByteArray(reinterpret_cast<const char*>(buffer.data()), buffer.size()).toBase64();
}
void CameraHandle::checkAndUpdateCurrentPlate(ParkingSpaceInfo*park,const cv::Mat &frame, RecognizedInfo& newInfo,
                                              int &result){
    if (newInfo.getLicensePlate() != park->getCurrentPlate().getLicensePlate()) {
        int count = 0;
        for (auto& info : park->getQueue()) {
            if (info.getLicensePlate() == newInfo.getLicensePlate()) {
                count++;
            }
        }
        
        qInfo() << QString("SN(%1): 最新车牌%2，当前区域车牌：%3").arg(sSn).arg(newInfo.getLicensePlate()).arg(park->getCurrentPlate().getLicensePlate());
        qInfo() << QString("SN(%1): 区域：%2，数量：%3").arg(sSn).arg(park->getSpaceIndex()).arg(count);
        
        if (count>= 3) {
            //第一次进场 当前车牌就是进来这个，老车牌就是空
            if(park->getCurrentPlate().getLicensePlate().length()<=0){
                //进场
                park->setCurrentPlate(newInfo);
                result=Mobilization;
            }else {
                //当前为空，离场
                if(newInfo.getLicensePlate().length()<=0){
                    AlgorithmTaskManage &algorithmTaskManage=AlgorithmTaskManage::getInstance();
                    std::vector<vides_data::ParkingArea> currentPlates;
                    std::map<int,int>resMap;
                    
                    int car_size =algorithmTaskManage.executeFindHuManCar(frame,0x01,currentPlates,resMap,sSn,heightReference);
                    qInfo()<<QString("SN(%1): 当前车形数量:%2").arg(sSn).arg(car_size);
                    
                    if (car_size <= 0 && car_size!=-2) {
                        qInfo()<<QString("SN(%1): 区域:%2出场").arg(sSn).arg(park->getSpaceIndex());
                        //如果有车辆检测到并且不在停车区域内部，视为出场
                        park->setCurrentPlate(newInfo);
                        result = Exit;
                    }else {
                        // 没有车辆或车辆在停车区域内部，移除队列
                        park->removeNoQueue();
                        qDebug()<<QString("SN(%1): no出场：:%2").arg(sSn).arg(car_size);
                    }
                }else{
                    //当前不为空，新车，新车入场，老车出场
                    //exitAndMoMap[Exit]=park->getCurrentPlate();
                    //exitAndMoMap[Mobilization]=newInfo;
                    park->setCurrentPlate(newInfo);
                    result=ExitAndMobilization;
                }
            }
        }
    }
}


void CameraHandle::batchRegionalPushLicensePlate(QByteArray &imgs,qint64 currentTime,vides_data::requestLicensePlate &newPlate){
    for(auto it = parkMap.begin(); it != parkMap.end(); ++it) {
        ParkingSpaceInfo* value = it->second; // 获取对应的值（ParkingSpaceInfo指针）
        vides_data::LicensePlate plates;
        plates.time=currentTime;
        plates.img=imgs;
        plates.areaLocation=value->getArea();
        newPlate.plates.push_back(plates);
    }
}

void CameraHandle::matToAreaMask(const cv::Mat &source, std::map<int, cv::Mat> &maskFrame) {
    Common & instace= Common::getInstance();
    
    for (auto iter = parkMap.begin(); iter != parkMap.end(); ++iter) {
        int id = iter->first;
        ParkingSpaceInfo* parkArea = iter->second;
        
        // 转换浮点坐标为整型坐标
        int topLeftX = instace.clamp(static_cast<int>(parkArea->getArea().topLeftCornerX), 0, source.cols - 1);
        int topLeftY =instace.clamp(static_cast<int>(parkArea->getArea().topLeftCornerY), 0, source.rows - 1);
        int topRightX =instace.clamp(static_cast<int>(parkArea->getArea().topRightCornerX), 0, source.cols - 1);
        int topRightY = instace.clamp(static_cast<int>(parkArea->getArea().topRightCornerY), 0, source.rows - 1);
        int bottomRightX = instace.clamp(static_cast<int>(parkArea->getArea().bottomRightCornerX), 0, source.cols - 1);
        int bottomRightY = instace.clamp(static_cast<int>(parkArea->getArea().bottomRightCornerY), 0, source.rows - 1);
        int bottomLeftX = instace.clamp(static_cast<int>(parkArea->getArea().bottomLeftCornerX), 0, source.cols - 1);
        int bottomLeftY = instace.clamp(static_cast<int>(parkArea->getArea().bottomLeftCornerY), 0, source.rows - 1);
        
        std::vector<cv::Point> parkAreaPoints = {
            cv::Point(topLeftX, topLeftY),
            cv::Point(topRightX, topRightY),
            cv::Point(bottomRightX, bottomRightY),
            cv::Point(bottomLeftX, bottomLeftY)
        };
        
        // 创建与source相同大小的掩码图像，并用黑色填充
        cv::Mat mask = cv::Mat::zeros(source.size(), CV_8UC1);
        
        // 使用fillPoly填充多边形到mask
        std::vector<std::vector<cv::Point>> parkAreas = { parkAreaPoints };
        cv::fillPoly(mask, parkAreas, cv::Scalar(255)); // 使用白色(255)填充指定的多边形区域
        
        // 使用掩码从source中提取区域，同时保持原始大小
        cv::Mat maskedSource = cv::Mat::zeros(source.size(), source.type());
        source.copyTo(maskedSource, mask);
        
        // 将带有掩码的图像存入maskFrame
        maskFrame[id] = maskedSource;
    }
}

bool CameraHandle::isChanged(const QPoint& newInfo, const QPoint& current) {
    const double epsilon = 1e-6; // 定义一个非常小的阈值
    double distance = std::sqrt(std::pow(newInfo.x() - current.x(), 2) + std::pow(newInfo.y() - current.y(), 2));
    return distance > epsilon; // 如果距离大于阈值，则认为发生了变化
}

void CameraHandle::updateImage(const cv::Mat & frame,qint64 currentTime){
    
    Common & instace= Common::getInstance();
    qInfo()<<"=============================>";
    AlgorithmTaskManage &algorithmTaskManage=AlgorithmTaskManage::getInstance();
    
    
    std::map<QString,vides_data::requestFaceReconition> mapFaces;
    
    ScopeSemaphoreExit guard([this]() {
        faceCount.fetch_add(1, std::memory_order_relaxed);
    });
    
    QByteArray imgs;
    this->matToBase64(frame, imgs);
    
    HttpService httpService(httpUrl);
    int faSize =0;
    std::vector<vides_data::ParkingArea> currentPlates;
    int uniforms=0x00;
    std::map<int,int>resMap;
    qInfo()<<QString("SN(%1): 相机算法:%2").arg(sSn).arg(algorithmPermissions);
    if ((algorithmPermissions & 0x01<<3) != 0) {
        //穿工服算法
        if ((algorithmPermissions & 0x01<<2) != 0) {
            uniforms=algorithmTaskManage.executeFindHuManCar(frame,0x02,currentPlates,resMap,sSn,heightReference);
            if(resMap.size()>0x00){
                faSize=resMap.at(0x00);
                uniforms=resMap.at(0x02);
            }
        }else{
            //人形
            uniforms=algorithmTaskManage.executeFindHuManCar(frame,0x00,currentPlates,resMap,sSn,heightReference);
            if(resMap.size()>0x00){
                faSize=resMap.at(0x00);
                uniforms=faSize;
            }
        }
        if(uniforms==-2 || faSize==-2){
            qInfo()<<QString("SN(%1): 没有可用的HumanDetection对象可以调度").arg(sSn);
            return ;
        }
        QPoint point_info(faSize,uniforms);
        if(isChanged(point_info,faceMapWorker)){
            qInfo()<<QString("SN(%1): 人形计算器:%2").arg(sSn).arg(faceCount);
            
            qInfo()<<QString("SN(%1): 人形频率:%2").arg(sSn).arg(face_frequency);
            
            if(faceCount.load(std::memory_order_relaxed)%face_frequency==0){
                int worker=0x00;
                if ((algorithmPermissions & 0x01<<2) != 0) {
                    worker = (faSize - uniforms > 0) ? (faSize - uniforms) : 0;
                }
                vides_data::response* resp=httpService.httpPostFacePopulation(imgs,faSize,worker,sSn,currentTime);
                
                if (resp->code!= 0) {
                    if(resp->msg=="TimeoutError")  {
                        QByteArray num_imgs;
                        httpService.setHttpUrl(httpUrl);
                        vides_data::response* img_resp = httpService.httpPostFacePopulation(num_imgs,faSize,worker,sSn,currentTime);
                        if (img_resp->code != 0) {
                            qInfo()<<QString("SN(%1):不加图片人数变化推送信息推送失败,失败信息%2").arg(sSn).arg(img_resp->msg);
                        }else {
                            qInfo()<<QString("SN(%1): 不加图片人数变化推送信息推送成功").arg(sSn);
                            
                        }
                        instace.deleteObj(img_resp);
                    }else{
                        qInfo()<<QString("SN(%1): 人数变化推送失败,失败信息%2").arg(sSn).arg(resp->msg);
                    }
                }else {
                    qInfo()<<QString("SN(%1): 人数变化推送成功").arg(sSn);
                }
                
                instace.deleteObj(resp);
                faceMapWorker.setX(faSize);
                faceMapWorker.setY(uniforms);
            }
        }
        
        if(faSize>0 && (algorithmPermissions & 0x01<<1) != 0){
            std::list<vides_data::faceRecognitionResult>faces;
            algorithmTaskManage.executeFindDoesItExistEmployee(frame,faces,sSn);
            if (faces.size()>0) {
                for(auto face:faces){
                    vides_data::requestFaceReconition faceReconition;
                    faceReconition.id = face.id;
                    faceReconition.img = imgs;
                    faceReconition.sn = sSn;
                    faceReconition.time = currentTime;
                    faceReconition.area.top_left_corner_x=face.x;
                    faceReconition.area.top_left_corner_y=face.y;
                    faceReconition.area.bottom_right_corner_x= face.x + face.width;
                    faceReconition.area.bottom_right_corner_y= face.y + face.height;
                    faceReconition.area.bottom_left_corner_x = face.x;
                    faceReconition.area.bottom_left_corner_y = face.y + face.height;
                    
                    faceReconition.area.top_right_corner_x = face.x + face.width;
                    faceReconition.area.top_right_corner_y = face.y;
                    httpService.setHttpUrl(httpUrl);
                    vides_data::response* resp = httpService.httpPostFaceReconition(faceReconition);
                    
                    mapFaces.insert(std::make_pair( face.id, faceReconition));
                    if (resp->code!= 0) {
                        if(resp->msg=="TimeoutError")  {
                            faceReconition.img.clear();
                            httpService.setHttpUrl(httpUrl);
                            vides_data::response* img_resp = httpService.httpPostFaceReconition(faceReconition);
                            if (img_resp->code != 0) {
                                qInfo()<<QString("SN(%1): 不加图片人脸信息推送失败,失败信息%2,人脸id%3").arg(sSn).arg(resp->msg).arg(face.id);
                            }else {
                                qInfo()<<QString("SN(%1): 不加图片人脸信息推送成功").arg(sSn);
                            }
                            instace.deleteObj(img_resp);
                        }else {
                            qInfo()<<QString("SN(%1): 人脸信息推送失败,失败信息%2").arg(sSn).arg(resp->msg);
                        }
                    }else{
                        qInfo()<<QString("SN(%1): 人脸信息推送成功").arg(sSn);
                    }
                    instace.deleteObj(resp);
                }
            }
        }
        
        if ((algorithmPermissions & 0x01<<2) != 0) {
            if(uniforms>0 ){
                //未穿工服的人数
                std::list<QString> outUniforms;
                faceUniformOverlap(mapFaces,currentPlates,outUniforms);
                for(auto strUniform:outUniforms){
                    httpService.setHttpUrl(httpUrl);
                    vides_data::response* resp=httpService.httpPostUniforms(imgs,strUniform, sSn,currentTime);
                    if (resp->code!= 0) {
                        if(resp->msg=="TimeoutError")  {
                            QByteArray num_imgs;
                            httpService.setHttpUrl(httpUrl);
                            vides_data::response* img_resp=httpService.httpPostUniforms(num_imgs,strUniform, sSn,currentTime);
                            if (img_resp->code != 0) {
                                qInfo()<<QString("SN(%1): 不加图片推送未穿工服人数失败,失败信息%2").arg(sSn).arg(img_resp->msg);
                            }else {
                                qInfo()<<QString("SN(%1): 不加图片推送未穿工服人数成功").arg(sSn);
                            }
                            instace.deleteObj(img_resp);
                        }else{
                            qInfo()<<QString("SN(%1): 推送未穿工服人数失败,失败信息%2").arg(sSn).arg(resp->msg);
                        }
                    }else{
                        qInfo()<<QString("SN(%1): 推送未穿工服人数成功").arg(sSn);
                    }
                    instace.deleteObj(resp);
                }
            }
        }
    }else{
        qDebug()<<sSn<<":人形识别算法关闭，只有车牌算法了";
    }
    //关闭车牌识别
    if ((algorithmPermissions & 0x01) == 0) {
        return ;
    }
    QString lpNumber;
    
    //    return ;
    if(image_save==1){
        QString fileName= instace.getVideoOut().append(instace.getTimeString()+".jpg");
        bool success = cv::imwrite(fileName.toStdString(), frame);
        
        if (success) {
            qInfo() << "图片已成功保存至：" << fileName;
        } else {
            qInfo() << "图片保存失败!";
        }
        
    }
    std::map<int,cv::Mat>areaMat;
    matToAreaMask(frame,areaMat);
    if(image_save==2){
        for (auto it = areaMat.begin(); it != areaMat.end(); ++it) {
            int key = it->first;
            cv::Mat areaMat = it->second;
            
            QString fileName= instace.getVideoDownload().append(QString::number( key)+".jpg");
            bool success = cv::imwrite(fileName.toStdString(), areaMat);
            
            if (success) {
                qInfo() << "图片已成功保存至：" << fileName;
            } else {
                qInfo() << "图片保存失败!";
            }
            
        }
        
    }
    vides_data::requestLicensePlate newPlate;
    newPlate.sn=sSn;
    
    uint64_t countValue =faceCount.load(std::memory_order_relaxed);
    
    if(countValue==0 ){
        vides_data::requestLicensePlate initPlate;
        initPlate.sn=sSn;
        algorithmTaskManage.executeFindlicensePlateNumber(frame, lpNumber,initPlate,currentTime,sSn);
        if(initPlate.plates.size()==0){
            batchRegionalPushLicensePlate(imgs,currentTime,initPlate);
            if(initPlate.plates.size()>0){
                licensePlateRecognitionResults(initPlate);
            }
        }
    }
    
    for (auto it = areaMat.begin(); it != areaMat.end(); ++it) {
        int key = it->first;
        cv::Mat areaMat = it->second;
        std::map<int, ParkingSpaceInfo*>::iterator parkAreaMap = parkMap.find(key);
        ParkingSpaceInfo* value=nullptr;
        if (parkAreaMap != parkMap.end()) {
            value = parkAreaMap->second; // 成功找到，获取
        } else {
            qInfo()<<QString("SN(%1): 区域%2不存在").arg(sSn).arg(key);
            continue;
        }
        vides_data::requestLicensePlate resultPlate;
        resultPlate.sn=sSn;
        
        algorithmTaskManage.executeFindlicensePlateNumber(areaMat, lpNumber,resultPlate,currentTime,sSn);
        
        std::list<vides_data::LicensePlate>ps =resultPlate.plates;
        qInfo()<<QString("SN(%1):区域:%2识别的车牌信息是:%3").arg(sSn).arg(key).
                 arg(lpNumber);
        if(ps.size()==0){
            int res=-1;
            if(value==nullptr){
                continue;
            }
            if(value->getQueue().size()>=10) {
                value->removeQueue();
            }
            RecognizedInfo recognizedInfo("",QDateTime::currentSecsSinceEpoch(),"未知");
            value->addQueue(recognizedInfo);
            // 使用value指向的ParkingSpaceInfo对象
            this->checkAndUpdateCurrentPlate(value,areaMat,recognizedInfo,res);
            if (res == Exit || res == Mobilization) {
                vides_data::LicensePlate current;
                current.areaLocation=value->getArea();
                current.img=imgs;
                current.new_color=recognizedInfo.getColor();
                current.new_plate=recognizedInfo.getLicensePlate();
                current.time=recognizedInfo.getRecognizeTime();
                newPlate.plates.push_back(std::move(current));
            }
        }else{
            int res =-1;
            if(value==nullptr){
                continue;
            }
            vides_data::LicensePlate maxPlate;
            LicensePlateRecognition licensePlateRecognitionNew;
            
            licensePlateRecognitionNew.filterLicensePlateConfidenceMax(resultPlate,maxPlate);
            
            RecognizedInfo recognizedInfo;
            if (maxPlate.new_color=="蓝牌" && maxPlate.new_plate.length() != 7) {
                qDebug()<<QString("SN(%1): 蓝牌车牌号%2,recognition.new_plate.length()=%3").arg(sSn).arg(maxPlate.new_plate).arg(maxPlate.new_plate.length());
                continue;
            } else if (maxPlate.new_color=="绿牌新能源" && maxPlate.new_plate.length() != 8) {
                qDebug()<<QString("SN(%1): 绿牌车牌号%2,recognition.new_plate.length()=%3").arg(sSn).arg(maxPlate.new_plate).arg(maxPlate.new_plate.length());
                continue;
            } else if (maxPlate.new_plate.length() < 7) {
                qDebug()<<QString("SN(%1): 非绿牌蓝牌车牌号%2,recognition.new_plate.length()=%3").arg(sSn).arg(maxPlate.new_plate).arg(maxPlate.new_plate.length());
                continue;
            }
            if(maxPlate.text_confidence>=carConfidenceMax){
                if(value->getQueue().size()>=7 && value->getQueue().size()<=10) {
                    for (int i = 0; i < 3; ++i) {
                        value->removeQueue();
                    }
                }
                for (int var = 0; var < 3; ++var) {
                    RecognizedInfo info(maxPlate.new_plate,maxPlate.time,maxPlate.new_color);
                    value->addQueue(info);
                    recognizedInfo=std::move(info);
                }
                this->checkAndUpdateCurrentPlate(value,areaMat,recognizedInfo,res);
            }
            if(maxPlate.text_confidence<=carConfidenceMin){
                qDebug()<<QString("SN(%1): recognition.text_confidence<=instace.getCarConfidenceMin:%2").arg(sSn).arg(carConfidenceMin);
                
                continue;
            }
            if(maxPlate.text_confidence>carConfidenceMin
                    && maxPlate.text_confidence<carConfidenceMax)
            {
                if(value->getQueue().size()>=10) {
                    value->removeQueue();
                }
                RecognizedInfo info(maxPlate.new_plate,maxPlate.time,maxPlate.new_color);
                value->addQueue(info);
                recognizedInfo=std::move(info);
                this->checkAndUpdateCurrentPlate(value,areaMat,recognizedInfo,res);
            }
            if (res == Exit || res == Mobilization) {
                maxPlate.areaLocation=value->getArea();
                maxPlate.img=imgs;
                maxPlate.new_color=recognizedInfo.getColor();
                newPlate.plates.push_back(std::move(maxPlate));
            }
            if(res==ExitAndMobilization){
                maxPlate.areaLocation=value->getArea();
                maxPlate.img=imgs;
                maxPlate.new_color=recognizedInfo.getColor();
                newPlate.plates.push_back(std::move(maxPlate));
            }
            
        }
    }
    if(newPlate.plates.size()>0){
        foreach (auto var, newPlate.plates) {
            qInfo()<<QString("SN(%1): 识别的车牌号是:%2").arg(sSn).arg(var.new_plate);
            
        }
        licensePlateRecognitionResults(newPlate);
    }
}
void CameraHandle::findIp(QString &ip){
    ip=QString::fromStdString(loginParam->sDevId);
}

void CameraHandle::findFirmwareVersion(QString &firmwareVersion){
    char szOutBuffer[1024] = { 0 };
    int nLen = sizeof(szOutBuffer);;
    int nResult = XSDK_DevGetSysConfigSyn(hDevice, JK_SystemInfo, szOutBuffer, &nLen, 3000, JK_SystemInfo_MsgId);
    
    if (nResult >= 0)
    {
        XSDK_CFG::SystemInfo cfg;
        cfg.Parse(szOutBuffer);
        const char* SoftWareVersion = cfg.SoftWareVersion.ToString();
        firmwareVersion=QString::fromStdString(SoftWareVersion);
    }
}
void CameraHandle::pushRecordToCloud(int id, int recognitionType, QString ossUrl){
    HttpService httpService(ossUrl);
    Common & instace= Common::getInstance();
    auto map= getCurrentData();
    QString videoPath= map.at("downloadFileName");
    QString access_key_id= map.at("access_key_id");
    QString access_key_secret= map.at("access_key_secret");
    QString bucket= map.at("bucket");
    QString securityToken=map.at("security_token");
    vides_data::response*res=httpService.httpUploadFile(videoPath,access_key_id,access_key_secret,bucket,securityToken);
    if(res->code==0){
        httpService.setHttpUrl(httpUrl);
        vides_data::response*  reco=httpService.httpPostRecord(id,recognitionType,sSn,
                                                               ossUrl);
        if(reco->code!=0){
            qInfo()<<"识别录像地址上传失败";
        }
        instace.deleteObj(reco);
    }
    instace.deleteObj(res);
    
}

void CameraHandle::licensePlateRecognitionResults(vides_data::requestLicensePlate &location){
    Common & instace= Common::getInstance();
    HttpService httpService(httpUrl);
    std::list<vides_data::responseRecognitionData> result;
    vides_data::response* resp = httpService.httpLicensePlateRecognition(location, result);
    
    if (resp->code != 0) {
        if(resp->msg=="TimeoutError")  {
            for (auto& plate : location.plates) {
                plate.img.clear();
            }
            httpService.setHttpUrl(httpUrl);
            vides_data::response* img_resp = httpService.httpLicensePlateRecognition(location, result);
            if (img_resp->code != 0) {
                qInfo()<<QString("SN(%1): 车牌不加图片上传失败:失败信息%2").arg(sSn).arg(img_resp->msg);
            }else{
                qInfo()<<QString("SN(%1): 车牌不加图片上传成功").arg(sSn);
            }
            instace.deleteObj(img_resp);
        }else{
            qInfo()<<QString("SN(%1): 车牌识别结果上传失败:失败信息%2").arg(sSn).arg(resp->msg);
            // 在达到最大重试次数且仍然没有成功的情况下执行相应的处理逻辑
        }
        
    }
    instace.deleteObj(resp);
}

bool CameraHandle::isWifiConnect(XSDK_HANDLE hDevice,XSDK_CFG::NetWork_Wifi &cfg){
    char szOutBuffer[4000] = { 0 };
    int  nInOutSize = sizeof(szOutBuffer);
    
    // 获取并解析配置
    int nResult = XSDK_DevGetSysConfigSyn(hDevice, JK_NetWork_Wifi, szOutBuffer, &nInOutSize, 3000, EXCMD_CONFIG_GET);
    qInfo()<<szOutBuffer;
    
    if (nResult >= 0) {
        cfg.Parse(szOutBuffer);
        return  strlen(cfg.SSID.Value())>0;
    } else {
        printf("Failed to get Wi-Fi configuration. Error code: %d\n", nResult);
        return  false;
    }
}

void CameraHandle::printWifi(XSDK_HANDLE hDevice,XSDK_CFG::NetWork_Wifi &cfg){
    char szOutBuffer[4000] = { 0 };
    int  nInOutSize = sizeof(szOutBuffer);
    
    // 获取并解析配置
    int nResult = XSDK_DevGetSysConfigSyn(hDevice, JK_NetWork_Wifi, szOutBuffer, &nInOutSize, 3000, EXCMD_CONFIG_GET);
    qInfo()<<szOutBuffer;
    
    if (nResult >= 0) {
        cfg.Parse(szOutBuffer);
    } else {
        printf("Failed to get Wi-Fi configuration. Error code: %d\n", nResult);
    }
}


/**
 * @brief CameraHandle::resetGb28181
 * 1. 关闭对应摄像头GB28181
2. 修改设备IP并保存当前IP
3. 定时（增加配置 默认5s）后修改为原IP（保证本地NVR可用）
4. 启动GB28181
需注意和定时任务对比GB28181配置冲突处理
需确认修改IP后抓图是否正常，如不正常需在命令开始前增加删除句柄，命令完成后增加句柄以保证抓图实时性
 */
int CameraHandle::resetGb28181(){
    NonConnectedCameraHandle *connectedCameraHandle =NonConnectedCameraHandle::getInstance();
    int old=hDevice;
    MainWindow::sp_this->setIsResetting(true);
    bool is_wifi=false;
    ScopeSemaphoreExit guard([]() {
        MainWindow::sp_this->setIsResetting(false);
    });
    int flg=this->updateSdkDevStatus(false);
    if(flg<0){
        qInfo()<<QString("SN(%1): GB28181关失败:%2").arg(sSn).arg(flg);
        return  -1;
    }
    QString ip=QString::fromUtf8(loginParam->sDevId);
    QString reachableIp= vides_data::findReachableIp();
    if (!reachableIp.isEmpty()) {
        qInfo()<<QString("SN(%1): 未使用的IP地址%2").arg(sSn).arg(reachableIp);
    } else {
        qInfo()<<QString("SN(%1): 找不到可使用的IP地址").arg(sSn);
        return -1;
    }
    this->hDevice=-1;
    MainWindow::sp_this->modifySnMapIp(sSn,url);
    vides_data::localDevice device;
    device.reachableIp=reachableIp;
    device.sSn=sSn;

    bool result= connectedCameraHandle->changeCameraIp(device);
    int newHandle=-1;
    if(!result ){
        result=connectedCameraHandle->wifiChangeIp(reachableIp,false,old,sSn);
        is_wifi=true;
        if(result){
            //老句柄抓图不正常了
            int sdk_handle=this->sdkDevLoginSyn(reachableIp,loginParam->nDevPort,loginParam->sUserName,loginParam->sPassword,3000);
            if(sdk_handle<0){
                qInfo()<<QString("SN(%1): WIFI新句柄生成失败").arg(sSn);
                return -1;
            }else {
                qInfo()<<QString("SN(%1): WIFI新句柄生成成功").arg(sSn);
                newHandle=sdk_handle;
                this->hDevice=-1;
                XSDK_DevLogout(old);
            }
        }
    }
    // 阻塞等待5秒
    QThread::sleep(5);
    
    QString old_ip;
    MainWindow::sp_this->findSnMapIp(this->sSn,old_ip);
    if(old_ip.length()>0){
        if(is_wifi){
            result=connectedCameraHandle->wifiChangeIp(old_ip,true,newHandle,sSn);
            int sdk_handle=this->sdkDevLoginSyn(old_ip,loginParam->nDevPort,loginParam->sUserName,loginParam->sPassword,3000);
            if(sdk_handle<0){
                qInfo()<<QString("SN(%1): WIFI新句柄生成失败").arg(sSn);
            }else {
                XSDK_DevLogout(newHandle);
                qInfo()<<QString("SN(%1): WIFI新句柄生成成功").arg(sSn);

            }
        }else {
            device.reachableIp=old_ip;
            device.sSn=sSn;
            bool result= connectedCameraHandle->changeCameraIp(device);
            if(result){
                int sdk_handle=this->sdkDevLoginSyn(old_ip,loginParam->nDevPort,loginParam->sUserName,loginParam->sPassword,3000);
                if(sdk_handle<0){
                    qInfo()<<QString("SN(%1): 有线新句柄生成失败").arg(sSn);
                }else {
                    XSDK_DevLogout(old);
                    qInfo()<<QString("SN(%1): 有线新句柄生成成功").arg(sSn);

                }
            }
        }
    }
    
    return 1;//this->updateSdkDevStatus(true);
    
}

bool CameraHandle::sdkWifi(QString &pwd,QString &ssid){
    Common & instace= Common::getInstance();
    XSDK_CFG::NetWork_Wifi wif;
    printWifi(hDevice,wif);
    
    QByteArray && byPwd = pwd.toUtf8();
    const char * cpwd= byPwd.data();
    wif.Keys.SetValue(cpwd);

    QString reachableIp= vides_data::findReachableIp();
    QString hex=instace.DecIpToHexIp(reachableIp);
    QByteArray && byJson = ssid.toUtf8();

    const char * cssid= byJson.data();
    wif.SSID.SetValue(cssid);
    wif.Enable.SetValue(true);
    wif.KeyType.SetValue(1);
    wif.EncrypType.SetValue("AES");
    wif.Auth.SetValue("WPA2PSK");
    QByteArray && byHex = hex.toUtf8();
    const char * c_hex= byHex.data();
    wif.HostIP.SetValue(c_hex);
    //wif.HostIP.SetValue(newc_ip);
    const char* wipCfg = wif.ToString();
    qInfo()<<"wipCfg==>"<<wipCfg;

    char szOutBuffer[512] = { 0 };
    int nLen = sizeof(szOutBuffer);
    int res =XSDK_DevSetSysConfigSyn(hDevice, JK_NetWork_Wifi, wipCfg, strlen(wipCfg), szOutBuffer, &nLen, 3000, EXCMD_CONFIG_SET);
    qInfo()<<QString("SN(%1): 修改WIFI结果:%2").arg(sSn).arg(res);
    if(res<0){
        qInfo()<<QString("SN(%1): 修改wifi失败:%2").arg(sSn).arg(res);
        return false;
    }
    return true;
}

void CameraHandle::sdkDevSystemTimeZoneSyn(QString &time){
    QByteArray bTime =time.toUtf8();
    const char* cTime=bTime.data();
    char outBuffer[512] = { 0 };
    int nInOutBufSize = sizeof(outBuffer);
    const char* zoneCfg ="{ \"FirstUserTimeZone\" : \"true\", \"OPTimeSetting\" : \"800\" }";
    
    int res = XSDK_DevSetSysConfigSyn(hDevice, JK_System_TimeZone, zoneCfg, strlen(zoneCfg), outBuffer, &nInOutBufSize, 3000, EXCMD_CONFIG_GET);
    if(res<0){
        qInfo()<<QString("SN(%1): FirstUserTimeZone 修改失败").arg(sSn);
        
    }
    res=XSDK_DevSynTime(hDevice,cTime,0);
    if(res<0){
        qInfo()<<QString("SN(%1): sdkDevSystemTimeZoneSyn修改失败").arg(sSn);
    }
}

//录像设置
void CameraHandle::sdkRecordCfg(const char * recordJson){
    char szOutBuffer[512] = { 0 };
    int nLen = sizeof(szOutBuffer);;
    int res=XSDK_DevSetSysConfigSyn(hDevice,JK_Record,recordJson,strlen(recordJson),szOutBuffer,&nLen,3000,EXCMD_CONFIG_SET);
    if(res<0){
        qInfo()<<QString("SN(%1): sdkRecordCfg 录像设置->修改失败").arg(sSn);
        
    }
}
//配置编码设置
void CameraHandle::sdkEncodeCfg(const char* pCfg){
    char szOutBuffer[512] = { 0 };
    int nLen = sizeof(szOutBuffer);
    int res=XSDK_DevSetSysConfigSyn(hDevice,JK_Simplify_Encode,pCfg,strlen(pCfg),szOutBuffer,&nLen,3000,EXCMD_CONFIG_SET);
    if(res<0){
        qInfo()<<QString("SN(%1): sdkEncodeCfg 配置编码设置->修改失败").arg(sSn);
        
    }
}

int CameraHandle::updateSdkDevStatus(bool status){
    
    this->isOperateGb28181.store(true, std::memory_order_release);
    ScopeSemaphoreExit streamGuard([this]() {
        isOperateGb28181.store(false, std::memory_order_release);
    });
    
    char szOutBuffer[40960]={ 0 };
    int  nInOutSize = sizeof(szOutBuffer);
    int res= XSDK_DevGetSysConfigSyn(hDevice,JK_NetWork_SPVMN,szOutBuffer,&nInOutSize,4000,EXCMD_CONFIG_GET);
    if(res<0){
        qInfo()<<QString("SN(%1): GB28181可远程开关").arg(sSn);
        return 0 ;
    }
    XSDK_CFG::NetWork_SPVMN config;
    config.Parse(szOutBuffer);
    config.bCsEnable.SetValue(status);
    const char* pCfg = config.ToString();
    sdkDevSpvMn(pCfg);
    return res;
}
void CameraHandle::updateSdkDevSpvMn(vides_data::responseGb28181 *gb28181){
    if(isOperateGb28181.load(std::memory_order_acquire)){
        qInfo()<<QString("SN(%1): mqtt正在操作GB28181").arg(sSn);
        return ;
    }
    char szOutBuffer[40960]={ 0 };
    int  nInOutSize = sizeof(szOutBuffer);
    int res= XSDK_DevGetSysConfigSyn(hDevice,JK_NetWork_SPVMN,szOutBuffer,&nInOutSize,4000,EXCMD_CONFIG_GET);
    if (res >= 0)
    {
        XSDK_CFG::NetWork_SPVMN config;
        config.Parse(szOutBuffer);
        const char* Camreaid = config.Camreaid.ToString();
        int iHsIntervalTime = config.iHsIntervalTime.ToInt();
        int iRsAgedTime = config.iRsAgedTime.ToInt();
        int sCsPort = config.sCsPort.ToInt();
        const char* szConnPass = config.szConnPass.ToString();
        const char* szCsIP = config.szCsIP.ToString();
        const char* szDeviceNO = config.szDeviceNO.ToString();
        const char* szServerDn = config.szServerDn.ToString();
        const char* szServerNo = config.szServerNo.ToString();
        bool  isEqual = (szCsIP == gb28181->sip_ip &&
                         sCsPort == gb28181->sip_port &&
                         szServerNo == gb28181->serial &&
                         szServerDn ==gb28181->realm &&
                         iRsAgedTime == gb28181->register_validity &&
                         iHsIntervalTime == gb28181->heartbeat_interval &&
                         szConnPass == gb28181->password &&
                         szDeviceNO == gb28181->device_id &&
                         Camreaid == gb28181->channel_id);
        if(!isEqual){
            config.Camreaid.InitArraySize(64);
            
            for (int i = 1; i <= 64; ++i) {
                if (i == 1) {
                    QByteArray b_StrValue = gb28181->channel_id.toUtf8();
                    const char* str_Value = b_StrValue.constData();
                    JStrObj* newCameraId = &config.Camreaid[i - 1];
                    newCameraId->operator=(str_Value);
                } else {
                    QString str("3402000000131000001" + QString::number(i, 10).rightJustified(2, '0'));
                    QByteArray b_Str = str.toUtf8();
                    const char* s_ct = b_Str.constData();
                    JStrObj* newCameraId = &config.Camreaid[i - 1];
                    newCameraId->operator=(s_ct);
                }
            }
            QByteArray && bSip_ip=  gb28181->sip_ip.toUtf8();
            char* sip_ip = bSip_ip.data();
            config.szCsIP.SetValue(sip_ip);
            
            QByteArray && bSzServerNo=gb28181->serial.toUtf8();
            char* sz_ServerNo = bSzServerNo.data();
            config.szServerNo.SetValue(sz_ServerNo);
            
            config.sCsPort.SetValue(gb28181->sip_port);
            config.sUdpPort.SetValue(5060);
            
            QByteArray && bSzServerDn=gb28181->realm.toUtf8();
            char* sz_ServerDn = bSzServerDn.data();
            config.szServerDn.SetValue(sz_ServerDn);
            
            config.bCsEnable.SetValue(true);
            
            config.iRsAgedTime.SetValue(gb28181->register_validity);
            config.iHsIntervalTime.SetValue(gb28181->heartbeat_interval);
            
            QByteArray && bSzConnPass=gb28181->password.toUtf8();
            char* sz_connPass = bSzConnPass.data();
            config.szConnPass.SetValue(sz_connPass);
            
            QByteArray && bDevice_id=gb28181->device_id.toUtf8();
            char* cdevice_id = bDevice_id.data();
            config.szDeviceNO.SetValue(cdevice_id);
            
            const char* pCfg = config.ToString();
            sdkDevSpvMn(pCfg);
        }
    }
    
}

void CameraHandle::sdkDevSpvMn(const char *spvMn){
    char szOutBuffer[512] = { 0 };
    int nLen = sizeof(szOutBuffer);
    int res=XSDK_DevSetSysConfigSyn(hDevice,JK_NetWork_SPVMN,spvMn,strlen(spvMn),szOutBuffer,&nLen,3000,EXCMD_CONFIG_SET);
    if(res<0){
        qInfo() <<sSn<< ":sdkDevSpvMn 28181->修改失败"<<res;
    }
}
int CameraHandle::deviceReboot(){
    int nRet=0;
    XSDK_CFG::OPMachine cfg;
    cfg.Action.SetValue("Reboot");
    
    const char* pCfg = cfg.ToString();
    nRet = XSDK_DevSetSysConfig(hDevice, JK_OPMachine, pCfg, strlen(pCfg), 1, 3000, EXCMD_SYSMANAGER_REQ);
    if(nRet<0){
        qInfo() << sSn<<":重启相机失败"<<nRet;
        return 0 ;
    }
    QString ip=QString::fromUtf8(loginParam->sDevId);
    MainWindow::sp_this->clearOfflineCameraHandle(ip,loginParam->nDevPort);
    return nRet;
}

int CameraHandle::deviceShutdown()
{
    int nRet = 0;
    
    XSDK_CFG::OPMachine cfg;
    cfg.Action.SetValue("Shutdown");
    
    const char* pCfg = cfg.ToString();
    nRet = XSDK_DevSetSysConfig(hDevice, JK_OPMachine, pCfg, strlen(pCfg), 1, 3000, EXCMD_SYSMANAGER_REQ);
    if(nRet<0){
        qInfo()<<QString("SN(%1): 设备关机失败:%2").arg(sSn).arg(nRet);
        return 0;
    }
    
    QString ip=QString::fromUtf8(loginParam->sDevId);
    MainWindow::sp_this->clearOfflineCameraHandle(ip,loginParam->nDevPort);
    
    return nRet;
}
bool CameraHandle::polygonsOverlap( ParkingSpaceInfo &poly1,  ParkingSpaceInfo &poly2) {
    
    QPolygonF realPolygon;
    realPolygon << QPointF(poly1.getArea().topLeftCornerX, poly1.getArea().topLeftCornerY)
                << QPointF(poly1.getArea().bottomLeftCornerX, poly1.getArea().bottomLeftCornerY)
                << QPointF(poly1.getArea().bottomRightCornerX, poly1.getArea().bottomRightCornerY)
                << QPointF(poly1.getArea().topRightCornerX, poly1.getArea().topRightCornerY);
    QPainterPath  realPath;
    realPath.addPolygon(realPolygon);
    
    
    QPolygonF spacePolygon;
    spacePolygon << QPointF(poly2.getArea().topLeftCornerX, poly2.getArea().topLeftCornerY)
                 << QPointF(poly2.getArea().bottomLeftCornerX, poly2.getArea().bottomLeftCornerY)
                 << QPointF(poly2.getArea().bottomRightCornerX, poly2.getArea().bottomRightCornerY)
                 << QPointF(poly2.getArea().topRightCornerX, poly2.getArea().topRightCornerY);
    QPainterPath spacePath;
    spacePath.addPolygon(spacePolygon);
    
    // 使用intersected方法获取两个路径的交集
    QPainterPath intersection = realPath.intersected(spacePath);
    
    // 如果交集不为空，则两个多边形重叠
    return !intersection.isEmpty();
}

double CameraHandle::calculateIntersectionArea(const QPolygonF &polygon1, const QPolygonF &polygon2) {
    QPolygonF intersection = polygon1.intersected(polygon2);
    int n = intersection.count();
    
    if (n < 3) return 0.0;
    
    // 构建增量式凸包
    std::vector<QPointF> convexHullPoints;
    for (const QPointF& point : intersection) {
        while (convexHullPoints.size() >= 2 && ccw(convexHullPoints[convexHullPoints.size() - 2], convexHullPoints.back(), point) <= 0) {
            convexHullPoints.pop_back();
        }
        convexHullPoints.push_back(point);
    }
    
    double area = 0.0;
    for (size_t i = 0; i < convexHullPoints.size(); ++i) {
        size_t j = (i + 1) % convexHullPoints.size();
        area += (convexHullPoints[i].x() * convexHullPoints[j].y() - convexHullPoints[j].x() * convexHullPoints[i].y());
    }
    return qAbs(area) / 2.0;
}

// 计算叉乘
double CameraHandle::ccw(const QPointF& a, const QPointF& b, const QPointF& c) {
    return (b.x() - a.x()) * (c.y() - a.y()) - (c.x() - a.x()) * (b.y() - a.y());
}
//顺时针
bool CameraHandle::isClockwise(const std::vector<cv::Point2f>& polygon) {
    float sum = 0.0;
    for (size_t i = 0; i < polygon.size(); ++i) {
        cv::Point2f current = polygon[i];
        cv::Point2f next = polygon[(i + 1) % polygon.size()];
        sum += (next.x - current.x) * (next.y + current.y);
    }
    return sum > 0;
}

void CameraHandle::faceUniformOverlap(std::map<QString, vides_data::requestFaceReconition>& mapFaces,
                                      std::vector<vides_data::ParkingArea>& uniforms,
                                      std::list<QString>& outUniforms) {
    const float epsilon = 1e-5;
    
    for (size_t i = 0; i < uniforms.size(); ++i) {
        std::vector<cv::Point2f> uniformAreaPoints = {
            cv::Point2f(uniforms[i].topLeftCornerX, uniforms[i].topLeftCornerY),
            cv::Point2f(uniforms[i].topRightCornerX, uniforms[i].topRightCornerY),
            cv::Point2f(uniforms[i].bottomRightCornerX, uniforms[i].bottomRightCornerY),
            cv::Point2f(uniforms[i].bottomLeftCornerX, uniforms[i].bottomLeftCornerY)
        };
        
        if (!isClockwise(uniformAreaPoints)) {
            std::reverse(uniformAreaPoints.begin(), uniformAreaPoints.end());
        }
        
        float maxIntersectionArea = 0.0;
        QString maxFaceId;
        
        for (auto iter = mapFaces.begin(); iter != mapFaces.end(); ++iter) {
            QString faceId = iter->first; // 人员id
            vides_data::requestFaceReconition faceValue = iter->second;
            
            std::vector<cv::Point2f> faceAreaPoints = {
                cv::Point2f(faceValue.area.top_left_corner_x, faceValue.area.top_left_corner_y),
                cv::Point2f(faceValue.area.top_right_corner_x, faceValue.area.top_right_corner_y),
                cv::Point2f(faceValue.area.bottom_right_corner_x, faceValue.area.bottom_right_corner_y),
                cv::Point2f(faceValue.area.bottom_left_corner_x, faceValue.area.bottom_left_corner_y)
            };
            
            if (!isClockwise(faceAreaPoints)) {
                std::reverse(faceAreaPoints.begin(), faceAreaPoints.end());
            }
            
            std::vector<cv::Point2f> intersection;
            float intersectionArea = cv::intersectConvexConvex(uniformAreaPoints, faceAreaPoints, intersection, true);
            
            if (intersectionArea > maxIntersectionArea) {
                maxIntersectionArea = intersectionArea;
                maxFaceId = faceId;
            }
        }
        
        if (!maxFaceId.isEmpty() && maxIntersectionArea > epsilon) {
            outUniforms.push_back(maxFaceId);
        }
    }
}


bool CameraHandle::isAnyOverlap(ParkingSpaceInfo *parkArea, std::vector<vides_data::ParkingArea> &currentPlates) {
    // 将parkArea转换为cv::Point2f的顶点列表
    std::vector<cv::Point2f> parkAreaPoints = {
        cv::Point2f(parkArea->getArea().topLeftCornerX, parkArea->getArea().topLeftCornerY),
        cv::Point2f(parkArea->getArea().topRightCornerX, parkArea->getArea().topRightCornerY),
        cv::Point2f(parkArea->getArea().bottomRightCornerX, parkArea->getArea().bottomRightCornerY),
        cv::Point2f(parkArea->getArea().bottomLeftCornerX, parkArea->getArea().bottomLeftCornerY)
    };
    
    if (!isClockwise(parkAreaPoints)) {
        std::reverse(parkAreaPoints.begin(), parkAreaPoints.end());
    }
    // 遍历currentPlates中的每一个区域，检查是否存在重合
    for (const auto &plateArea : currentPlates) {
        // 构建当前plateArea的顶点列表
        std::vector<cv::Point2f> plateAreaPoints = {
            cv::Point2f(plateArea.topLeftCornerX, plateArea.topLeftCornerY),
            cv::Point2f(plateArea.topRightCornerX, plateArea.topRightCornerY),
            cv::Point2f(plateArea.bottomRightCornerX, plateArea.bottomRightCornerY),
            cv::Point2f(plateArea.bottomLeftCornerX, plateArea.bottomLeftCornerY)
        };
        
        if (!isClockwise(plateAreaPoints)) {
            std::reverse(plateAreaPoints.begin(), plateAreaPoints.end());
        }
        
        std::vector<cv::Point2f> intersection;
        // 使用cv::intersectConvexConvex计算交集
        float  intersectionArea= cv::intersectConvexConvex(parkAreaPoints, plateAreaPoints, intersection, true);
        const float epsilon = 1e-5;
        // 如果交集不为空，说明有重合
        if (intersectionArea>epsilon && !intersection.empty()) {
            return true;
        }
    }
    
    // 所有车牌区域均与parkArea无重合
    return false;
}



int CameraHandle::findPointRegion(ParkingSpaceInfo &prakArea) {
    float maxIntersectionArea = 0.0;
    int areaOfMaxIntersection = -1;
    std::vector<cv::Point2f> currentPolygonPoints = {
        cv::Point2f(prakArea.getArea().topLeftCornerX, prakArea.getArea().topLeftCornerY),
        cv::Point2f(prakArea.getArea().topRightCornerX, prakArea.getArea().topRightCornerY),
        cv::Point2f(prakArea.getArea().bottomRightCornerX, prakArea.getArea().bottomRightCornerY),
        cv::Point2f(prakArea.getArea().bottomLeftCornerX, prakArea.getArea().bottomLeftCornerY)
    };
    
    if (!isClockwise(currentPolygonPoints)) {
        std::reverse(currentPolygonPoints.begin(), currentPolygonPoints.end());
    }
    
    qInfo() << "Current Polygon Points:";
    for (const auto& point : currentPolygonPoints) {
        qInfo() << "(" << point.x << ", " << point.y << ")";
    }
    
    for (ParkingSpaceInfo *info : parkingSpaceInfos) {
        std::vector<cv::Point2f> polygonInfoPoints = {
            cv::Point2f(info->getArea().topLeftCornerX, info->getArea().topLeftCornerY),
            cv::Point2f(info->getArea().topRightCornerX, info->getArea().topRightCornerY),
            cv::Point2f(info->getArea().bottomRightCornerX, info->getArea().bottomRightCornerY),
            cv::Point2f(info->getArea().bottomLeftCornerX, info->getArea().bottomLeftCornerY)
        };
        
        // Ensure polygonInfoPoints are in clockwise order
        if (!isClockwise(polygonInfoPoints)) {
            std::reverse(polygonInfoPoints.begin(), polygonInfoPoints.end());
        }
        
        qInfo() << "Polygon Info Points for Space " << info->getSpaceIndex() << ":";
        for (const auto& point : polygonInfoPoints) {
            qInfo() << "(" << point.x << ", " << point.y << ")";
        }
        
        std::vector<cv::Point2f> intersection;
        float intersectionArea = cv::intersectConvexConvex(polygonInfoPoints, currentPolygonPoints, intersection, true);
        
        const float epsilon = 1e-5;
        if (intersectionArea > epsilon && intersectionArea > maxIntersectionArea) {
            maxIntersectionArea = intersectionArea;
            areaOfMaxIntersection = info->getSpaceIndex();
        }
    }
    return areaOfMaxIntersection;
}


int CameraHandle::determineArea(ParkingSpaceInfo &prakArea){
    double maxIntersectionArea = 0.0;
    int areaOfMaxIntersection = -1;
    QPolygon currentPolygon;
    currentPolygon<< QPoint(prakArea.getArea().topLeftCornerX, prakArea.getArea().topLeftCornerY)
                  << QPoint(prakArea.getArea().bottomLeftCornerX,prakArea.getArea().bottomLeftCornerY)
                  << QPoint(prakArea.getArea().bottomRightCornerX, prakArea.getArea().bottomRightCornerY)
                  << QPoint(prakArea.getArea().topRightCornerX, prakArea.getArea().topRightCornerY);
    
    for (ParkingSpaceInfo *info : parkingSpaceInfos) {
        QPolygon polygonInfo; // 移动定义到这里，确保每次迭代时重新初始化
        polygonInfo << QPoint(info->getArea().topLeftCornerX, info->getArea().topLeftCornerY)
                    << QPoint(info->getArea().bottomLeftCornerX, info->getArea().bottomLeftCornerY)
                    << QPoint(info->getArea().bottomRightCornerX, info->getArea().bottomRightCornerY)
                    << QPoint(info->getArea().topRightCornerX, info->getArea().topRightCornerY);
        
        if (polygonsOverlap(prakArea, *info)) {
            
            double currentIntersection = calculateIntersectionArea(polygonInfo, currentPolygon);
            
            if (currentIntersection > maxIntersectionArea) {
                maxIntersectionArea = currentIntersection;
                areaOfMaxIntersection = info->getSpaceIndex();
            }
        }
    }
    
    return areaOfMaxIntersection;
}

void CameraHandle::initAlgorithmPermissions(__uint8_t algorithm){
    if(algorithm!=algorithmPermissions){
        this->algorithmPermissions=algorithm;
    }
}
void CameraHandle::initParkingSpaceInfo(const std::list<vides_data::responseArea> &areas){
    int index = 1;
    for (auto area = areas.begin(); area != areas.end(); ++area) {
        ParkingSpaceInfo* info = new ParkingSpaceInfo();
        vides_data::ParkingArea pArea;
        pArea.bottomLeftCornerX = area->bottom_left_corner_x;
        pArea.bottomLeftCornerY = area->bottom_left_corner_y;
        
        pArea.topLeftCornerX = area->top_left_corner_x;
        pArea.topLeftCornerY = area->top_left_corner_y;
        
        pArea.topRightCornerX = area->top_right_corner_x;
        pArea.topRightCornerY = area->top_right_corner_y;
        pArea.bottomRightCornerX = area->bottom_right_corner_x;
        pArea.bottomRightCornerY = area->bottom_right_corner_y;
        
        info->setArea(pArea);
        if (parkMap.find(index) == parkMap.end()) {
            info->setSpaceIndex(index); // Assuming this method sets the space index
            parkMap[index] = info;
            parkingSpaceInfos.push_back(info);
        }
        index++;
    }
}
bool CameraHandle::compareLists(const std::list<vides_data::responseArea>& newAreas) {
    std::list<vides_data::ParkingArea> areas;
    for (const auto& spaceInfoPtr : parkingSpaceInfos) {
        if (!spaceInfoPtr) {
            continue;
        }
        vides_data::ParkingArea area = spaceInfoPtr->getArea();
        areas.push_back(area);
    }
    // 检查两个列表的大小是否相同
    if (newAreas.size() != areas.size()) {
        return false;
    }
    
    auto itResponse = newAreas.begin();
    auto itParking = areas.begin();
    
    // 逐个比较 responseArea 和 ParkingArea 对象是否相同
    while (itResponse != newAreas.end() && itParking != areas.end()) {
        if (itResponse->bottom_right_corner_x != itParking->bottomRightCornerX ||
                itResponse->bottom_right_corner_y != itParking->bottomRightCornerY ||
                itResponse->bottom_left_corner_x != itParking->bottomLeftCornerX ||
                itResponse->bottom_left_corner_y != itParking->bottomLeftCornerY ||
                itResponse->top_left_corner_x != itParking->topLeftCornerX ||
                itResponse->top_left_corner_y != itParking->topLeftCornerY ||
                itResponse->top_right_corner_x != itParking->topRightCornerX ||
                itResponse->top_right_corner_y != itParking->topRightCornerY) {
            return false; // 如果任意一个元素不匹配，则返回 false
        }
        
        ++itResponse;
        ++itParking;
    }
    
    return true;
}
void CameraHandle::updateParkMapAndParkingSpaceInfos(const std::list<vides_data::responseArea>&newAreas){
    Common & instace= Common::getInstance();
    parkingSpaceInfos.clear();
    for(auto iter = parkMap.begin(); iter != parkMap.end(); ++iter) {
        instace.deleteObj( iter->second);
    }
    parkMap.clear();
    initParkingSpaceInfo(newAreas);
}

