#include "CLiveViodeProc.h"

#include <QDebug>


#include "CAppInfo.h"
#include "logproc.h"

std::shared_ptr<CLiveViodeProc> g_clientVideoProcPtr = nullptr;

CVideoRenderCallBack::CVideoRenderCallBack()
{
    m_nLastFrameTime = 0;
}

void CVideoRenderCallBack::onRenderVideoFrame(const char* userId, TRTCVideoStreamType streamType, TRTCVideoFrame* frame)
{
//    if(g_inProcessFaceVerify && streamType == TRTCVideoStreamTypeBig)
//    {

//        __int64 curTime = g_appInfoPtr->serverMTime();
//        if(curTime - m_nLastFrameTime >= g_appInfoPtr->m_vFaceMoudleInfo.ipfc.nFaceDetectIntervalSeconds)
//        {
//            cv::Mat matImg;
//            cv::cvtColor(cv::Mat(frame->height, frame->width, CV_8UC4, frame->data), matImg, CV_RGBA2RGB);
//            IMAGE_INFO imgInfo;
//            imgInfo.matImage = matImg.clone();
//            g_inProcessFaceVerify->addImage(imgInfo);
//            m_nLastFrameTime = curTime;
//        }
//    }
}

CLiveViodeProc::CLiveViodeProc()
{
    m_hwnd = nullptr;
    m_nLiveType = lt_unknown;
    m_bEnableLocalAudo = false;
    m_bPlay = false;
    m_nCameraCount = 0;

    m_sCameraStreamName = "";
    m_sCameraStreamRecordId = "";
    m_sScreenStreamName = "";
    m_sScreenStreamRecordId = "";

    m_bIsCameraTest = false;

    // 创建 TRTCCloud 实例
    m_pTRTCSDK = getTRTCShareInstance();

    // 注册 SDK 回调事件
    m_pTRTCSDK->addCallback(this);

    m_pVideoRenderCallBack = new CVideoRenderCallBack;
//    m_pVideoRenderCallBack->setCallBack([this](cv::Mat frame)
//        {
//            emit videoFrame(frame);
//        });
}


CLiveViodeProc::~CLiveViodeProc()
{
    exitRoom();

    // 取消监听 SDK 事件
    if(m_pTRTCSDK)
    {
        m_pTRTCSDK->removeCallback(this);
    }

    // 释放 TRTCCloud 实例
    if(m_pTRTCSDK != nullptr)
    {
        destroyTRTCShareInstance();
        m_pTRTCSDK = nullptr;
    }

    if(m_pVideoRenderCallBack != nullptr)
    {
        delete m_pVideoRenderCallBack;
    }
}

void CLiveViodeProc::startTest(HWND hwnd)
{
//    m_pTRTCSDK->getDeviceManager()->setCurrentDevice(TXMediaDeviceTypeCamera, 0);
    m_pTRTCSDK->getDeviceManager()->startCameraDeviceTest(hwnd);
    m_bIsCameraTest = true;
}

int CLiveViodeProc::getCameraCount()
{
    if(m_nCameraCount == 0)
    {
        m_nCameraCount = m_pTRTCSDK->getDeviceManager()->getDevicesList(TXMediaDeviceTypeCamera)->getCount();
    }
    return m_nCameraCount;
}

QString CLiveViodeProc::setCurrentCamera(int nIndex)
{
    if(nIndex < m_nCameraCount)
    {
        const char *pid = m_pTRTCSDK->getDeviceManager()->getDevicesList(TXMediaDeviceTypeCamera)->getDevicePID(nIndex);
        m_pTRTCSDK->getDeviceManager()->setCurrentDevice(TXMediaDeviceTypeCamera, pid);
        return pid;
    }
}

QString CLiveViodeProc::getCurrentCamera()
{
    const char *pid = m_pTRTCSDK->getDeviceManager()->getCurrentDevice(TXMediaDeviceTypeCamera)->getDevicePID();
    return pid;
}

