#include "CameraHandle.h"
#include "TaskRunnable.h"
#include "HumanDetection.h"
#include "ScopeSemaphoreExit.h"
#include <QRegularExpression>
CameraHandle::CameraHandle(){

}
CameraHandle::CameraHandle(QString &url, QString &httpUrl, QString &sSn, int &channel,const QString &modelPaths, float carConfidence,int imageSave)
    : 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),
      semaphore(1) {
    connect(this, SIGNAL(afterDownloadFile(int,int,QString)), this, SLOT(pushRecordToCloud(int,int,QString)),Qt::QueuedConnection);
    detector = TCV_CreateHumanDetector();
    // 设置检测得分阈值 默认0.5
    TCV_HumanDetectorSetScoreThreshold(detector, 0.8f);

    HLPR_ContextConfiguration configuration = {0};
    QByteArray && by_mpath=modelPaths.toUtf8();
    char* m_path=by_mpath.data();
    configuration.models_path = m_path;
    configuration.max_num = 5;
    configuration.det_level = DETECT_LEVEL_LOW;
    configuration.use_half = false;
    configuration.nms_threshold = 0.5f;
    configuration.rec_confidence_threshold = carConfidence;
    configuration.box_conf_threshold = 0.30f;
    configuration.threads = 1;
    ctx = HLPR_CreateContext(&configuration);

}

CameraHandle::~CameraHandle() {
    Common & instace= Common::getInstance();
    dev_snap_syn_timer->stop();
    instace.deleteObj(dev_snap_syn_timer);
    instace.deleteObj(loginParam);
    instace.deleteObj(sxMediaFaceImageReq);
    if(detector!=nullptr){
        TCV_ReleaseHumanDetector(detector);
        detector=nullptr;
    }
    for(auto iter = parkMap.begin(); iter != parkMap.end(); ++iter) {
        instace.deleteObj( iter->second);
    }
    parkMap.clear();
    QThreadPool::globalInstance()->waitForDone();

}

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() << "登录设备失败";
        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)
        {
            qDebug()<<"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);
                    qDebug() << "ffmpeg process finished successfully.";
                } else {
                    qDebug() << "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::getCurrentFrame(std::vector<uchar> &buffer){
    MediaFaceImage* mediaFaceImage= MediaFaceImage::getInstance();
    mediaFaceImage->CameraImage(this->hDevice,this->channel,buffer);
}


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

    QThreadPool* threadPool = QThreadPool::globalInstance();
    threadPool->setMaxThreadCount(8);
    auto taskSyn = std::bind(&CameraHandle::sdkDevSnapSyn, this, hDevice, this->channel);


    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;
}

void CameraHandle::setCurrentFace(int currentFace){
    std::lock_guard<std::mutex> guard(faceMutex);
    this->currentFace=currentFace;
}
std::map<QString, QString>&CameraHandle::getCurrentData(){
    return currentData;
}
std::map<int, vides_data::responseRecognitionData>&CameraHandle::getVideoCurrentData(){
    return videoCurrentData;
}
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;
    qDebug() << "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() <<  "sdkDevSnapSyn:正在执行线程";
        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
    {
        qDebug() << "OnDevAlarmCallback[Dev:" << hObject << "][Event:" << szString << "]";
    }
    cv::Mat image;
    MediaFaceImage* mediaFaceImage= MediaFaceImage::getInstance();
    qint64 currentTime= QDateTime::currentSecsSinceEpoch();
    mediaFaceImage->FaceImageCallBack(hObject,this->channel,image);

    if (image.empty())
    {
        qInfo() << "Failed to read the image";
        return -1;
    }
    if (image.rows <= 0 || image.cols <= 0 || image.channels() <= 0) {
        qInfo() << "图像尺寸或通道数不正确，需排查原因";
        return -1;
    }
    updateImage(image, currentTime);
}

