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

#ifndef INC_1_LIBDEVCPP_QGADATAPOOL_H
#define INC_1_LIBDEVCPP_QGADATAPOOL_H


#include <qlibc/qlibc.h>
#include <jadom2/JABaseDom.h>
#include <exlib/QJAServer.h>
#include <exlib/QJAService.h>
#include <exlib/QMqttClient.h>
#include <exlib/http/QHttpSSLClient.h>

#include "gao/QGAActionObjects.h"
#include "gao/QGaVarFuncs.h"

#include "QJAGafficUtil.h"
#include <exception>

namespace jedge {


    //系统方法调用的响应者
    using SiteCtrLMethodHandler = std::function<bool(qlibc::QData& msg, qlibc::QData* resp)>;

    //一个数据池。
    class JE_API QGADataPool :
            public qlibc::QData, public QGADataPoolBase {
    protected:
        QJAMgServer &opr_;
        QJAMgService &service_;

        std::string base_path_;
        std::string cache_file_path_;
        bool quit_ = false;

#ifdef DEBUG
        bool debugging_message_ = true;
#else
        bool debugging_message_ = false;
#endif
        std::recursive_mutex dp_m_;

        //数据访问接口
        jedge::QMqttClient*     mqtt_Client_ = nullptr;
        jedge::QHttpSSLClient*  ssl_client_ = nullptr;
        jedge::QHttpClient*     http_client_ = nullptr;
        std::mutex              mmqq_;
        std::condition_variable wmqq_;

        QStringList             mqttTopics_;
        std::string             default_publish_;
        qlibc::QRTimer          hbTimer = nullptr;  //mqtt心跳维持的timer

        qlibc::QPObjectHolder<QGaCachedVar>  glvars_;  //全局的对象
        qlibc::QPObjectHolder<QGaCachedVar>  glvars_idx_;  //全局的对象
        qlibc::QPObjectHolder<GaUserDefFunction>  glUdFuncs_;  //全局的对象
        qlibc::QPObjectHolder<GaUserDefFunctionVar>  glUdVarFuncs_;  //全局的对象

        //数据源
        qlibc::QPObjectHolder<QGaDataAction> gaoPool_;

        //数据通道,不重置
        QGAChannelHolder          channelPool_;

        qlibc::QPObjectHolder<int>
                                deliverIndexKeys_;  //已经支持的indexKey的计数

        gaoFinder*              gao_finder_;
        GaAutoCacher*           auto_cacher_;
        GaVarFinder*            var_finder_;
        GaMsgEncryptor*         msg_encryptor_;
        QGaCachedVarUpdater*    cache_auto_savor_;
        QGaRedirector*          redirector_;

        qlibc::QPObjectHolder<SiteCtrLMethodHandler>  glSysCalls_;  //全局的对象

        qlibc::QPObjectHolder<QGaMsgTemplate>  glMsgTemplates_;  //全局的对象

        //    protected:
        std::string checkFileInPath(const std::string& fileName) {
            return fileName.empty()?"": FileUtils::contactFilename(base_path_, fileName);
        }

        std::string getFullSiteFilePath(const std::string& fileName) {
            return FileUtils::contactFilename(base_path_, fileName);
        }

        void setupCachedVars(qlibc::QData &data);

        virtual void setupMgbusConnection(qlibc::QData &data);

        virtual void setupMqttConnection(qlibc::QData &data);

        virtual void setupHttpSSL(qlibc::QData &data);

        virtual void setupHttp(qlibc::QData &data);

        virtual void setupUserChannel(const std::string& channel, qlibc::QData &data);

        void buildDataActions(const std::string& conn, QData &data);

        virtual void reprepareMqttTopics(const qlibc::QData& data);;

        virtual bool decodeMqttMessage(const std::string& topic, void *payload, int payloadLen, char* buffer, int* len) {return false; };

        virtual bool encryptMqttMessage(const std::string& payload, std::string& encryptOut) {return false; };

        virtual bool handleMqttMessage(const std::string &topic, qlibc::QData &message);

        virtual void resyncMqttStatus() {};

        void restartHeartBeat();

        virtual void mqttHeartBeat();

        bool returnMqttMessage(const std::string& topic, qlibc::QData& message) {
            message.putString("topic",topic);
            return returnMqttMessage(message);
        }

        bool returnMqttMessage(qlibc::QData& message);

    public:
        explicit QGADataPool(QJAMgServer &server, QJAMgService &service, qlibc::QData& siteCfg, const std::string& name, std::string basePath);

        virtual ~QGADataPool();

        QJAMgServer& getOperator();

        virtual void buildSiteData();
        virtual void clearSiteData();

        std::string getSiteName() override;

        inline const std::string& getDeviceSerialNumber() {
            return service_.getLocalMgbusHostSn();
        };

        QGaDataAction* findGAO(const std::string &fullKey);

        QGaDataAction* findGAO(const std::string& conn, const std::string& gatype, const std::string &objKey);

        QGaDataAction* findDeliverGAO(const std::string& conn, const std::string& indexKey, const std::string &objKey);

        virtual QGaDataAction *createActionFromValue(std::string& key, const char *type, const Json::Value &value);

        void buildDataChannelActions(QGaChannelActionList &tempChannelActions, const std::string& kk, const Json::Value &value);


        /**
         * request是单纯的对外动作,并可在deliver动作或cylcer动作中被引用。
         * request 动作中,可引用cache、log或其它request动作,但无法调用return等动作。
         *  可根据结果进行不同的cache动作调用
         */
        virtual QGaDataAction *createDeliverActionFromValue(const std::string& key, const Json::Value &value);

        virtual QGaDataAction *createRequestActionFromValue(const std::string& key, const Json::Value &value);

        /**
         *  自定义响应函数
         */
        void addUserDefinedGAO(const std::string& channelPathKey, const QGaActionImpl& handler);

        void addUserMgbusDeliverGAO(const string &actionkey, const QGaActionImpl& handler) {
            addUserDefinedGAO("mgbus.deliver.uri."+actionkey, handler);
        }

        void addUserMqttDeliverGAO(const string &idxKey, const string &actionkey, const QGaActionImpl& handler) {
            addUserDefinedGAO("mqtt."+idxKey+"."+actionkey, handler);
        }

        void addUserHttpsRequestGAO(const string &actionkey, const QGaActionImpl& handler) {
            addUserDefinedGAO("https.request."+actionkey, handler);
        }

        void addUserDefineGAO(const std::string &userArea, const  std::string& indexKey, const QGaActionImpl& handler) {
            addUserDefinedGAO(userArea+"."+indexKey, handler);
        }

        virtual void handleMqttOfflineEvent(QData &data) {}

        //获取Cached的Key
        Json::Value *getCachedVarValue(const std::string& varKey);

        //获取Cached的Key
        QGaCachedVar *getCachedVar(const std::string& varKey) {
            return glvars_idx_.findObject(varKey);
        }

        bool mqttPublish(const std::string& topic, qlibc::QData& msg, int qos = 0) {
            if(mqtt_Client_!=nullptr && mqtt_Client_->isConnected())
                return mqtt_Client_->publish(topic, msg.toJSONString().c_str(), qos);
            return false;
        }

        bool mqttPublish(const std::string& topic, const char* buff, int qos = 0) {
            if(mqtt_Client_!=nullptr && mqtt_Client_->isConnected())
                return mqtt_Client_->publish(topic, buff, qos);
            return false;
        }

        bool httpSyncPost(const std::string& host, const std::string& uriKey, qlibc::QData& req, qlibc::QData& resp);

        bool httpsSyncPost(const std::string& host, const std::string& uriKey, qlibc::QData& req, qlibc::QData& resp);

        bool httpSyncPost(const std::string& uriKey, qlibc::QData& resp);

        bool httpsSyncPost(const std::string& uriKey,qlibc::QData& resp);

        bool mgbusRequest(const std::string& mod, const std::string& uriKey, qlibc::QData& req, qlibc::QData& resp) {
            return service_.postServiceRequest(mod, uriKey, req, resp);
        }

        bool mgbusMessage(const std::string& mod, const std::string& uriKey, qlibc::QData& req) {
            return service_.postServiceMessage(mod, uriKey, req);
        }

        bool mgbusRequest(const std::string& uriKey, qlibc::QData& resp);

        bool mgbusMessage(const std::string& uriKey);

        void stopHeartbeat();

        void defaultMqttHeartBeat();

        void prepareDefaultMqttParams(qlibc::QData& cfg, std::string& username, std::string& password, std::string& clientId);

        bool handleDefaultMqttMessage(const std::string &topic, qlibc::QData &msg);

        bool handleDefaultMgbusMessage(QData &req, QData *rsp);

        bool httpSyncPostRaw(const std::string& httpUri, const std::string& payload, const char* httpContent);

        bool httpsSyncPostRaw(const std::string& httpUri, const std::string& payload, const char* httpContent);

        virtual void prepareMqttParams(qlibc::QData& cfg, std::string& username, std::string& password, std::string& clientId);

        virtual bool handleMgbusMessage(QData &req, QData *rsp);

        QGaDataAction* buildDataChannelAction(const std::string &channel, const std::string &control, const std::string &cond, int ln, const Json::Value &actions);

        void autoCacheResult(const std::string &actKey, qlibc::QData &result);

        bool handleGaLocalVars(Json::Value &ret, const string &varKey, const qlibc::QData &msg);

        bool handleGaFunc(Json::Value &ret, const string &funcKey, const qlibc::QData &msg);

        void setupUserDefinedGaoFuncs();

        void bindUserDefinedGAOFunction(const std::string& funcKey, const GaUserDefFunction& funcBody);

        //针对某个uri的特殊处理逻辑
        void setupMgbusUserHandler(qlibc::QData& config, const std::string& udIndex);

        //消息子协议区分响应
        virtual auto handleUserHandler(const std::string& userKey, const std::string& indexKey, QData *req, QData *resp) -> bool;

        //显示cache变量的值
        void showCachedVars(const std::string &cacheVarKey, bool full, bool update);

        void showCachedVar(const std::string &cacheVarKey,QGaCachedVar *var,bool full,  bool update);

        void addCachedVar(const std::string &key, const std::string &path, QGaCachedVar *cachedVar);

        void checkRemoveKey(const std::string &oldKey);

        void saveCacheVar(QGaCachedVar *cv);

        void loadSavedCacheVar(QGaCachedVar *cv);

        const std::string &getDefaultPublishTopic();

        const std::string &getCacheFilePath() {
            return cache_file_path_;
        }

        void listGaoItems(const std::string& grepKey);

        bool runDirectGao(const std::string& fullKey,  qlibc::QData *req, qlibc::QData *resp);

        //触发系统事件
        bool invokeDPEvent(const std::string& channel, const std::string& evtKey, qlibc::QData &param);

        bool callGaoSystemMethod(const std::string &method, qlibc::QData &req, qlibc::QData *resp);

        void reloadSite();

        GaVarFinder *getVarFinder() override;

        QJAMgServer &getJAServer() override;

        QJAMgService &getJAService() override;

        QGAChannelHolder &getChannelPool() override;

        gaoFinder *getGaoFinder() override;

        void removeCacheData() {
            FileUtils::removeDir(cache_file_path_);
        }

        bool isDebuggingMessage() override;

        void setDebuggingMessage(bool debug = true) {
            debugging_message_ = debug;
        }

    protected:
        void addTopicString(const Json::Value &topicValue);

        void handleConfigVars(string &result, const string &src);

        void setupExGaoActions(qlibc::QData& data);

        //siteCtrl方法:加载自定义消息模板,清理自定义消息模板
        bool reloadMessageTempl(qlibc::QData &req, qlibc::QData *resp);
        bool clearMessageTempl(qlibc::QData &req, qlibc::QData *resp);

        void setupMsgTemplates(QData &data);

        void loadMessageTemplate(const string &tpFile);
        void clearMessageTemplate(const string &tpName);

        bool createDevlierDataActionByDefValue(const string &gaoPath, const Json::Value &actsDefObj,
                                               const string &tmplName="");

        void addDeliverKeyIndex(const std::string& key);

        void updateTemplateCacheNames();

        void setupSystemCacheVar();
    };

#define bindDeliverGaoHandler(_handler)  data_pool_->addUserMgbusDeliverGAO(#_handler, \
            [this](QGAChannelPool& pool, qlibc::QData *req, qlibc::QData *resp)->bool { \
                return this->_handler(pool,req,resp);\
            })

#define bindDeliverGaoHandlerFunc(_handler)  data_pool_->addUserMgbusDeliverGAO(#_handler, \
            [](QGAChannelPool& pool, qlibc::QData *req, qlibc::QData *resp)->bool { \
                return _handler(pool,req,resp);\
            })

#define GaoHandler(_func,_pool,_r,_p) auto _func(QGAChannelHolder& _pool, qlibc::QData *_r, qlibc::QData *_p)->bool

    class JE_API QGaSiteCtrlChannel : public QGADataChannel {
    protected:
        QGADataPool &site_;

    public:
        explicit QGaSiteCtrlChannel(QGADataPool &site): site_(site) {}

        bool handleChannelMessage(QGaDataAction* action, qlibc::QData &msg, qlibc::QData* resp) override;
    };


}

#endif //INC_1_LIBDEVCPP_QGADATAPOOL_H
