#include "inprogressFace.h"

#include "logproc.h"
#include "CCommonTools.h"
#include "CFaceRecProc.h"
#include "CAppInfo.h"
#include "json/json.h"

std::shared_ptr<CInprogressFace> g_inProcessFace = nullptr;

CInprogressFace::CInprogressFace()
{
    qRegisterMetaType<CClientExamProcessUploadSign>("CClientExamProcessUploadSign");
    connect(g_httpBllPtr.get(), &CHttpBll::sgnClientExamProcessUploadSign, this, &CInprogressFace::onClientExamProcessUploadSign);
	qRegisterMetaType<CBaseResponsePackage>("CBaseResponsePackage");
	connect(g_httpBllPtr.get(), &CHttpBll::sgnSaveFaceCaptureResult, this, &CInprogressFace::onSaveFaceCaptureResult);
    qRegisterMetaType<CUploadFileToAliyun>("CUploadFileToAliyun");
    connect(g_httpBllPtr.get(), &CHttpBll::sgnUploadFileToAliyun, this, &CInprogressFace::onUploadFileToAliyun);

    genCameraInfo();

    m_bIsRun = true;
    m_thread = std::thread(std::bind(&CInprogressFace::threadProc, this));
}

void CInprogressFace::genCameraInfo()
{
    std::vector<CameraInfo> list;
    if(CCommonTools::listCameraDevices(list) <= 0)
    {
       return;
    }

    Json::Value jCameraInfo;
    for(CameraInfo &ci : list)
    {
        if(ci.pid.empty() || ci.vid.empty())
        {
            m_bHasVirtualCamera = true;
        }
        Json::Value jCamera;
        jCamera["detail"] = QString::fromStdWString(ci.detail.c_str()).toStdString();
        jCamera["name"] = QString::fromStdWString(ci.name.c_str()).toStdString();
        jCamera["pid"] = QString::fromStdWString(ci.pid.c_str()).toStdString();
        jCamera["vid"] = QString::fromStdWString(ci.vid.c_str()).toStdString();
        jCameraInfo.append(jCamera);
    }
    m_sCameraInfo = Json::FastWriter().write(jCameraInfo).c_str();
}

CInprogressFace::~CInprogressFace()
{
    m_bIsRun = false;
    m_thread.join();
}

void CInprogressFace::startFaceVerify(bool bVerify)
{
    m_bStart = bVerify;
}

void CInprogressFace::addImage(cv::Mat matImage)
{
    if(m_bStart)
    {
        std::scoped_lock lock(m_mImgList);
        m_vImgList.push_back(matImage);        
    }
}

void CInprogressFace::addFaceCountImage(cv::Mat matImage)
{
    if(m_bStart)
    {
        std::scoped_lock lock(m_mImgFaceCountList);
        m_vImgFaceCountList.push_back(matImage);
    }
}

void CInprogressFace::threadProc()
{
	if (g_faceRecProcPtr == nullptr)
	{
		g_faceRecProcPtr = std::make_shared<CFaceRecProc>();		
	}

    if (!g_appInfoPtr->m_sStudentPhotoPath.isEmpty())
    {
        QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
        sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
        if (!QFile::exists(sFileName))
        {
            emit compareFailed(QString::fromLocal8Bit("底照下载失败，请检查网络"));
            return;
        }

        if(!g_faceRecProcPtr->setBaseImage(sFileName))
        {
            emit compareFailed(g_faceRecProcPtr->errorMsg());
            return;
        }
    }
    else
    {
        emit compareFailed(QString::fromLocal8Bit("当前考试未底照"));
        return;
    }

    while(m_bIsRun)
    {
        if(m_bStart)
        {
            if(m_vImgFaceCountList.begin() != m_vImgFaceCountList.end())
            {
                cv::Mat matImage;
                {
                    std::scoped_lock lock(m_mImgFaceCountList);

                    matImage = (*m_vImgFaceCountList.begin()).clone();
                    m_vImgFaceCountList.erase(m_vImgFaceCountList.begin());
                }

                if(matImage.empty())
                {
                    myDebug()<<"matImage.empty";
                    continue;
                }

                int nFaceCount = 0;

                if(g_faceRecProcPtr->getFaceCount(matImage, nFaceCount))
                {
                    if(nFaceCount == 0)
                    {
                        //无人脸
                        emit compareFailed(QString::fromLocal8Bit("请调整坐姿，诚信考试"));
                    }
                    else if(nFaceCount > 1 && g_appInfoPtr->m_oExamInfo.bIsStrangerEnable)
                    {
                        //陌生人
                        emit compareFailed(QString::fromLocal8Bit("请独立完成考试"));
                    }
                }
                else
                {
                    QString sErrorMsg = g_faceRecProcPtr->errorMsg();
                    myDebug()<<QString::fromLocal8Bit("人脸检测失败:")<<sErrorMsg;
                }
            }

            if(m_vImgList.begin() != m_vImgList.end())
            {                

                cv::Mat matImage;
                {
                    std::scoped_lock lock(m_mImgList);

                    matImage = (*m_vImgList.begin()).clone();
                    m_vImgList.erase(m_vImgList.begin());
                }

                if(matImage.empty())
                {
                    myDebug()<<"matImage.empty";
                    continue;
                }

                int nFaceCount = 0;
                float fScore = 0;
                bool bRealness = false;
                int nTime = 0;
                if(!g_faceRecProcPtr->getMaxFaceScoreWithBase(matImage, nFaceCount, fScore, bRealness, nTime))
                {
                    //比对失败
                    QString sErrorMsg = g_faceRecProcPtr->errorMsg();
                    myDebug()<<QString::fromLocal8Bit("人脸检测失败:")<<sErrorMsg;
                    uploadFile(matImage, nFaceCount, fScore, bRealness);
                    emit compareFailed(sErrorMsg);
                }
                else
                {
                    if(nFaceCount == 0)
                    {
                        //无人脸
                        uploadFile(matImage, nFaceCount, fScore, bRealness);
                        emit compareFailed(QString::fromLocal8Bit("请让我看到您的正脸"));
                    }
                    else if(nFaceCount > 1 && g_appInfoPtr->m_oExamInfo.bIsStrangerEnable)
                    {
                        //陌生人
                        uploadFile(matImage, nFaceCount, fScore, bRealness);
                        emit compareFailed(QString::fromLocal8Bit("检测到陌生人"));
                    }
					else
					{
						uploadFile(matImage, nFaceCount, fScore, bRealness);
					}
                }

            }
        }
        else
        {
            Sleep(100);
        }
    }
}

