//
// Created by matrixai on 10/26/24.
//

#include "ControlEngine.h"

ControlEngine::ControlEngine() {}

ControlEngine::~ControlEngine() {}

APP_ERROR ControlEngine::Init()
{
    // 传给web socket 引擎
    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    // 发给箱号推理引擎
    strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1";
    // 发送箱角推理引擎
    strPort2_ = engineName_ + "_" + std::to_string(engineId_) + "_2";
    // 发给存储文本引擎
    strPort3_ = engineName_ + "_" + std::to_string(engineId_) + "_3";
    // 发给存图引擎
    strPort4_ = engineName_ + "_" + std::to_string(engineId_) + "_4";

    this->baseConfig_ = Config::getins()->getBaseConfig();
    this->identifyConfig_ = Config::getins()->getIdentifyConfig();
    this->vecDataSourceConfig_ = Config::getins()->getAllDataSourceConfig();

    this->initParam();
    LogInfo << "ControlEngine Init ok";
    return APP_ERR_OK;
}

APP_ERROR ControlEngine::DeInit()
{
    LogInfo << "ControlEngine DeInit ok";
    return APP_ERR_OK;
}

/**
* 参数初始化(识别结束时需调用)
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void ControlEngine::initParam()
{
    this->strDetectDate_ = "";
    for (int i = 0; i < this->vecDataSourceConfig_.size(); ++i)
    {
        this->mapDetectNO_[i] = 0;
        this->mapIdentifyType_[i] = IDENTIFY_INIT;

    }
}

void ControlEngine::endIdentify(int iDataSource)
{
    std::shared_ptr<VDetectInfo> pVDetectInfo = std::make_shared<VDetectInfo>();
    pVDetectInfo->bIsEnd = true;
    pVDetectInfo->iDataSource = iDataSource;
    pVDetectInfo->strDetectDate = this->strDetectDate_;
    pVDetectInfo->strDetectTime = this->strDetectTime_;
    // 传给推理引擎
    outputQueMap_[strPort1_]->push(std::static_pointer_cast<void>(pVDetectInfo), true);
    outputQueMap_[strPort2_]->push(std::static_pointer_cast<void>(pVDetectInfo), true);

    this->mapDetectNO_[iDataSource] = 0;
    this->mapIdentifyType_[iDataSource] = IDENTIFY_INIT;

    LogInfo << " 数据源：" << iDataSource << " --- 识别结束!";
}

void ControlEngine::sendWSEngine(std::string msg)
{
    msg = "{\"containerNo\":\"\",\"detectDate\":\"\",\"detectTime\":\"\",\"id\":\"\",\"images\":\"\",\"imagesDir\":\"\",\"status\":\"normal\",\"msg\":\"" + msg +"\"}";
    // 传给websocket引擎
    outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(std::make_shared<std::string>(msg)));
}

bool ControlEngine::isDetecting()
{
    for (const auto & dataSource : this->mapIdentifyType_)
    {
        if (dataSource.second == IDENTIFY_START)
        {
            return true;
        }
    }

    return false;
}

void ControlEngine::detectControl(std::shared_ptr<std::string> pWSServerOrder)
{
    Json::CharReaderBuilder readerBuilder;
    std::istringstream iss(*pWSServerOrder);
    Json::Value jvOrder;
    std::string errs;
    bool parsingSuccessful = Json::parseFromStream(readerBuilder, iss, &jvOrder, &errs);
    if (!parsingSuccessful)
    {
        std::string msg = "Web Socket 接口调用参数异常，所传数据非json：" + *pWSServerOrder;
        LogError << msg;
        this->sendWSEngine(msg);
        return;
    }

    if (!jvOrder.isObject() || !jvOrder.isMember("id") || !jvOrder.isMember("commandType"))
    {
        std::string msg = "Web Socket 接口调用参数异常，所传数据缺少核心字段：" + *pWSServerOrder;
        LogError << msg;
        this->sendWSEngine(msg);
        return;
    }

//    if (jvOrder["commandType"].asInt() != 1 && jvOrder["commandType"].asInt() != 2)
//    {
//        std::string msg = "Web Socket 接口调用参数异常，所传状态不正确：" + *pWSServerOrder;
//        LogError << msg;
//        this->sendWSEngine(msg);
//        return;
//    }

    switch (jvOrder["commandType"].asInt()) {
        case IDENTIFY_START:

            if (this->isDetecting())
            {
                std::string msg = "当前正在识别，无需重复发送识别信号";
                LogWarn << msg;
                this->sendWSEngine(msg);
                break;
            }
            this->mapIdentifyType_ = {{0, IDENTIFY_START}, {1, IDENTIFY_START}, {2, IDENTIFY_START}};
            g_car_type = 1;
            break;
        case IDENTIFY_STOP:
            if (!this->isDetecting())
            {
                std::string msg = "当前已停止识别，无需重复发送结束信号";
                LogWarn << msg;
                this->sendWSEngine(msg);
                break;
            }
            this->mapIdentifyType_ = {{0, IDENTIFY_INIT}, {1, IDENTIFY_INIT}, {2, IDENTIFY_INIT}};
            g_car_type = 0;
            break;
        case IDENTIFY_RECORD:
            if (!jvOrder.isMember("containerNo"))
            {
                std::string msg = "Web Socket 接口调用参数异常，所传数据缺少核心字段：" + *pWSServerOrder;
                LogError << msg;
                this->sendWSEngine(msg);
                break;
            }
            {
                std::string msg = "{\"status\":\"normal\",\"containerNo\":" + jvOrder["containerNo"].asString() +"}";
                // 传给websocket引擎
                outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(std::make_shared<std::string>(msg)));
            }
            break;
        default:
            std::string msg = "Web Socket 接口调用参数异常，所传状态不正确：" + *pWSServerOrder;
            LogError << msg;
            this->sendWSEngine(msg);
            break;
    }
}

APP_ERROR ControlEngine::Process()
{
    while (!isStop_)
    {
        //pop端口0，接收命令
        std::shared_ptr<void> pVoidData0 = nullptr;
        inputQueMap_[strPort0_]->pop(pVoidData0);
        if (nullptr != pVoidData0)
        {
            std::shared_ptr<std::string> pWSServerOrder = std::static_pointer_cast<std::string>(pVoidData0);

            this->detectControl(pWSServerOrder);
        }

        //pop端口1，解码后数据
        std::shared_ptr<void> pVoidData1 = nullptr;
        inputQueMap_[strPort1_]->pop(pVoidData1);

        if (nullptr != pVoidData1)
        {
            std::shared_ptr<ProcessData> pProcessData = std::static_pointer_cast<ProcessData>(pVoidData1);

            if (pProcessData->bIsEnd)
            {
                if (!this->isDetecting()) continue;
//                if (this->strDetectDate_.empty())
//                {
//                    std::string msg = "数据源：" + std::to_string(pProcessData->iDataSource) + " 摄像头读取画面失败，停止识别！";
//                    this->sendWSEngine(msg);
//                    this->mapIdentifyType_[pProcessData->iDataSource] = IDENTIFY_INIT;
//                    continue;
//                }
                
                this->endIdentify(pProcessData->iDataSource);
                LogInfo << "数据源:" << pProcessData->iDataSource << " 画面读取结束：停止识别！";
                continue;
            }

            if (!this->isDetecting())
            {
                if (this->mapDetectNO_[pProcessData->iDataSource] > 0)
                {
                    this->endIdentify(pProcessData->iDataSource);
                }
                this->strDetectDate_ = "";
                continue;
            }

            if (this->mapIdentifyType_[pProcessData->iDataSource] == IDENTIFY_INIT)
            {
                continue;
            }

            if (this->mapDetectNO_[pProcessData->iDataSource] > this->identifyConfig_.iMaxIdentifyFrame)
            {
                LogInfo << " 数据源:" << pProcessData->iDataSource << " 超过最大允许识别帧数：" << this->identifyConfig_.iMaxIdentifyFrame << " 停止识别！";
                this->endIdentify(pProcessData->iDataSource);
                continue;
            }

            this->mapDetectNO_[pProcessData->iDataSource]++;

            cv::Mat image(pProcessData->dataSourceInfo.iHeight,
                    pProcessData->dataSourceInfo.iWidth,
                    CV_8UC3,
                    static_cast<uint8_t*>(pProcessData->sourceFrameData.pData.get()));

            if (this->strDetectDate_.empty())
            {
                this->strDetectDate_ = ai_matrix::TimeUtil::getins()->getDate();
                this->strDetectTime_ = ai_matrix::TimeUtil::getins()->getTime();
                //创建该该列车的数据存储目录(防止后续多线程创建报错)
                std::string strTrainPath = this->baseConfig_.strDebugResultPath + "/"
                                           + strDetectDate_ + "/"
                                           + ai_matrix::StringUtil::getins()->replace_all_distinct(strDetectTime_, ":", "-") + "/";
                ai_matrix::FileUtil::getins()->createDirPath(strTrainPath);
                std::string strBestImgPath = baseConfig_.strResultPath + "/"
                                             + strDetectDate_ + "/"
                                             + ai_matrix::StringUtil::getins()->replace_all_distinct(strDetectTime_, ":", "-") + "/";
                ai_matrix::FileUtil::getins()->createDirPath(strBestImgPath);
            }

            std::string strFilePath = baseConfig_.strDebugResultPath + "/"
                                      + strDetectDate_ + "/"
                                      + StringUtil::getins()->replace_all_distinct(strDetectTime_, ":", "-")
                                      + "/";

            // 识别 + 存文本
            std::shared_ptr<VDetectInfo> pVDetectInfo = std::make_shared<VDetectInfo>();
            pVDetectInfo->iDataSource = pProcessData->iDataSource;
            pVDetectInfo->strFilePath = strFilePath;
            pVDetectInfo->strFileName = std::to_string(this->mapDetectNO_[pProcessData->iDataSource]) + "_" + std::to_string(pProcessData->iDataSource) + ".json";
            pVDetectInfo->iFrameId = this->mapDetectNO_[pProcessData->iDataSource]; //当前帧号
            pVDetectInfo->i64TimeStamp = pProcessData->sourceFrameData.i64TimeStamp;
            pVDetectInfo->bIsEnd = pProcessData->bIsEnd;
            pVDetectInfo->strDetectDate = strDetectDate_;
            pVDetectInfo->strDetectTime = strDetectTime_;
            pVDetectInfo->cvImage = image;
            outputQueMap_[strPort1_]->push(std::static_pointer_cast<void>(pVDetectInfo), true);
            outputQueMap_[strPort2_]->push(std::static_pointer_cast<void>(pVDetectInfo), true);
            outputQueMap_[strPort3_]->push(std::static_pointer_cast<void>(pVDetectInfo), true);

            // 存图
            std::shared_ptr<SaveImgData> pSaveImgData = std::make_shared<SaveImgData>();
            pSaveImgData->strFilePath = strFilePath;
            pSaveImgData->strFileName = std::to_string(this->mapDetectNO_[pProcessData->iDataSource]) + "_" + std::to_string(pProcessData->iDataSource) + ".jpg";
            pSaveImgData->cvImage = image;
            pSaveImgData->bIsEnd = pProcessData->bIsEnd;
            outputQueMap_[strPort4_]->push(std::static_pointer_cast<void>(pSaveImgData), true);

            
        }

    }
    return APP_ERR_OK;
}