void CameraHandle::sdkDevSnapSyn(XSDK_HANDLE hDevice, int nChannel){
    if(hDevice<=0){
        qInfo() << "相机断线";
        return;
    }
    if (!semaphore.tryAcquire()) {
        qInfo() <<  "callbackFunction:正在执行线程";
        return ;
    }
    ScopeSemaphoreExit guard([this]() {
        semaphore.release();  // 释放信号量
    });
    cv::Mat image;
    MediaFaceImage* mediaFaceImage= MediaFaceImage::getInstance();
    qint64 currentTime= QDateTime::currentSecsSinceEpoch();
    int ret=mediaFaceImage->FaceImageCallBack(hDevice,nChannel, image);

    qDebug() << "SdkDevSnapSyn HTTP POST request to: " << sSn;
    if (ret < 0) {
        offlineCount++; // 累加计数器
        qDebug() << "offlineCount: " << loginParam->sDevId<<offlineCount;

        if (offlineCount >= 3) { // 判断是否连续3次返回0
            qInfo() << "设备离线";
            QString ip=QString::fromUtf8(loginParam->sDevId);
            MainWindow::sp_this->clearOfflineCameraHandle(ip,loginParam->nDevPort);
            // 执行离线处理逻辑
            // TODO: 可以在此处更新设备状态、发送告警通知等
            // 重置计数器，以便下次再次检测连续离线
            offlineCount = 0;
        }
    } else {
        // 如果不连续，则重置计数器
        offlineCount = 0;
    }
    if (image.empty())
    {
        qInfo() << "Failed to read the image";
        return ;
    }
    if (image.rows <= 0 || image.cols <= 0 || image.channels() <= 0) {
        qInfo() << "图像尺寸或通道数不正确，需排查原因";
        return ;
    }
    updateImage(image, currentTime);
}

void CameraHandle::setTimeoutMs(int timeoutMs){
    this->timeoutMs=timeoutMs;
}

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,std::map<int,RecognizedInfo>&exitAndMoMap){
    if (newInfo.getLicensePlate() != park->getCurrentPlate().getLicensePlate()) {
        int count = 0;
        for (auto& info : park->getQueue()) {
            if (info.getLicensePlate() == newInfo.getLicensePlate()) {
                count++;
            }
        }
        qDebug() << "不同的区域：" << park->getSpaceIndex() << "，数量：" << count;
        if (count >= 3) {
            //第一次进场 当前车牌就是进来这个，老车牌就是空
            if(park->getCurrentPlate().getLicensePlate().length()<=0){
                //进场
                park->setCurrentPlate(newInfo);
                result=Mobilization;
            }else {
                //当前为空，立场
                if(newInfo.getLicensePlate().length()<=0){
                    HumanDetection &humanDetection=HumanDetection::getInstance();
                    int car_size = humanDetection.findHuManCar(frame,1,detector);
                    qDebug()<<sSn<<":"<<"当前车形数量:"<<car_size;
                    if(car_size<=0){
                        //出场
                        park->setCurrentPlate(newInfo);
                        result=Exit;
                    }else{
                        park-> removeNoQueue();
                        qDebug()<<sSn<<":"<<"no出场:"<<car_size;
                    }
                }else{
                    qDebug()<<sSn<<":"<<"出场:"<<2;
                    qDebug()<<sSn<<":"<<"老车出场:"<<park->getCurrentPlate().getLicensePlate();
                    qDebug()<<sSn<<":"<<"老车出场:"<<park->getCurrentPlate().getLicensePlate();

                    //当前不为空，新车，新车入场，老车出场
                    exitAndMoMap[Exit]=park->getCurrentPlate();
                    exitAndMoMap[Mobilization]=newInfo;
                    park->setCurrentPlate(newInfo);
                    result=ExitAndMobilization;
                }
            }
        }
    }
}