void CInprogressFace::uploadFile(cv::Mat faceMat, int nFaceCount, float fScore, int nRealness)
{
    QString sFileName = QString("temp/photo/%1.png").arg(CCommonTools::getUuid());
    QImage imgCompare = CCommonTools::Mat2QImage(faceMat);
    imgCompare.save(sFileName, "PNG");

    CHttpRequestPackage hrp;
    hrp.sUri = "/api/ecs_oe_student/client/exam/process/upload/sign";
    hrp.nRequestType = RequestType::rtClientExamProcessUploadSign;
    hrp.sParamList.push_back(QString("fileSuffix,%1").arg(".png"));
    hrp.sParamList.push_back(QString("fileMd5,%1").arg(CCommonTools::fileMd5(sFileName)));
    hrp.sCommonStr = QString("%1,%2,%3,%4").arg(__FILE__).arg(nFaceCount).arg(fScore).arg(nRealness);
    hrp.sCommonStr1 = sFileName;
    hrp.eParamType = HttpParamType::hptBody;
    g_httpBllPtr->post(hrp);
}

//文件上传
void CInprogressFace::onClientExamProcessUploadSign(CClientExamProcessUploadSign processUpload)
{    
    QStringList list = processUpload.sCommonStr.split(",");
    if(list.count() == 4)
    {
        QString sFile = list[0];
        int nFaceCount = list[1].toInt();
        float fScore = list[2].toFloat();
        int nRealness = list[3].toInt();
        
		if(__FILE__ == sFile)
        {
			if (processUpload.nCode == 200)
			{
                CHttpRequestPackage hrp;
                hrp.sUri = processUpload.sFormUrl;
                hrp.nRequestType = RequestType::rtUploadFileToAliyun;
                hrp.sCommonStr = QString("%1,%2,%3,%4").arg(__FILE__).arg(nFaceCount).arg(fScore).arg(nRealness);;
                hrp.sCommonStr1 = processUpload.sAccessUrl;
                hrp.sParamList.push_back(QString("OSSAccessKeyId,%1").arg(processUpload.sOssAcessKeyId));
                hrp.sParamList.push_back(QString("Signature,%1").arg(processUpload.sSignature));
                hrp.sParamList.push_back(QString("key,%1").arg(processUpload.sKey));
                hrp.sParamList.push_back(QString("policy,%1").arg(processUpload.sPolicy));
                hrp.sParamList.push_back(QString("success_action_status,%1").arg(200));
                hrp.sParamList.push_back(QString("formdataFileType,file,%1").arg(processUpload.sFilePath));
                hrp.bNoHostPrefix = true;
                hrp.eParamType = HttpParamType::hptFormdata;
                g_httpBllPtr->post(hrp);

			}
			else
			{

			}
        }
    }   
}

void CInprogressFace::onUploadFileToAliyun(CUploadFileToAliyun uploadFileToAliyun)
{
    QStringList list = uploadFileToAliyun.sCommonStr.split(",");
    if(list.count() == 4)
    {
        QString sFile = list[0];
        int nFaceCount = list[1].toInt();
        float fScore = list[2].toFloat();
        int nRealness = list[3].toInt();

        if(__FILE__ == sFile)
        {
            if (uploadFileToAliyun.nCode == 200)
            {
                CHttpRequestPackage hrp;
                hrp.sUri = "/api/ecs_oe_student/client/exam/process/saveFaceCaptureResult";
                hrp.nRequestType = RequestType::rtSaveFaceCaptureResult;
                Json::Value jBody = Json::Value::null;
                jBody["examRecordDataId"] = g_appInfoPtr->m_oExamInfo.nExamRecordDataId;
                jBody["faceCompareResult"] = fScore;
                jBody["facelivenessResult"] = nRealness;
                jBody["fileUrl"] = uploadFileToAliyun.sFileUrl.toStdString();
                jBody["pass"] = (fScore * 100 > g_appInfoPtr->m_oExamInfo.nFaceThreshold) ? true : false;
                jBody["stranger"] = nFaceCount > 1;
                jBody["hasVirtualCamera"] = m_bHasVirtualCamera;
                jBody["cameraInfos"] = m_sCameraInfo.toStdString();
                hrp.sParamList.push_back(QString("CustomBody,%1").arg(jBody.toStyledString().c_str()));
                hrp.eParamType = HttpParamType::hptCustomBody;
                myDebug() << jBody.toStyledString().c_str();
                g_httpBllPtr->post(hrp);
            }
            else
            {

            }
        }
    }
}

//保存人脸抓拍比对验证结果
void CInprogressFace::onSaveFaceCaptureResult(CBaseResponsePackage res)
{
    if(res.nCode == 200)
    {

    }
    else
    {

    }
}
