#include "local_server.hpp"
#include <string.h>
#include <zlog.h>
#include <json/json.h>
#include "common/global.hpp"
#include "common/common_func.hpp"
#include "mqttclient/mqtt_client.h"
#include "dbaccess/sql_db.hpp"
#include "utility/secure.hpp"
#include "scheduler/schedule.hpp"
#include "jsonparse/communication_cmd.hpp"

extern zlog_category_t *zct;

LocalServer::LocalServer() {}

LocalServer::~LocalServer() { zlog_info(zct, "~LocalServer is called!"); }

void LocalServer::HandleFromServer(const char *pData_r, int pLen, const char *topic) {
    if (pLen == 0) {
        return;
    }

    std::string data_r = (std::string)(pData_r);
    zlog_info(zct, "MQTT recv  base64 %s", data_r.c_str());
    char *base64_data = new char[data_r.length()];
    memset(base64_data, 0, data_r.length());
    secure::instance().Base64Decode(data_r.c_str(), (unsigned char *)base64_data);
    std::string pData = std::string(base64_data);
    delete[] base64_data;
    zlog_info(zct, "MQTT recv  %s", pData.c_str());
    Json::Reader recvReader;
    Json::Value recvValue;
    Json::Value recvBody;
    if (recvReader.parse(pData, recvValue)) {
        int cmdType = atoi(recvValue["cmd"].asString().c_str());
        if (cmdType == 41) {
            recvBody = recvValue["cmdBody"];
        } else {
            std::string cmdBody = recvValue["cmdBody"].asString();
            if (!recvReader.parse(cmdBody, recvBody)) {
                zlog_error(zct, "recv body error, content:[%s]", cmdBody.c_str());
                return;
            }
        }

        switch (cmdType) {
            // case kHWStatus: {
            //     JsonData jd;
            //     std::string data = jd.JsonCmd_07();
            //     data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            // } break;
            case kRebootSystem: {
                recvValue["dataNodeGatewayNo"] = GlobalConfig::MacAddr_G;
                recvValue["status"] = "ACK";
                Json::FastWriter fw;
                std::string strjson = fw.write(recvValue);
                data_publish(strjson.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
                system("sync");
                sleep(3);
                system("reboot");
            } break;
            case kTiming: {
                std::string timestamp = recvBody["timestamp"].asString();
                unsigned long itimestamp = atol(timestamp.c_str());
                char localtimestamp[32] = {0};
                GetTimeNet(localtimestamp, 1);
                std::string current_system_timestamp = std::string(localtimestamp);
                unsigned long current_timestamp = boost::lexical_cast<unsigned long>(current_system_timestamp);
                unsigned long diff_seconds = abs(current_timestamp - itimestamp);
                if (diff_seconds > 5) {
                    SetTime(itimestamp);
                    mssleep(200);
                    system("hwclock -w");
                    scheduler::instance().ModifyScheduleTs(itimestamp - current_timestamp);
                    if (!recvValue["ZoneId"].isNull() && recvValue["ZoneId"].asString().length() > 0) {
                        std::string zoneid = recvValue["ZoneId"].asString();
                        ZoneConfig(zoneid);
                    }
                } else {
                    zlog_warn(zct, "[Timing] diff seconds:%ld lesser than 5, not to modify", diff_seconds);
                }
            } break;
            case 13: {
                std::string type = recvValue["type"].asString();
                if (type.compare("delete") == 0) {
                    WriteStr2Config(SERVERCONFIG, "Server", "localServerIpAddress", "0.0.0.0");
                    GlobalConfig::ServerIP.clear();
                    exit(0);
                }
            } break;
            case kModifyProperty: {
                Param_20 param;
                param.mCmdSerial = recvValue["cmdSerial"].asString();
                std::string type = recvBody["type"].asString();
                if (0 == type.compare("SET")) {
                    param.mMode = 0;
                    param.mDataWatchName = recvBody["SystemInfo"]["dataNodeGatewayName"].asString();
                    param.mDataWatchAssetId = recvBody["SystemInfo"]["dataNodeGatewayAssetId"].asString();
                    param.mDataWatchAddedBy = recvBody["SystemInfo"]["dataNodeGatewayAddedBy"].asString();
                } else {
                    param.mMode = 1;
                }
                JsonData jd;
                std::string data = jd.JsonCmd_20(param);
                zlog_info(zct, "20 data: %s", data.c_str());
                data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            } break;
            case kTimeZone: {
                Param_22 param;
                std::string type = recvBody["type"].asString();
                param.mCmdSerial = recvValue["cmdSerial"].asString();

                if (0 == type.compare("SET")) {
                    param.mMode = 0;
                    param.mTimeZone = recvBody["timezone"].asString();
                    ZoneConfig(param.mTimeZone);
                } else {
                    param.mMode = 1;
                }
                JsonData jd;
                std::string data = jd.JsonCmd_22(param);
                data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            } break;
            case kMqttBrokerCfg: {
                std::string type = recvBody["type"].asString();
                Param_23 param;
                param.mCmdSerial = recvValue["cmdSerial"].asString();
                if (0 == type.compare("SET")) {
                    param.mMode = 0;
                    param.mServerIp = recvBody["localServerIpAddress"].asString();
                    param.mPort = std::to_string(recvBody["localServerPort"].asInt());
                    param.mCommMode = std::to_string(recvBody["CommMode"].asInt());
                } else {
                    param.mMode = 1;
                }
                JsonData jd;
                std::string data = jd.JsonCmd_23(param);
                data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            } break;
            case kNetworkCfg: {
                Param_25 param;
                param.mCmdSerial = recvValue["cmdSerial"].asString();
                std::string type = recvBody["type"].asString();
                if (0 == type.compare("SET")) {
                    param.mDnsName = recvBody["dnsName"].asString();
                    param.mGateway = recvBody["gateway"].asString();
                    param.mHostName = recvBody["hostName"].asString();
                    param.mIp = recvBody["dataWatchIpAddress"].asString();
                    param.mSubnetMask = recvBody["subnetMask"].asString();
                    param.mNetworkPortStatus = recvBody["networkPortStatus"].asString();
                    param.mMode = 0;
                } else {
                    param.mMode = 1;
                }
                JsonData jd;
                std::string data = jd.JsonCmd_25(param);
                data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            } break;
            case kGetTransducerInfo: {
                Param_26 param;
                param.mCmdSerial = recvValue["cmdSerial"].asString();
                std::string type = recvBody["type"].asString();
                JsonData jd;
                std::string data = jd.JsonCmd_26(param);
                data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            } break;
            case kDeleteTransducerInfo: {
                Param_27 param;
                param.mCmdSerial = recvValue["cmdSerial"].asString();

                JsonData jd;
                std::string data = jd.JsonCmd_27(recvBody);
                data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            } break;
            case kExecuteShellScript: {
                JsonData jd;
                std::string data = jd.JsonCmd_50(recvBody);
                data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            } break;
            case kSetTransducerInfo: {
                JsonData jd;
                Param_41 param;
                std::vector<Param_41> param41;
                for (size_t i = 0; i < recvBody.size(); i++) {
                    param.mdataNodeNo = recvBody[i]["dataNodeNo"].asString();
                    param.mfeatureInterVal = recvBody[i]["featureInterVal"].asInt();
                    param.mwaveInterVal = recvBody[i]["waveInterVal"].asInt();
                    param.msamplingRate = recvBody[i]["samplingRate"].asInt();
                    param.mrange = recvBody[i]["range"].asInt();
                    param.mAccSampleTime = recvBody[i]["ACCSampleTime"].asInt();
                    param.mstartBrands = recvBody[i]["startBrands"].asString();
                    param.mstopBrands = recvBody[i]["stopBrands"].asString();
                    param.menvelopeBandPass = recvBody[i]["envelopeBandPass"].asString();
                    param.mviff = recvBody[i]["viff"].asInt();
                    param.mfaultFrequency = recvBody[i]["faultFrequency"].asString();
                    param.ZigbeePower = recvBody[i]["ZigbeePower"].asInt();
                    param.ZigbeeRetry = recvBody[i]["ZigbeeRetry"].asInt();
                    param41.push_back(param);
                }
                std::string data = jd.JsonCmd_Cgi_41(param41, 1);
                char whereCon[64] = {0};
                sprintf(whereCon, " UpdateFlag <> 1 ");
                std::string strData = sqlite_db_ctrl::instance().GetNodeConfigureInfor(whereCon);
                data_publish(strData.c_str(), GlobalConfig::Topic_G.mPubConfig.c_str());

            } break;
            case kModifyTestPointId: {
                JsonData jd;
                std::string data = jd.JsonCmd_51(recvBody);
                data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            } break;
            case kModifyTransducerLoose: {
                JsonData jd;
                std::string data = jd.JsonCmd_53(recvBody);
                data_publish(data.c_str(), GlobalConfig::Topic_G.mPubCmd.c_str());
            } break;
            default: break;
        }
        zlog_info(zct, "cmdType : %d ", cmdType);

    } else {
        zlog_error(zct, "parse fail, content:[%s]", pData.c_str());
    }
}
