//
// Created by Ht on 2022/1/8.
//


/**
 *      开发测试支持工具，
 *          便于快速实现一些功能的测试。
 *
 */

#ifndef INC_0_LIBDEVCPP_QJAGAFFICSERVICE_H
#define INC_0_LIBDEVCPP_QJAGAFFICSERVICE_H

#include <exlib/QJAServiceEntry.h>
#include <exlib/http/QHttpServer.h>
#include "debug/JAVdaoDebuggers.h"

namespace jedge {

#define getFieldCStr(_field, _jsobj) \
    const auto* _field = (_jsobj).isMember(#_field) ? h.operator[](#_field).asCString() : ""
#define getFieldVal(_field, _jsobj) \
    auto _field = (_jsobj).isMember(#_field) ? h.operator[](#_field) : Json::nullValue;

    static const char* fileMsg = R"({"code":200,"payload":[{"device_mode":"SmartPadOs","item_key":"android-px30-v1","ver":"%s"}]})";
    static const char* vkey_target_info_query_module_ = "cpad";
    static const char* sval_mod_target = "vdalt";

    class JE_API JEDebugTargetDevice {
    public:
        std::string                 mModule;
        std::string                 mPanelName;
        std::string                 mPanelSn;
        std::string                 mPanelIp;
        std::string                 mAppVer;
        std::string                 mGateVer;
        std::string                 mSysVer;

        Json::Value                 mUpdateMeshDevs;
        Json::Value                 mDevices;

        explicit JEDebugTargetDevice(std::string mod, std::string panel,
                                     std::string sn, std::string ip,
                                     std::string av, std::string gv,
                                     std::string ver) :
                mModule(std::move(mod)) ,
                mPanelName(std::move(panel)),
                mPanelSn(std::move(sn)),
                mPanelIp(std::move(ip)),
                mAppVer(std::move(av)),
                mGateVer(std::move(gv)),
                mSysVer(std::move(ver)),
                mUpdateMeshDevs(Json::arrayValue),
                mDevices(Json::arrayValue) {
        }
    };

    class JEMeshDevice {
    public:
        JEMeshDevice(std::string idx, std::string disc, std::string cap) :
                     key_(std::move(idx)), disc_(std::move(disc)),cap_(std::move(cap)) {
        }

        std::string key_;
        std::string disc_;
        std::string cap_;
    };

    class JADebugOperationService :
            public  QJAPluginService {
    protected:
        std::string         data_base_path_;          //
        std::string         target_module_;           //

        std::recursive_mutex m_;
        qlibc::QPObjectHolder<JEMeshDevice>
                            mDeviceTypes;
        qlibc::QPObjectHolder<JEDebugTargetDevice>
                            mJEdgeNodes;

        qlibc::QRTimer      showTimer;

        unsigned long       runCount = 0;
        bool                showNodes = false;

    public:
        explicit JADebugOperationService(jedge::QJAMgServer& opr, const std::string &name, const qlibc::QData &config);

        //面板操作:显示所有可用面板,设置活跃面板,显示当前活跃面板
        // panel    显示当前活跃的面板
        // panel -l 列举当前所有可用面板
        // panel <sn|a,b,c,...> 选择一个活跃节点用于开发
        bool panelOperation(qlibc::JCArgNode& param);

        //vdal端口操作
        // port             列举子命令帮助
        // port -l          列举远程面板的可用port
        // port <name>      选择一个远程port
        // port name <name> 选择一个远程port
        // port name        显示当前的已选port
        // port reload      远程port重载
        // port path [<newPath>] 显示本地vdao文件的路径[设置路径]
        // port local       列举本地的可用vdao文件
        // port list        列举远程可用的vdao资源文件
        // port upload  <file>   上传一个本地的vdao文件到远程动态vdao目录,并立即加载这个vdao文件
        // port remove  <file>   删除一个远程vdao资源文件
        // port show        显示远程port中已加载的vdao资源(gao -l <grepKey>)
        // port jedp-show   显示远程port中已加载的jedp资源项
        // port jedp-local  显示本地可用jedp资源
        // port jedp-upload 上传一个jedp文件到远程(如有同名文件,则覆盖之,覆盖后自动重载port)
    ImplementCommandHandler(portOperation, JAVdaoDebuggers);

        //设备操作
        // dev list         列举当前所有可用操作设备
        // dev              显示当前的设备操作对象
        // dev set <dev>    设置默认的设备操作对象
    ImplementCommandHandler(devOperation, JAVdaoDevOperator);

        //消息资源调式:  用于基于vdal的消息发送和返回调试.
        // sc                   显示子命令的帮助信息
        // sc path [<scPath>]   显示[设置]调试消息路径
        // sc list [<grep_key>] 列举scPath路径中的所有可用脚本文件
        // sc file [<name>]     设置本地默认脚本文件
        // sc show [<file>]     列举本地默认脚本[文件]中可用的消息
        // sc send [<file>.]<msgNo> 发送一个脚本消息(执行<file>.msgNo)
        // sc p,step [<file>.]<msgNo> 启动一个消息动作调试
        // sc n,next            执行消息的下一个响应,并观察返回的消息log
        // sc g,go              执行完毕当前的VDAO指令序列
        // sc c,cancel          取消当前单步执行系列
    ImplementCommandHandler(debugMessage, JAVdaoScRunner);

        //串口模拟消息调式:
        // ss                   显示子命令的帮助信息
        // sc path [<scPath>]   显示[设置]调试串口资源库的消息路径
        // ss list              列举scPath路径中的所有可用脚本文件
        // ss file [<name>]     列举本地脚本文件
        // ss show [<file>]     列举本地脚本文件中可用的消息
        // ss [<file>].no       发送一个文件资源中的串口(编号)消息的字节流到vdal模拟串口上报消息
        // ss "bytes"           发送一个串口命令
    ImplementCommandHandler(debugSerial, JAVdaoSerialEmulator);

        inline void markShowDebugNodes() {
            showNodes = true;
        }

        void checkPanelOnlineInfo(const std::string& mgnet, bool forceRecheck, bool showBle, bool showDev , QStringList& toDel, std::mutex& m);


        void checkMgbusNodeOffline(bool forceRecheck, bool showBle = false, bool showDev = false);

        void queryOnlineMgbusModules(QStringList& mods);

        void onServiceStart(const QData &config) override;

        void onServiceStop() override {
            //停止自动显示扫描到的panel列表
            operator_.timerEngineRef()->stopTimer(showTimer);
            MgService::onServiceStop();
        }


        const std::string& getCaptionOfDeviceType(const std::string& mode);

        const std::string& getDiscriptionOfDeviceType(const std::string& mode);

        void showMeshDevices(Json::Value &value, const char* showMark = qlog_LOG);

        //是否显示ble设备
        void showDebugNodeList(bool showBle = true, bool showDev = false, const std::string& PanelToShow = "");


        /**
         *      device.txt
         *          02 22,bubble,球泡灯
         *          01 01,gate,mesh网关
         *          ……
         * @param fn
         */
        void loadDeviceDefine(const std::string& fn);

        bool dbgLog(qlibc::QData &req, qlibc::QData *resp);

        void preparePattern() override {
            prepareSelfBind;
            bindHandler(dbgLog);
        }

        //mgnet, panelName, ip, appver, gatever, sysver
        bool checkMgbusNodeOk(const std::string &mgnet, std::string &panelName, std::string & ip,
                              std::string & appver, std::string & gatever, std::string & sysver,
                              bool forceRecheck = false);

        bool insertIfOldNotExistsNorEquals(const std::string &mgnet,const std::string &mod,const std::string &panelName,const std::string & sn, const std::string & ip,
                                           const std::string & appver, const std::string & gatever,const std::string & sysver);

        bool queryPanelInfos(const std::string &mgnet, const std::string &mod);

        bool OnModuleConnected(MgTriggerWatcher &w, const string &k, const QData &m) override;

        bool OnModuleDisconnected(MgTriggerWatcher &w, const string &k, const QData &m) override {
            emtpyWatchers();
            return QJAMgService::OnModuleDisconnected(w, k, m);
        }

    };

}
#endif //INC_0_LIBDEVCPP_QJAGAFFICSERVICE_H

