//
// 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 "QGAActionObjects.h"
#include "QGaVarFuncs.h"
#include "QGAOUtils.h"

#include <exception>
#include <src/dbg/QVdalJedpDebugger.h>

namespace jedge {

    static const char* gao_action_type_mgbus = "mgbus";

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

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

        //数据访问接口
        std::mutex              mmqq_;
        std::condition_variable wmqq_;

        qlibc::QRTimer          hbTimer = nullptr;  //mqtt心跳维持的timer

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

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

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

        SyncerPool                syncers_pool_;

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

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

        QVdalJedpDebugger       debugger_;

        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 setupBaseChannels(qlibc::QData &data);

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

        void restartHeartBeat();

        virtual void PoolHeartBeat() { }

    public:
        SyncerPool &getSyncerPool() override;

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

        virtual ~QGAPortPool();

        QJAMgServer& getOperator();

        virtual void buildPoolData();
        virtual void clearSiteData();

        std::string getPoolName() override;

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

        const std::string &getPoolBasePath() {
            return base_path_;
        }

        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);

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

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

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

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

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

        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();

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

        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, const std::string &tmplName = "");

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

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

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

        virtual void setupDefaultGaoFuncs();

        virtual void onFunctionFieldDefine(const std::string &pathKey, const std::string &funcKey, Json::Value &def, const std::string &tmplName = "") {}

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

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

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

        //显示cache变量的值
        void showCachedVars(const std::string &cacheVarKey, bool full, bool update, Json::Value* logs = nullptr);
        void showConsts(const std::string &cacheVarKey, bool full, Json::Value* logs = nullptr);

        void showCachedVar(const std::string &cacheVarKey,QGaCachedVar *var,bool full,  bool update, Json::Value* logs = nullptr, int line=-1);
        void showConstVar(const std::string &cacheVarKey, qlibc::QData *var,bool full = false, Json::Value* logs = nullptr, int line=-1);

        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 &getCacheFilePath() {
            return cache_file_path_;
        }

        void listGaoItems(const std::string& grepKey, Json::Value* logs = nullptr);

        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);

        void reloadPool();

        GaVarFinder *getVarFinder() override;

        QJAMgServer &getJAServer() override;

        QJAMgService &getJAService() override;

        QGAChannelHolder &getChannelPool() override;

        gaoFinder *getGaoFinder() override;

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

        void releasePoolData();

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

    protected:
         void handleConfigVars(string &result, const std::string &src) const;

        void setupExGaoActions(qlibc::QData& data);

        void setupMsgTemplates(QData &data);

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

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

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

        void updateTemplateCacheNames();

        void setupSystemCacheVar();

        virtual bool handleExTypeVar(Json::Value &ret, const std::string &type, const std::string &varKey);

        void initPoolControlCalls();

        void loadRestAvailableGaos(QData &data);

        void buildSingleActionDef(qlibc::QData &data, std::unordered_set<std::string> &channelKeys, const std::string &tmplName = "");

        virtual void onDataActionItemBuilt(QGaDataAction *action);

        virtual void onGaoActionObjectBuilt(const std::string &gaoPath, QGaDataAction *action);

        bool afterInnerActionCreated(QGaDataAction *action, string &fullPathKey, const string &propKey, Json::Value &subDef);
    public:
        string getBreifInfo();

        void copyConstsToGlobalTable();
    };

    using QGAPortPoolR = std::shared_ptr<QGAPortPool>;

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

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

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

    class JE_API QGaPoolCtrlChannel : public QGADataChannel {
    protected:
        QGAPortPool &pool_;

    public:
        explicit QGaPoolCtrlChannel(QGAPortPool &site): pool_(site) {}

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

}

#endif //INC_1_LIBDEVCPP_QGADATAPOOL_H
