#include "FaceRecognition.h"


FaceReconition::FaceReconition() {}

FaceReconition::~FaceReconition(){
    if (ctxHandle != nullptr) {
        HF_ReleaseFaceContext(ctxHandle);
        ctxHandle = nullptr;
    }
}

FaceReconition* FaceReconition::instance = nullptr;

void FaceReconition::initSourceImageMap(std::map<QString,QString>&maps,float confidence){
    featureRemove();
    HResult ret;
    // 初始化context
#if defined(__arm__) || defined(__ARM_ARCH)
    // ARM 平台相关的代码
    QString bPath = QCoreApplication::applicationDirPath() + "/model_zip/N1su_5";
#elif defined(__i386__) || defined(__x86_64__)
    QString bPath = QCoreApplication::applicationDirPath() + "/model_zip/T1_5";
#else
#error "不支持的架构"
#endif
    QByteArray && bypath = bPath.toUtf8();
    char* spath = bypath.data();
    HString path = spath;
    HInt32 option = HF_ENABLE_QUALITY | HF_ENABLE_FACE_RECOGNITION | HF_ENABLE_MASK_DETECT;
    HF_DetectMode detMode = HF_DETECT_MODE_IMAGE;   // 选择图像模式 即总是检测
    // 创建ctx
    ret = HF_CreateFaceContextFromResourceFileOptional(path, option, detMode, 5, &ctxHandle);
    if (ret != HSUCCEED) {
        qInfo() << QString("Create ctx error: %1").arg(ret);
        return;
    }
    //    ret = HF_FaceRecognitionThresholdSetting(ctxHandle, 0.36);
    //    if (ret != HSUCCEED) {
    //        qInfo() << QString("HF_FaceRecognitionThresholdSetting error: %1").arg(ret);
    //        return;
    //    }
    customIds.clear();
    int i = 0;
    for (auto it = maps.begin(); it != maps.end(); ++it,++i) {
        const QString& key = it->first;
        const QString& value = it->second;
        cv::Mat image = cv::imread(value.toStdString());
        if (image.empty()) {
            qInfo()<< "错误：图像为空或路径不正确，无法加载图像 ";
            return;
        }

        HF_ImageData imageData = {0};
        imageData.data = image.data;
        imageData.height = image.rows;
        imageData.width = image.cols;
        imageData.rotation = VIEW_ROTATION_0;
        imageData.format = FORMAT_BGR;
        
        HImageHandle imageSteamHandle;
        ret = HF_CreateImageStream(&imageData, &imageSteamHandle);
        this->configConfidence=confidence;
        if (ret != HSUCCEED) {
            qInfo() << QString("image handle error: %1").arg((long)imageSteamHandle);
            HF_ReleaseImageStream(imageSteamHandle); // 释放资源
            return;
        }
        
        HF_MultipleFaceData multipleFaceData = {0};
        HF_FaceContextRunFaceTrack(ctxHandle, imageSteamHandle, &multipleFaceData);
        
        if (multipleFaceData.detectedNum <= 0) {
            qInfo() << QString("initSourceImageMap:未检测到人脸: %1").arg(key);
            HF_ReleaseImageStream(imageSteamHandle); // 释放资源
            return;
        }
        
        HF_FaceFeature feature = {0};
        ret = HF_FaceFeatureExtract(ctxHandle, imageSteamHandle, multipleFaceData.tokens[0], &feature);
        if (ret != HSUCCEED) {
            qInfo() << QString("特征提取出错: %1").arg(ret);
            HF_ReleaseImageStream(imageSteamHandle); // 释放资源
            
            return;
        }
        
        char* tagName = new char[key.size() + 1];
        std::strcpy(tagName, key.toStdString().c_str());
        HF_FaceFeatureIdentity identity = {0};
        identity.feature = &feature;
        identity.customId = i;
        customIds.push_back( identity.customId);
        identity.tag = tagName;
        
        ret = HF_FeaturesGroupInsertFeature(ctxHandle, identity);
        if (ret != HSUCCEED) {
            qInfo() << QString("插入失败: %1").arg(ret);
            HF_ReleaseImageStream(imageSteamHandle); // 释放资源
            return;
        }
        
        delete[] tagName;
        
        ret = HF_ReleaseImageStream(imageSteamHandle);
        if (ret == HSUCCEED) {
            imageSteamHandle = nullptr;
            qInfo() << QString("mage released");
        } else {
            qInfo() << QString("image release error: %l").arg(ret);
        }
    }
}