void CLiveViodeProc::startTest(ITRTCVideoRenderCallback *pCallBack, bool bHighDpi)
{
    if(!bHighDpi)
    {
        m_pTRTCSDK->getDeviceManager()->startCameraDeviceTest(pCallBack);
    }
    else
    {
        qDebug()<<"TRTCVideoEncParam";
        TRTCVideoEncParam params;
        params.resMode = TRTCVideoResolutionModeLandscape;
        params.videoFps = 10;
        params.videoBitrate = 600;
        params.videoResolution = TRTCVideoResolution_960_720;
        m_pTRTCSDK->setVideoEncoderParam(params);
        TRTCRenderParams renderParams;
        renderParams.fillMode = TRTCVideoFillMode_Fit;
        m_pTRTCSDK->setLocalRenderParams(renderParams);
        m_pTRTCSDK->startLocalPreview(nullptr);

        m_pTRTCSDK->setLocalVideoRenderCallback(TRTCVideoPixelFormat_BGRA32, TRTCVideoBufferType_Buffer, pCallBack);
    }
    m_bIsCameraTest = true;
}

void CLiveViodeProc::stopTest(bool bHighDpi)
{
    if(m_bIsCameraTest)
    {
        m_bIsCameraTest = false;
        if(!bHighDpi)
        {
            m_pTRTCSDK->getDeviceManager()->stopCameraDeviceTest();
        }
        else
        {
            m_pTRTCSDK->stopLocalPreview();
            m_pTRTCSDK->setLocalVideoRenderCallback(TRTCVideoPixelFormat_BGRA32, TRTCVideoBufferType_Buffer, nullptr);
        }
    }
}

bool CLiveViodeProc::isCameraTest()
{
    return m_bIsCameraTest;
}

void CLiveViodeProc::setHandle(HWND hwnd)
{

    if(hwnd != nullptr && m_hwnd == nullptr)
    {

        m_pTRTCSDK->startLocalPreview(hwnd);
        myDebug()<<"startLocalPreview";
    }
    else if(hwnd == nullptr)
    {
        m_pTRTCSDK->stopLocalPreview();
        myDebug()<<"stopLocalPreview";

    }
    else
    {
        m_pTRTCSDK->updateLocalView(hwnd);
        myDebug()<<"updateLocalView";
    }

    m_hwnd = hwnd;
}

void CLiveViodeProc::enableFrameCallBack(bool bEnable)
{
    m_bFrameCallBack = bEnable;
}

void CLiveViodeProc::enableLoaclAudio(bool bEnable)
{
    m_bEnableLocalAudo = bEnable;
}

void CLiveViodeProc::startPlayAudio()
{
    m_bPlay = true;
}

void CLiveViodeProc::initParam(int nLiveType, uint32_t nSdkAppId, std::string sUserId, std::string sUserSig,
    std::string sRoomId, std::string sCameraStreamName, std::string sCameraStreamRecordId,
    std::string sScreenStreamName, std::string sScreenStreamRecordId)
{
    m_nSdkAppId = nSdkAppId;
    m_sUserId = sUserId;
    m_sUserSig = sUserSig;
    m_sRoomId = sRoomId;
    m_nLiveType = nLiveType;
    m_sCameraStreamName = sCameraStreamName;
    m_sScreenStreamName = sScreenStreamName;
    m_sCameraStreamRecordId = sCameraStreamRecordId;
    m_sScreenStreamRecordId = sScreenStreamRecordId;
}

void CLiveViodeProc::EnterRoom()
{
    try
    {
        TRTCParams params;
        params.sdkAppId = m_nSdkAppId;//1400411036;
        params.userId   = m_sUserId.c_str();//"s03";
        params.userSig  = m_sUserSig.c_str();//"eJwtzFELgjAUhuH-suuQczanJnQRFCwygjLLy2ArDmXZJiZF-z2ZXn7PB**X5dk*aI1lKeMBsInfpM2joQt5diBGdvp2rmvSLMUQIEQEEQ2P6WqypncpJQeAQRuqvE1jjsijZKzQta9WC7ni7qV0gUeH78OpzNyuEE*Z2Gb70bEK712r5vl6uZmx3x9ryDAN";
        params.roomId   = 0; // 输入您想进入的房间
        params.strRoomId = m_sRoomId.c_str();
        params.role     = TRTCRoleAnchor; //主播
        std::string streamId = "";
        std::string recordId = "";
        streamId = m_sCameraStreamName;//QString("oe_%1_client_camera").arg(params.roomId).toStdString();
        recordId = m_sCameraStreamRecordId;
        if(m_nLiveType == lt_client_screen)
        {
            streamId = m_sScreenStreamName;//QString("oe_%1_client_screen").arg(params.roomId).toStdString();
            recordId = m_sScreenStreamRecordId;
        }
        params.streamId = streamId.c_str();
        if(recordId != "")
        {
            params.userDefineRecordId = recordId.c_str();
        }

        myDebug()<<params.streamId;

        if(m_pTRTCSDK)
        {
            m_pTRTCSDK->setDefaultStreamRecvMode(false, false);
            m_pTRTCSDK->enterRoom(params, TRTCAppSceneLIVE);
        }
    }
    catch(std::exception &e)
    {
        myDebug()<<e.what();
    }
}

