#include "faceCompare.h"
#include "ui_faceCompare.h"

#include "CAppInfo.h"

#include <QDesktopWidget>
#include <QFile>
#include <QFileInfo>

#include "awMsgBox.h"
#include "logproc.h"
#include "CCommonTools.h"
#include "CFaceRecProc.h"


faceCompare::faceCompare(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::faceCompare)
{
    ui->setupUi(this);

    setStyleSheet(g_appInfoPtr->m_sQssStr);

    initUI();
    m_bStartCompare = false;

    qRegisterMetaType<CBaseResponsePackage>("CBaseResponsePackage");
    qRegisterMetaType<CClientExamProcessUploadSign>("CClientExamProcessUploadSign");
    qRegisterMetaType<CUploadFileToAliyun>("CUploadFileToAliyun");

    connect(g_httpBllPtr.get(), &CHttpBll::sgnClientExamProcessUploadSign, this, &faceCompare::onClientExamProcessUploadSign);
    connect(g_httpBllPtr.get(), &CHttpBll::sgnSaveFaceCompareResult, this, &faceCompare::onSaveFaceCompareResult);
    connect(g_httpBllPtr.get(), &CHttpBll::sgnUploadFileToAliyun, this, &faceCompare::onUploadFileToAliyun);


    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))
    {
        CHttpRequestPackage hrp;
        hrp.sUri = g_appInfoPtr->m_sStudentPhotoPath;
        hrp.sCommonStr = sFileName;
        hrp.sCommonStr1 = __FILE__;
        hrp.nRequestType = RequestType::rtDownLoadFile;
        hrp.nRetryCount = 3;
        g_httpBllPtr->downLoad(hrp);
    }

    m_pVideoTimer = std::make_shared<QTimer>();
    m_pVideoTimer->setInterval(200);
    connect(m_pVideoTimer.get(), &QTimer::timeout, this, [&](){
        std::scoped_lock lock(m_imageMutex);
        QImage img = CCommonTools::Mat2QImage(m_nCurImage);

        ui->widget_fc_camera->setAutoFillBackground(true);
        QPalette palette;
        palette.setBrush(QPalette::Window, QBrush(img.scaled(ui->widget_fc_camera->width(), ui->widget_fc_camera->height())));
        ui->widget_fc_camera->setPalette(palette);
    });

    g_clientVideoProcPtr->startTest(this);

    m_pVideoTimer->start();

	connect(this, &faceCompare::compareFailed, this, [&](QString sErrorMsg) {
        ShowMsg(sErrorMsg, this, MSG_ICON_TYPE::mit_error);        
		ui->btn_fc_compare->setEnabled(true);

        if(!g_appInfoPtr->m_oExamInfo.bIsFaceCheck)
        {
            if(m_pSkipFaceCompare == nullptr)
            {
                m_pSkipFaceCompare = std::make_shared<skipFaceCompare>(this);
                connect(m_pSkipFaceCompare.get(), &skipFaceCompare::cancel, this, [&](){
                    m_pSkipFaceCompare.reset();
                });

                connect(m_pSkipFaceCompare.get(), &skipFaceCompare::confirm, this, [&](){
                    m_pSkipFaceCompare.reset();
                    emit faceComparePass();
                });
            }
            m_pSkipFaceCompare->show();
        }
	});
	
    m_bIsRun = true;
    m_thread = std::thread(std::bind(&faceCompare::threadProc, this));	
}

faceCompare::~faceCompare()
{
    m_pVideoTimer->stop();
    g_clientVideoProcPtr->stopTest();

    m_bIsRun = false;
    m_thread.join();
    awMsgBox::clear(this);
    delete ui;
}

void faceCompare::onRenderVideoFrame(const char* userId, TRTCVideoStreamType streamType, TRTCVideoFrame* frame)
{
    if(g_clientVideoProcPtr->isCameraTest())
    {
        __int64 nServerTime = g_appInfoPtr->serverMTime();
        if(nServerTime - m_lastFaceTime >= 100)
        {
            m_lastFaceTime = nServerTime;
            cv::Mat matImg;
            cv::cvtColor(cv::Mat(frame->height, frame->width, CV_8UC4, frame->data), matImg, CV_RGBA2RGB);
            std::scoped_lock lock(m_imageMutex);
            m_nCurImage = matImg.clone();
        }
    }
}