int FaceReconition::featureRemove(){
    if(customIds.size()>0){
        for(auto customId:customIds){
            HResult ret= HF_FeaturesGroupFeatureRemove(ctxHandle,customId);
            qDebug()<<"ret:featureRemove "<<ret;
        }

        HF_ReleaseFaceContext(ctxHandle);
    }
}
void FaceReconition::doesItExistEmployee(const cv::Mat &source,std::list<vides_data::faceRecognitionResult>&faces){
    HResult ret;
    HF_ContextCustomParameter parameter = {0};
    HF_ImageData imageData = {0};
    imageData.data = source .data;
    imageData.height = source.rows;
    imageData.width = source.cols;
    imageData.rotation = VIEW_ROTATION_0;
    imageData.format = FORMAT_BGR;
    
    HImageHandle imageSteamHandle;
    ret = HF_CreateImageStream(&imageData, &imageSteamHandle);
    if (ret != HSUCCEED) {
        qInfo()<<QString("image handle error:%1").arg((long) imageSteamHandle,0,10);
        return ;
    }
    HF_MultipleFaceData multipleFaceData = {0};
    HF_FaceContextRunFaceTrack(ctxHandle, imageSteamHandle, &multipleFaceData);
    
    if (multipleFaceData.detectedNum <= 0) {
        qDebug()<<QString("search 未检测到人脸");
        return ;
    }
    
    std::vector<std::vector<float>> features;
    // 被搜索的目标这边推荐使用拷贝式的接口来获取特征向量
    HInt32 featureNum;
    HF_GetFeatureLength(ctxHandle, &featureNum);
    for(int j=0;j< multipleFaceData.detectedNum; ++j){
        std::vector<float> newfeature(featureNum,0.0f);
        ret = HF_FaceFeatureExtractCpy(ctxHandle, imageSteamHandle, multipleFaceData.tokens[j], newfeature.data());
        if(ret != HSUCCEED) {
            qDebug()<<QString("特征提取出错: %1").arg(ret);
            HF_ReleaseImageStream(imageSteamHandle);
            return ;
        }
        features.push_back(newfeature);
    }
    int rect=0;
    for(auto feat:features){
        HF_FaceFeature feature;
        feature.size = feat.size();
        feature.data = feat.data();
        HF_FaceFeatureIdentity searchIdentity = {0};
        //    HF_FaceFeature featureSearched = {0};
        //    searchIdentity.feature = &featureSearched;
        HFloat confidence;
        ret = HF_FeaturesGroupFeatureSearch(ctxHandle, feature, &confidence, &searchIdentity);
        if (ret != HSUCCEED) {
            qInfo()<<QString("搜索失败: %1").arg(ret);
            return ;
        }
        
        qDebug()<<QString("搜索置信度: %1").arg(confidence);
        qDebug()<<QString("匹配到的tag: %1").arg(searchIdentity.tag);
        qDebug()<<QString("匹配到的customId: %1").arg(searchIdentity.customId);
        // Face Pipeline
        ret = HF_MultipleFacePipelineProcess(ctxHandle, imageSteamHandle, &multipleFaceData, parameter);
        if (ret != HSUCCEED) {
            //printf("pipeline执行失败: %ld", ret);
            qInfo()<<QString("pipeline执行失败: %1").arg(ret);
            return ;
        }
        HF_RGBLivenessConfidence livenessConfidence = {0};
        ret = HF_GetRGBLivenessConfidence(ctxHandle, &livenessConfidence);
        if (ret != HSUCCEED) {
            qInfo()<<QString("获取活体数据失败1");
            return ;
        }
        //printf("活体置信度: %f", livenessConfidence.confidence[0]);
        qDebug()<<QString("活体置信度====>:%1").arg(livenessConfidence.confidence[0],0,'Q',4);
        
        HF_FaceMaskConfidence maskConfidence = {0};
        ret = HF_GetFaceMaskConfidence(ctxHandle, &maskConfidence);
        if (ret != HSUCCEED) {
            qInfo()<<QString("获口罩数据失败");
            return ;
        }
        HInt32 faceNum;
        ret = HF_FeatureGroupGetCount(ctxHandle, &faceNum);
        if (ret != HSUCCEED) {
            // printf("获取失败");
            qInfo()<<QString("获取失败");
            return ;
        }
        //printf("人脸特征数量: %d", faceNum);
        if (confidence > configConfidence) {
            vides_data::faceRecognitionResult newface;
            newface.id=searchIdentity.tag;
            newface.x=multipleFaceData.rects[rect].x;
            newface.y=multipleFaceData.rects[rect].y;
            newface.width=multipleFaceData.rects[rect].width;
            newface.height=multipleFaceData.rects[rect].height;
            faces.push_back(newface);
        }
        
        rect++;
    }
    ret = HF_ReleaseImageStream(imageSteamHandle);
    if (ret == HSUCCEED) {
        imageSteamHandle = nullptr;
        // printf("image released");
    } else {
        //printf("image release error: %ld", ret);
        qInfo()<<QString("image release error: %1").arg(ret);
    }
}