void CLiveViodeProc::exitRoom()
{
    if(m_pTRTCSDK)
    {
        m_pTRTCSDK->exitRoom();
        if(m_nLiveType == lt_client_camera)
        {
            m_pTRTCSDK->stopLocalPreview();
            m_pTRTCSDK->stopLocalAudio();
        }
        else if(m_nLiveType == lt_client_screen)
        {
            m_pTRTCSDK->stopScreenCapture();
        }
        else if(m_nLiveType == lt_client_camera_screen)
        {
            m_pTRTCSDK->stopLocalPreview();
            m_pTRTCSDK->stopLocalAudio();
            m_pTRTCSDK->stopScreenCapture();
        }

    }
}

void CLiveViodeProc::onError(TXLiteAVError errCode, const char* errMsg, void* arg)
{
    QString sErrorStr = QString::fromLocal8Bit("errMsg:%1,errCode:%2").arg(errMsg).arg(errCode);
    qDebug() << "errCode:" << errCode << "errMsg:" << errMsg;

    if (errCode == ERR_ROOM_ENTER_FAIL)
    {
        emit videoErrorMsg(sErrorStr);
        exitRoom();
    }
    else if(errCode == ERR_CAMERA_START_FAIL ||
            errCode == ERR_CAMERA_NOT_AUTHORIZED ||
            errCode == ERR_CAMERA_SET_PARAM_FAIL ||
            errCode == ERR_CAMERA_OCCUPY)
    {
        emit cameraUseFailed();
    }
}

void CLiveViodeProc::onWarning(TXLiteAVWarning warningCode, const char* warningMsg, void* arg)
{
    qDebug() << "warningCode:" << warningCode << "warningMsg:" << warningMsg;
    if(warningCode == WARNING_CAMERA_DEVICE_EMPTY ||
            warningCode == WARNING_CAMERA_NOT_AUTHORIZED)
    {
        emit cameraUseFailed();
    }
}

void CLiveViodeProc::onEnterRoom(int result)
{
    try
    {
        if(result < 0)
        {
            emit videoErrorMsg(QString::fromLocal8Bit("开启推流失败，错误代码：").arg(result));
            return;
        }
        myDebug()<<"onEnterRoom";
        // 获取渲染窗口的句柄。
        if(m_pTRTCSDK)
        {
            // 调用 SDK 接口设置渲染模式和渲染窗口。
            if(m_nLiveType == lt_client_camera)
            {
                TRTCVideoEncParam params;
                params.resMode = TRTCVideoResolutionModeLandscape;
                params.videoFps = 15;
                params.videoResolution = TRTCVideoResolution_640_480;
                m_pTRTCSDK->setVideoEncoderParam(params);
                TRTCRenderParams renderParams;
                renderParams.fillMode = TRTCVideoFillMode_Fit;
                m_pTRTCSDK->setLocalRenderParams(renderParams);
//                m_pTRTCSDK->setLocalViewFillMode(TRTCVideoFillMode_Fit);
                m_pTRTCSDK->startLocalPreview(m_hwnd);
                if(m_bFrameCallBack)
                {
                    m_pTRTCSDK->setLocalVideoRenderCallback(TRTCVideoPixelFormat_BGRA32, TRTCVideoBufferType_Buffer, m_pVideoRenderCallBack);
                }
            }
            else if(m_nLiveType == lt_client_screen)
            {
                TRTCScreenCaptureSourceInfo source;
                source.type = TRTCScreenCaptureSourceTypeScreen;
                RECT rt =  { 0, 0, 0, 0 };
                TRTCScreenCaptureProperty captureProperty;
                captureProperty.enableHighLight = false;
                m_pTRTCSDK->selectScreenCaptureTarget(source, rt, captureProperty);
                TRTCVideoEncParam params;
                params.resMode = TRTCVideoResolutionModeLandscape;
                params.videoFps = 15;
                params.videoResolution = TRTCVideoResolution_640_480;
                m_pTRTCSDK->startScreenCapture(nullptr, TRTCVideoStreamTypeBig, &params);
            }
            else
            {
                TRTCVideoEncParam params;
                params.resMode = TRTCVideoResolutionModeLandscape;
                params.videoFps = 15;
                params.videoResolution = TRTCVideoResolution_640_480;
                m_pTRTCSDK->setVideoEncoderParam(params);
                TRTCRenderParams renderParams;
                renderParams.fillMode = TRTCVideoFillMode_Fit;
                m_pTRTCSDK->setLocalRenderParams(renderParams);
                m_pTRTCSDK->startLocalPreview(m_hwnd);
                if(m_bFrameCallBack)
                {
                    m_pTRTCSDK->setLocalVideoRenderCallback(TRTCVideoPixelFormat_BGRA32, TRTCVideoBufferType_Buffer, m_pVideoRenderCallBack);
                }


                TRTCScreenCaptureSourceInfo source;
                source.type = TRTCScreenCaptureSourceTypeScreen;
                RECT rt =  { 0, 0, 0, 0 };
                TRTCScreenCaptureProperty captureProperty;
                captureProperty.enableHighLight = false;
                m_pTRTCSDK->selectScreenCaptureTarget(source, rt, captureProperty);
                TRTCVideoEncParam paramsScreen;
                paramsScreen.resMode = TRTCVideoResolutionModeLandscape;
                paramsScreen.videoFps = 15;
                paramsScreen.videoResolution = TRTCVideoResolution_640_480;
                m_pTRTCSDK->startScreenCapture(nullptr, TRTCVideoStreamTypeSub, &paramsScreen);
                std::string streamId = m_sScreenStreamName;//QString("oe_%1_client_screen").arg(m_nRoomId).toStdString();
                m_pTRTCSDK->startPublishing(streamId.c_str(), TRTCVideoStreamTypeSub);
            }

            if(m_bEnableLocalAudo)
            {
                m_pTRTCSDK->enableAudioVolumeEvaluation(300);
                m_pTRTCSDK->setAudioCaptureVolume(100);
//                m_pTRTCSDK->setAudioQuality(TRTCAudioQualitySpeech);
                m_pTRTCSDK->startLocalAudio(TRTCAudioQualitySpeech);
            }

            emit enterRoomSucceed();
        }
    }
    catch(std::exception &e)
    {
        myDebug()<<e.what();
    }
}