void CameraHandle::updateImage(const cv::Mat & frame,qint64 currentTime){

    Common & instace= Common::getInstance();


    qDebug()<<"=============================>";
    static int i=0;
    printf("updateImage%d次\n", ++i);
    faceCount.fetch_add(1, std::memory_order_relaxed);
    qDebug()<<"faceCount==>"<<faceCount.load(std::memory_order_relaxed);

    int width = frame.cols;  // 获取图像宽度
    int height = frame.rows; // 获取图像高度
    qDebug()<<"frame 宽度:"<<width<<"frame 高度:"<<height;
    FaceReconition &faceRecognition = FaceReconition::getInstance();

    HumanDetection &humanDetection=HumanDetection::getInstance();
    LicensePlateRecognition &licensePlateRecogn =LicensePlateRecognition::getInstance();
    static int ii=0;
    printf("updateImage retryCount: %d \n", ++ii);
    //faceRecognition.search(frame,imageHandleList,names);
    QByteArray imgs;
    int faSize=humanDetection.findHuManCar(frame,0,detector);

    this->matToBase64(frame, imgs);
    HttpService httpService(httpUrl);
    if(currentFace!=faSize){
        if(faceCount.load(std::memory_order_relaxed)%face_frequency==0){
            vides_data::response* resp=httpService.httpPostFacePopulation(imgs,faSize,sSn,currentTime);
            if (resp->code!= 0) {
                qInfo()<<"人数变化推送信息推送失败";
            }
            instace.deleteObj(resp);
            currentFace=faSize;
        }
    }
    if(faSize>0){
        qDebug() << "faceRecognition.doesItExistEmployee Current thread ID: " << QThread::currentThreadId();
        std::list<vides_data::faceRecognitionResult>faces;
        faceRecognition.doesItExistEmployee(frame,faces);
        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);

                if (resp->code!= 0) {
                    qInfo()<<"识别人脸信息推送失败"<<face.id;
                }
                instace.deleteObj(resp);
            }
        }
    }
    QString lpNumber;
    vides_data::requestLicensePlate plate;
    plate.sn=sSn;

    //    return ;
    if(image_save==1){
        QString fileName= instace.getVideoOut().append(instace.getTimeString()+".jpg");
        bool success = cv::imwrite(fileName.toStdString(), frame);

        if (success) {
            qDebug() << "图片已成功保存至：" << fileName;
        } else {
            qDebug() << "图片保存失败!";
        }

    }

    licensePlateRecogn.licensePlateNumber(frame, lpNumber,plate,currentTime,ctx);
    std::map<int,RecognizedInfo>exitMoMap;
    vides_data::requestLicensePlate newPlate;
    newPlate.sn=sSn;
    qDebug()<<QString("识别的车牌号是:%1").arg(lpNumber);
    std::list<vides_data::LicensePlate>ps=plate.plates;
    int res=-1;
    this->matToBase64(frame, imgs);
    if(ps.size()==0){
        for (auto it = parkMap.begin(); it != parkMap.end(); ++it) {
            ParkingSpaceInfo* value = it->second;  // 获取值
            if(value->getQueue().size()>=10) {
                value->removeQueue();
            }
            RecognizedInfo recognizedInfo(lpNumber,QDateTime::currentSecsSinceEpoch(),"未知");
            value->addQueue(recognizedInfo);
            this->checkAndUpdateCurrentPlate(value,frame,recognizedInfo,res,exitMoMap);
            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{
        std::unordered_map<int, vides_data::LicensePlate> indexToLicensePlate;
        for (auto it_ps = ps.begin(); it_ps != ps.end(); ++it_ps) {
            vides_data::LicensePlate& currentPlate = *it_ps;
            ParkingSpaceInfo newcurrentPlate;
            newcurrentPlate.setArea(currentPlate.recognition);
            int index = this->findPointRegion(newcurrentPlate);
            qDebug()<<"识别的区域:"<<index;
            indexToLicensePlate[index] = currentPlate;
        }
        for (auto it = parkMap.begin(); it != parkMap.end(); ++it) {
            int key = it->first;
            ParkingSpaceInfo* value = it->second;  // 获取值
            if (indexToLicensePlate.count(key) > 0) {
                vides_data::LicensePlate recognition= indexToLicensePlate.at(key);
                RecognizedInfo recognizedInfo;
                if (recognition.new_color=="蓝牌" && recognition.new_plate.length() != 7) {
                    qDebug()<<"蓝牌车牌号:"<<recognition.new_plate<<"===>recognition.new_plate.length():"<<recognition.new_plate.length();
                    continue;
                } else if (recognition.new_color=="绿牌新能源" && recognition.new_plate.length() != 8) {
                    qDebug()<<"绿牌车牌号:"<<recognition.new_plate<<"===>recognition.new_plate.length():"<<recognition.new_plate.length();
                    continue;
                } else if (recognition.new_plate.length() < 7) {
                    qDebug()<<"非绿牌蓝牌车牌号:"<<recognition.new_plate<<"===>recognition.new_plate.length():"<<recognition.new_plate.length();
                    continue;
                }
                if(recognition.text_confidence>=instace.getCarConfidenceMax()){
                    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(recognition.new_plate,recognition.time,recognition.new_color);
                            value->addQueue(info);
                            recognizedInfo=std::move(info);
                        }
                        this->checkAndUpdateCurrentPlate(value,frame,recognizedInfo,res,exitMoMap);
                    }
                }
                if(recognition.text_confidence<=instace.getCarConfidenceMin()){
                    continue;
                }
                if(recognition.text_confidence>instace.getCarConfidenceMin()
                        && recognition.text_confidence<instace.getCarConfidenceMax())
                {
                    if(value->getQueue().size()>=10) {
                        value->removeQueue();
                    }
                    RecognizedInfo info(recognition.new_plate,recognition.time,recognition.new_color);
                    value->addQueue(info);
                    recognizedInfo=std::move(info);
                    this->checkAndUpdateCurrentPlate(value,frame,recognizedInfo,res,exitMoMap);
                }
                if (res == Exit || res == Mobilization) {
                    recognition.areaLocation=value->getArea();
                    recognition.img=imgs;
                    recognition.new_color=recognizedInfo.getColor();
                    newPlate.plates.push_back(std::move(recognition));
                }
                if(res==ExitAndMobilization){
                    if(exitMoMap.size()>0){
                        recognition.areaLocation=value->getArea();
                        recognition.img=imgs;
                        recognition.new_color=recognizedInfo.getColor();
                        newPlate.plates.push_back(std::move(recognition));

                        RecognizedInfo exitInfo=exitMoMap[Exit];
                        vides_data::LicensePlate oldInfo;
                        oldInfo.areaLocation=value->getArea();
                        oldInfo.img=imgs;
                        oldInfo.new_color=exitInfo.getColor();
                        oldInfo.new_plate=exitInfo.getLicensePlate();
                        oldInfo.time=exitInfo.getRecognizeTime();
                        newPlate.plates.push_back(std::move(oldInfo));
                    }
                }
            }else{
                if(value->getQueue().size()>=10) {
                    value->removeQueue();
                }
                RecognizedInfo recognizedInfo("", QDateTime::currentSecsSinceEpoch(), "未知");
                value->addQueue(recognizedInfo);
                int res;
                this->checkAndUpdateCurrentPlate(value, frame, recognizedInfo, res,exitMoMap);

                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();
                    current.recognition=value->getArea();
                    newPlate.plates.push_back(std::move(current));
                }
                if(res==ExitAndMobilization){
                    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));
                    RecognizedInfo exitInfo=exitMoMap[Exit];
                    vides_data::LicensePlate oldInfo;
                    oldInfo.areaLocation=value->getArea();
                    oldInfo.img=imgs;
                    oldInfo.new_color=exitInfo.getColor();
                    oldInfo.new_plate=exitInfo.getLicensePlate();
                    oldInfo.time=exitInfo.getRecognizeTime();
                    newPlate.plates.push_back(std::move(oldInfo));
                }
            }
        }
    }
    qDebug()<<QString("%1==>当前车牌数量:%2").arg(sSn).arg(ps.size());
    if(newPlate.plates.size()>0){
        licensePlateRecognitionResults(newPlate);
        foreach (auto var, plate.plates) {
            qDebug()<<QString("sn:%1 =>识别的车牌号是:%2").arg(sSn).arg(var.new_plate);
        }
    }
}

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();
    QByteArray imgs;
    int maxRetryCount = 2; // 最大重试次数
    int retryCount = 0; // 当前重试次数
    bool requestSuccess = false; // 标记请求是否成功
    while (retryCount < maxRetryCount && !requestSuccess) {
        HttpService httpService(httpUrl);
        std::list<vides_data::responseRecognitionData> result;
        vides_data::response*resp=  httpService.httpLicensePlateRecognition(location,result);

        if (resp->code == 0) {
            if(result.size()==0){
                return ;
            }
            vides_data::responseStsCredentials sts_credentials=HttpService::stsCredentials;
            QString oUrl = "http://" + sts_credentials.bucket + "." + sts_credentials.endpoint;
            currentData["ossUrl"] =oUrl;
            currentData["bucket"] = sts_credentials.bucket;
            currentData["access_key_id"] =sts_credentials.access_key_id;
            currentData["access_key_secret"] =sts_credentials.access_key_secret;
            currentData["security_token"]=sts_credentials.security_token;
            //            foreach (auto var, result) {
            //                vides_data::responseRecognitionData data;
            //                data.id=var.id;
            //                data.inTime=var.inTime;
            //                data.outTime=var.outTime;
            //                data.recognitionType=var.recognitionType;
            //                data.sn=var.sn;
            //                videoCurrentData[var.id]=data;

            //                sdkDownloadFileByTime(this->hDevice,var.id,
            //                                      instace.timestampToDateString(var.inTime),instace.timestampToDateString(var.outTime));
            //            }
            requestSuccess = true;
        } else {
            ++retryCount;
        }
        instace.deleteObj(resp);
    }
    if (!requestSuccess) {
        qInfo()<<"licensePlateRecognitionResults:车牌识别结果失败";
        // 在达到最大重试次数且仍然没有成功的情况下执行相应的处理逻辑
    }

}
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, 5000, EXCMD_CONFIG_GET);
    if(res<0){
        qInfo() << "FirstUserTimeZone:修改失败";
    }
    res=XSDK_DevSynTime(hDevice,cTime,0);
    if(res<0){
        qInfo() << "sdkDevSystemTimeZoneSyn:修改失败";
    }
}

