#include "ToWeb.h"

namespace ai_matrix
{
    const int TIME_DIFF = 28800; // 8 hour
    ToWeb *ToWeb::ins = nullptr;
    ToWeb::GarbageCollector ToWeb::gc;
    std::mutex ToWeb::mx;

    ToWeb *ToWeb::getins()
    {
        //双层锁，确保线程安全
        if (ins == nullptr)
        {
            std::lock_guard<std::mutex> guard(mx); //防止异常发生不能解锁
            if (ins == nullptr)
            {
                ins = new ToWeb();
            }
        }
        return ins;
    }

    void ToWeb::setConfig(const HttpServerConfig &httpConfig) {
        this->httpConfig_ = httpConfig;
    }

    bool ToWeb::getToken() {
        try
        {
            httplib::Client cli(this->httpConfig_.strIp, this->httpConfig_.iPort);
            cli.set_connection_timeout(0, 300 * 1000);
            cli.set_read_timeout(0,300*1000);
            httplib::Headers header;
            httplib::Params params;

            header.emplace("Authorization", "Basic Y2xpZW50X2VudGVycHJpc2U6Y2xpZW50X2VudGVycHJpc2Vfc2VjcmV0");

            params.emplace("username", this->httpConfig_.strUserName);
            params.emplace("password", this->httpConfig_.strPassword);
            params.emplace("tenantId", "000000");
            params.emplace("grant_type", "password");
            auto res = cli.Post(this->httpConfig_.strTokenUrl, header, params);
            if (res)
            {
                if (res->status == 200)
                {
                    Json::CharReaderBuilder readerBuilder;
                    std::istringstream iss(res->body);
                    Json::Value root;
                    std::string errs;
                    bool parsingSuccessful = Json::parseFromStream(readerBuilder, iss, &root, &errs);

                    if (parsingSuccessful)
                    {
                        if (!root.get("token_type", "").asString().empty())
                        {
                            this->webToken = root["token_type"].asString();
                            this->webToken.append(" ");
                            this->webToken.append(root["access_token"].asString());
                            LogInfo << "已获取到web token";
                            return true;
                        }
                        else
                        {
                            LogError << "获取web token失败，原因：" << res->body;
                        }
                    }
                    else
                    {
                        LogError << "获取web token返回数据解析异常，返回数据非json。详细：" << res->body;
                    }
                }
            }
            else
            {
                auto err = res.error();
    //            if (err == httplib::Error::Connection) {
    //                std::cout << "   (连接出错)" << std::endl;
    //            }
                LogError << "获取web token失败！请检查网络或请求地址。详细：" << to_string(err);
            }
        }
        catch (std::exception &e)
        {
            LogError << "获取授权失败,原因：";
            LogError << e.what();
        }
        return false;
    }