void faceCompare::onDownLoadFile(CDownLoadFileInfo downLoadFileInfo)
{
    if(downLoadFileInfo.sModuleName == __FILE__)
    {
        if (downLoadFileInfo.nCode == 200)
        {
            QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
            sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
            ui->label_fc_basePhoto->setPixmap(QPixmap(sFileName).scaled(ui->label_fc_basePhoto->width(), ui->label_fc_basePhoto->height(),
                Qt::IgnoreAspectRatio));
        }
        else
        {
            if(downLoadFileInfo.sMessage.isEmpty())
            {
                ShowMsg(QString::fromLocal8Bit("下载失败"), this, MSG_ICON_TYPE::mit_error);
            }
            else
            {
                ShowMsg(downLoadFileInfo.sMessage, this, MSG_ICON_TYPE::mit_error);
            }
        }
    }
}

void faceCompare::initUI()
{
    QDesktopWidget *dekwiget = QApplication::desktop();
    setGeometry(0, 0, dekwiget->width(), dekwiget->height());
    ui->widget_mask->setGeometry(0, 0, dekwiget->width(), dekwiget->height());
    ui->widget_fc_BG->setGeometry((width() - g_appInfoPtr->m_fRate*800)/2, (height() - g_appInfoPtr->m_fRate*536)/2,
                                   g_appInfoPtr->m_fRate*800, g_appInfoPtr->m_fRate*536);
    ui->label_fc_title->adjustSize();
    ui->label_fc_title->setGeometry(g_appInfoPtr->m_fRate*20, g_appInfoPtr->m_fRate*16,
                                    ui->label_fc_title->width(), ui->label_fc_title->height());
    ui->btn_fc_close->setGeometry(ui->widget_fc_BG->width() - g_appInfoPtr->m_fRate*(20 + 16),
                                  g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16);
    ui->label_HLine->setGeometry(0, ui->label_fc_title->y() + ui->label_fc_title->height() + g_appInfoPtr->m_fRate*16,
                                 ui->widget_fc_BG->width(), g_appInfoPtr->m_fRate*1 < 1 ? 1 : g_appInfoPtr->m_fRate*1);
    ui->label_fc_basePhoto->setGeometry(g_appInfoPtr->m_fRate*30, ui->label_HLine->y() + ui->label_HLine->height() + g_appInfoPtr->m_fRate*20,
                                        g_appInfoPtr->m_fRate*140, g_appInfoPtr->m_fRate*180);
	QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
	sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
	ui->label_fc_basePhoto->setPixmap(QPixmap(sFileName).scaled(ui->label_fc_basePhoto->width(), ui->label_fc_basePhoto->height(),
		Qt::IgnoreAspectRatio));
	ui->label_fc_basePhotoTips->setGeometry(ui->label_fc_basePhoto->x() + g_appInfoPtr->m_fRate*10,
                                            ui->label_fc_basePhoto->y() + ui->label_fc_basePhoto->height() - g_appInfoPtr->m_fRate*(10+20),
                                            ui->label_fc_basePhoto->width() - g_appInfoPtr->m_fRate*10*2, g_appInfoPtr->m_fRate*20);
    ui->widget_fc_camera->setGeometry(ui->label_fc_basePhoto->x() + ui->label_fc_basePhoto->width() + g_appInfoPtr->m_fRate*20,
                                     ui->label_fc_basePhoto->y(), g_appInfoPtr->m_fRate*580, g_appInfoPtr->m_fRate*300);
    ui->label_faceRect->setGeometry((ui->widget_fc_camera->width() - g_appInfoPtr->m_fRate*140)/2,
                                    (ui->widget_fc_camera->height() - g_appInfoPtr->m_fRate*140 - g_appInfoPtr->m_fRate*(20 + 40))/2,
                                    g_appInfoPtr->m_fRate*140, g_appInfoPtr->m_fRate*140);
    ui->btn_fc_compare->setGeometry((ui->widget_fc_camera->width() - g_appInfoPtr->m_fRate*120)/2,
                                    ui->widget_fc_camera->height() - g_appInfoPtr->m_fRate*(20 + 40),
                                    g_appInfoPtr->m_fRate*120, g_appInfoPtr->m_fRate*40);
    ui->label_fc_tips->adjustSize();
    ui->label_fc_tips->setGeometry(ui->widget_fc_camera->x(), ui->widget_fc_camera->y() + ui->widget_fc_camera->height() + g_appInfoPtr->m_fRate*20,
                                   ui->label_fc_tips->width(), ui->label_fc_tips->height());
    ui->label_fc_note->setGeometry(ui->widget_fc_camera->x(), ui->label_fc_tips->y() + ui->label_fc_tips->height() + g_appInfoPtr->m_fRate*5,
                                   g_appInfoPtr->m_fRate*580, g_appInfoPtr->m_fRate*100);
}


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

    if (!g_appInfoPtr->m_sStudentPhotoPath.isEmpty())
    {
        if(!setBaseImage())
        {
            return;
        }
    }
    else
    {
        ShowMsg(QString::fromLocal8Bit("本场考试需要进行人脸检测,但是您没有上传底照，请联系老师"), this, MSG_ICON_TYPE::mit_error);
        QTimer::singleShot(3000, this, [&]() { emit exitFaceCompare(); });
        return;
    }