void CLiveViodeProc::onExitRoom(int reason)
{

}

void CLiveViodeProc::onRemoteUserEnterRoom(const char* userId)
{
    QString sUserId = userId;
    if(sUserId.startsWith("m_"))
    {
        emit invigilatorEnterRoom();
        myDebug()<<"invigilatorEnterRoom";
    }
}

void CLiveViodeProc::onRemoteUserLeaveRoom(const char* userId, int reason)
{
    QString sUserId = userId;
    if(sUserId.startsWith("m_"))
    {
        emit invigilatorLeaveRoom();
        myDebug()<<"invigilatorLeaveRoom";
    }

}

void CLiveViodeProc::onUserVideoAvailable(const char* userId, bool available)
{
//    if(available)
//    {
//        qDebug()<<userId;
//        if(m_pTRTCSDK)
//        {
//            m_pTRTCSDK->startRemoteView(userId, m_hwnd);
//        }
//    }
//    else
//    {
//        if(m_pTRTCSDK)
//        {
//            m_pTRTCSDK->stopRemoteView(userId);
//        }
//    }
}

void CLiveViodeProc::onUserAudioAvailable(const char* userId, bool available)
{
    QString sUserId = userId;
    if(sUserId.startsWith("m_"))
    {
        if(available)
        {
            if(/*m_bPlay && */m_pTRTCSDK)
            {
                m_pTRTCSDK->muteRemoteAudio(userId, false);
            }
        }
        else
        {
            m_bPlay = false;
            if(m_pTRTCSDK)
            {
                m_pTRTCSDK->muteRemoteAudio(userId, true);
            }
        }
    }
}

void CLiveViodeProc::onUserVoiceVolume(TRTCVolumeInfo* userVolumes, uint32_t userVolumesCount, uint32_t totalVolume)
{
    TRTCVolumeInfo *pVolumeInfo = userVolumes;
    for(int i = 0; i < userVolumesCount; i++)
    {
        QString sUserId = pVolumeInfo->userId;
        if(sUserId.startsWith("m_"))
        {
            emit invigilatorVolume(pVolumeInfo->volume);
        }
        pVolumeInfo++;
    }
}

void CLiveViodeProc::onConnectionLost()
{
    emit videoConnectionLost();
}

void CLiveViodeProc::onConnectionRecovery()
{
    emit videoConnectionRecovery();
}