//录像设置
void CameraHandle::sdkRecordCfg(const char * recordJson){

    qDebug()<<recordJson;
    char szOutBuffer[512] = { 0 };
    int nLen = sizeof(szOutBuffer);;
    int res=XSDK_DevSetSysConfigSyn(hDevice,JK_Record,recordJson,strlen(recordJson),szOutBuffer,&nLen,5000,EXCMD_CONFIG_SET);
    if(res<0){
        qInfo() << "sdkRecordCfg 录像设置->修改失败"<<res;
    }
}
//配置编码设置
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,5000,EXCMD_CONFIG_SET);
    if(res<0){
        qInfo() << "sdkEncodeCfg 配置编码设置->修改失败"<<res;
    }
}
void CameraHandle::sdkDevSpvMn(const char *spvMn){
    char szOutBuffer[512] = { 0 };
    int nLen = sizeof(szOutBuffer);
    qDebug()<<spvMn;
    int res=XSDK_DevSetSysConfigSyn(hDevice,JK_NetWork_SPVMN,spvMn,strlen(spvMn),szOutBuffer,&nLen,5000,EXCMD_CONFIG_SET);
    if(res<0){
        qInfo() << "sdkDevSpvMn 28181->修改失败"<<res;
    }
}
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());
}
int CameraHandle::findPointRegion(ParkingSpaceInfo &prakArea){
    //左下、右下、右上、左上。
    double 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)
    };
    qDebug() << "Current Polygon Points:";
    for (const auto& point : currentPolygonPoints) {
        qDebug() << "(" << 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)
        };
        // 打印 polygonInfoPoints 的值
        qDebug() << "Polygon Info Points for Space " << info->getSpaceIndex() << ":";
        for (const auto& point : polygonInfoPoints) {
            qDebug() << "(" << point.x << ", " << point.y << ")";
        }

        std::vector<cv::Point2f> intersection;
        double intersectionArea = cv::intersectConvexConvex(polygonInfoPoints, currentPolygonPoints, intersection, true);
        if (intersectionArea>0.0 && 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::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);
}