//    if(!g_faceRecProcPtr->hasBaseImage())
//    {
//        if(!setBaseImage())
//        {
//            return;
//        }
//    }

    m_bStartCompare = true;
	ui->btn_fc_compare->setEnabled(false);
}

bool faceCompare::setBaseImage()
{
    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))
    {
        ShowMsg(QString::fromLocal8Bit("底照下载失败，请检查网络"), this, MSG_ICON_TYPE::mit_error);
        return false;
    }
    QFileInfo filePath(sFileName);

    if(!g_faceRecProcPtr->setBaseImage(filePath.absoluteFilePath()))
    {
        //g_faceRecProcPtr->errorMsg()
        ShowMsg(QString::fromLocal8Bit("底照不符合要求，请更换照片"), this, MSG_ICON_TYPE::mit_error);
        return false;
    }
    return true;
}

void faceCompare::on_btn_fc_close_clicked()
{
    m_bIsRun = false;
    emit exitFaceCompare();
}

void faceCompare::threadProc()
{
    while(m_bIsRun)
    {
        if(m_bStartCompare)
        {
            cv::Mat img = m_nCurImage;
            if(!img.empty())
            {
                //人脸比对
                int nFaceCount = 0;
                float fScore = 0;
                bool bRealness = false;
				int nTime = 0;
                if(!g_faceRecProcPtr->getMaxFaceScoreWithBase(img, nFaceCount, fScore, bRealness, nTime))
                {
                    //比对失败
                    QString sErrorMsg = g_faceRecProcPtr->errorMsg();
                    emit compareFailed(sErrorMsg);
                }
                else
                {
                    if(nFaceCount == 0)
                    {
                        //无人脸
                        emit compareFailed(QString::fromLocal8Bit("请让我看到您的正脸"));
                    }
                    else if(nFaceCount > 1 && g_appInfoPtr->m_oExamInfo.bIsStrangerEnable)
                    {
                        //陌生人
                        emit compareFailed(QString::fromLocal8Bit("检测到陌生人"));
                    }
                    else
                    {
#ifdef _DEBUG
                        g_appInfoPtr->m_oExamInfo.nFaceThreshold = 1;
#endif // _DEBUG
                        if(fScore*100 > g_appInfoPtr->m_oExamInfo.nFaceThreshold)
                        {
							m_fScore = fScore;
							m_nFaceCount = nFaceCount;
							m_nTime = nTime;
                            //比对成功
                            QString sFileName = QString("temp/photo/%1.png").arg(CCommonTools::getUuid());
                            QImage imgCompare = CCommonTools::Mat2QImage(img);
                            imgCompare.save(sFileName, "PNG");

                            CHttpRequestPackage hrp;
                            hrp.sUri = "/api/ecs_oe_student/client/exam/process/upload/sign";
                            hrp.nRequestType = RequestType::rtClientExamProcessUploadSign;
                            hrp.sCommonStr = __FILE__;
                            hrp.sCommonStr1 = sFileName;
                            hrp.sParamList.push_back(QString("fileSuffix,%1").arg(".png"));
                            hrp.sParamList.push_back(QString("fileMd5,%1").arg(CCommonTools::fileMd5(sFileName)));

                            hrp.eParamType = HttpParamType::hptBody;
                            g_httpBllPtr->post(hrp);
                        }
                        else
                        {
                            //低于阈值
                            emit compareFailed(QString::fromLocal8Bit("检测失败"));
                        }
                    }
                }
                m_bStartCompare = false;
            }
        }
        else
        {
            Sleep(100);
        }
    }
}