    bool ToWeb::upWeb(const Json::Value &jvRequest, int retransmission) {
        try {
            Json::StreamWriterBuilder writer;
            std::string str = Json::writeString(writer, jvRequest);

            LogInfo << "第" << jvRequest["carriageOrder"].asInt() << "节，发送web: " << str;

            httplib::Client cli(this->httpConfig_.strIp, this->httpConfig_.iPort);
            cli.set_connection_timeout(0, 300 * 1000);
            cli.set_read_timeout(3,0);
            httplib::Headers header;
            httplib::Params params;
            header.emplace("blade-auth", this->webToken);
            //header.emplace("Content-Type", "application/json");

            auto res = cli.Post(this->httpConfig_.strUpResultUrl, header, str, "application/json");
            if (res)
            {
                if (res->status == 200)
                {
                    LogInfo << "第" << jvRequest["carriageOrder"].asInt() << "节，web返回: " << res->body;
                    Json::CharReaderBuilder readerBuilder;
                    std::istringstream iss(res->body);
                    Json::Value root;
                    std::string errs;
                    bool parsingSuccessful = Json::parseFromStream(readerBuilder, iss, &root, &errs);
                    if (parsingSuccessful)
                    {
                        if (root["success"].asBool())
                        {
                            return true;
                        }
                        else
                        {

                            if (root["msg"].asString() == "请求未授权") {
                                LogWarn << "第" << jvRequest["carriageOrder"].asInt() << "节，因请求未授权，而上传识别结果失败！重新请求token。";
                                if (!this->getToken()) return false;
                                return this->upWeb(jvRequest, retransmission);
                            }
                            LogError << "第" << jvRequest["carriageOrder"].asInt() << "节，识别结果上传失败，原因：" << root["msg"].asString();
                        }
                    }
                    else
                    {
                        LogError << "第" << jvRequest["carriageOrder"].asInt() << "节，识别结果上传失败，返回数据解析异常，返回数据非json：" + res->body;
                    }
                }
                else
                {
                    LogError << "第" << jvRequest["carriageOrder"].asInt() << "节，识别结果上传失败，原因：" << res->status << " - " << res->body;
                    if (res->status == 401) {
                        LogWarn << "因请求未授权，而上传识别结果失败！重新请求token。";
                        this->getToken();
                        return this->upWeb(jvRequest, retransmission);
                    }
                }
            }
            else
            {
                LogError << "第" << jvRequest["carriageOrder"].asInt() << "节，上传数据失败(超时)，请检查网络，或者上传地址！计划重新上传次数：" << retransmission;
                if (retransmission > 0) return this->upWeb(jvRequest, --retransmission);
            }
        }
        catch (std::exception &e)
        {
            LogError << "第" << jvRequest["carriageOrder"].asInt() << "节，上传识别结果失败,原因：";
            LogError << e.what();
        }
        return false;
    }

    bool ToWeb::upDeviceStatus(const Json::Value &jvRequest, int retransmission) {
        try {
            Json::StreamWriterBuilder writer;
            std::string str = Json::writeString(writer, jvRequest);

            LogInfo << "设备状态报警，发送web: " << str;

            httplib::Client cli(this->httpConfig_.strIp, this->httpConfig_.iPort);
            cli.set_connection_timeout(0, 300 * 1000);
            cli.set_read_timeout(3,0);
            httplib::Headers header;
            httplib::Params params;
            header.emplace("blade-auth", this->webToken);
            //header.emplace("Content-Type", "application/json");

            auto res = cli.Post(this->httpConfig_.strUpDeviceStatusUrl, header, str, "application/json");
            if (res)
            {
                if (res->status == 200)
                {
                    LogInfo << "设备状态报警，web返回: " << res->body;
                    Json::CharReaderBuilder readerBuilder;
                    std::istringstream iss(res->body);
                    Json::Value root;
                    std::string errs;
                    bool parsingSuccessful = Json::parseFromStream(readerBuilder, iss, &root, &errs);
                    if (parsingSuccessful)
                    {
                        if (root["success"].asBool())
                        {
                            return true;
                        }
                        else
                        {

                            if (root["msg"].asString() == "请求未授权") {
                                LogWarn << "设备状态报警，因请求未授权，而上传识别状态失败！重新请求token。";
                                if (!this->getToken()) return false;
                                return this->upDeviceStatus(jvRequest, retransmission);
                            }
                            LogError << "设备状态报警，识别状态上传失败，原因：" << root["msg"].asString();
                        }
                    }
                    else
                    {
                        LogError << "设备状态报警，识别状态上传失败，返回数据解析异常，返回数据非json：" + res->body;
                    }
                }
                else
                {
                    LogError << "设备状态报警，识别状态上传失败，原因：" << res->status << " - " << res->body;
                    if (res->status == 401) {
                        LogWarn << "因请求未授权，而上传识别状态失败！重新请求token。";
                        this->getToken();
                        return this->upDeviceStatus(jvRequest, retransmission);
                    }
                }
            }
            else
            {
                LogError << "设备状态报警，上传数据失败(超时)，请检查网络，或者上传地址！计划重新上传次数：" << retransmission;
                if (retransmission > 0) return this->upDeviceStatus(jvRequest, --retransmission);
            }
        }
        catch (std::exception &e)
        {
            LogError << "设备状态报警，上传识别状态失败,原因：";
            LogError << e.what();
        }
        return false;
    }

}