//文件上传
void faceCompare::onClientExamProcessUploadSign(CClientExamProcessUploadSign processUpload)
{
    try
    {
        if(processUpload.sCommonStr == __FILE__)
        {
            if(processUpload.nCode == 200)
            {
                CHttpRequestPackage hrp;
                hrp.sUri = processUpload.sFormUrl;
                hrp.nRequestType = RequestType::rtUploadFileToAliyun;
                hrp.sCommonStr = __FILE__;
                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
            {
                if(processUpload.sMessage.isEmpty())
                {
                    ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error);
                }
                else
                {
                    ShowMsg(processUpload.sMessage, this, MSG_ICON_TYPE::mit_error);
                }
            }
        }
    }
    catch (const std::exception &e)
    {
        ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error);
        myServerLog()<<"exception error"<<e.what();
    }
}

void faceCompare::onUploadFileToAliyun(CUploadFileToAliyun uploadFileToAliyun)
{
    try
    {
        if(uploadFileToAliyun.sCommonStr == __FILE__)
        {
            if(uploadFileToAliyun.nCode == 200)
            {
                CHttpRequestPackage hrp;
                hrp.sUri = "/api/ecs_oe_student/client/exam/process/saveFaceCompareResult";
                hrp.nRequestType = RequestType::rtSaveFaceCompareResult;
                Json::Value jBody = Json::Value::null;
                jBody["faceCompareResult"] = QString::number(m_fScore).toStdString();
                jBody["fileUrl"] = uploadFileToAliyun.sFileUrl.toStdString();
                jBody["pass"] = true;
                jBody["processTime"] = m_nTime;
                jBody["stranger"] = m_nFaceCount > 1;
                hrp.sParamList.push_back(QString("CustomBody,%1").arg(jBody.toStyledString().c_str()));
                hrp.eParamType = HttpParamType::hptCustomBody;

                g_httpBllPtr->post(hrp);
            }
            else
            {
                if(uploadFileToAliyun.sMessage.isEmpty())
                {
                    ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error);
                }
                else
                {
                    ShowMsg(uploadFileToAliyun.sMessage, this, MSG_ICON_TYPE::mit_error);
                }
            }
        }
    }
    catch (const std::exception &e)
    {
        ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error);
        myServerLog()<<"exception error"<<e.what();
    }
}

//保存人脸识别比对验证结果
void faceCompare::onSaveFaceCompareResult(CBaseResponsePackage res)
{
    try
    {
        if(res.nCode == 200)
        {
            ShowMsg(QString::fromLocal8Bit("人脸比对成功"), this, MSG_ICON_TYPE::mit_succeed);
            QTimer::singleShot(3000, this, [&](){
                emit faceComparePass();
            });

        }
        else
        {
            if(res.sMessage.isEmpty())
            {
                ShowMsg(QString::fromLocal8Bit("保存人脸识别信息失败"), this, MSG_ICON_TYPE::mit_error);
            }
            else
            {
                ShowMsg(res.sMessage, this, MSG_ICON_TYPE::mit_error);
            }
        }
    }
    catch (const std::exception &e)
    {
        ShowMsg(QString::fromLocal8Bit("保存人脸识别信息失败"), this, MSG_ICON_TYPE::mit_error);
        myServerLog()<<"exception error"<<e.what();
    }
}
