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

#ifndef INC_1_LIBDEVCPP_QGAACTIONOBJECTS_H
#define INC_1_LIBDEVCPP_QGAACTIONOBJECTS_H

#include <exlib/http/QHttpSSLClient.h>
#include <exlib/QJAService.h>
#include <exlib/QMqttClient.h>

#include <utility>

#include "QGABaseObject.h"
#include "QGaControllerUtil.h"
#include "QGaVarFuncs.h"

namespace jedge {

    static const char func_sign_ = '@';
    static const char* cache_auto_save_ = "ac";
    static const char* vkey_channel_call_ = "$call";
    //可以是 http/https/mgbus/mqtt/cache/log/return
    //设计多种channel通道，并将这些通道的发送函数记录进去。在DataPool中封装这些内容。

    class QGaDataAction;

    class JE_API QGADataChannel {
    protected:
        bool fast_str_call_ = false;
    public:
        virtual ~QGADataChannel() = default;

        virtual bool handleChannelMessage(QGaDataAction* action, qlibc::QData& msg, qlibc::QData* resp) = 0;

        virtual bool supportFastStrCall() {
            return fast_str_call_;
        }

    protected:
        bool checkAutocacheSet(qlibc::QData &msg) {
            auto autoCache = msg.getBool(cache_auto_save_);
            msg.removeKey(cache_auto_save_);
            return autoCache;
        }

        void clearFunctionField(qlibc::QData &msg) {
            clearJedgeCallInfo(msg);
            msg.removeString("~u");
        }
    };

    class JE_API QGAChannelHolder {
    protected:
        qlibc::QPObjectHolder<QGADataChannel> channels_;
    public:

        void addDataChannel(const std::string& type, QGADataChannel* channel){
            channels_.appendNew(type, channel);
        }

        QGADataChannel* findDataChannel(const std::string& type) {
            return channels_.findObject(type);
        }
    };

    class JE_API QGAActionObject : public QGABaseObject {

    protected:
        explicit QGAActionObject() : QGABaseObject() {}
        explicit QGAActionObject(const qlibc::QData &data) : QGABaseObject(data) {}
    };

    class QGaDataAction;

    using gaoFinder = std::function<QGaDataAction*(const std::string& indexKey, const std::string& channel)>;


    class JE_API QGADataPoolBase {
    public:
        virtual std::string     getPoolName() = 0;
        virtual GaVarFinder*    getVarFinder() = 0;
        virtual gaoFinder*      getGaoFinder() = 0;
        virtual QJAMgServer&    getJAServer() = 0;
        virtual QJAMgService&   getJAService() = 0;
        virtual QGAChannelHolder& getChannelPool() = 0;
        virtual SyncerPool &getSyncerPool() = 0;
    };

    /**
     *  描述一个程序体,可以是request、deliver。
     *      request：  单向向外发送请求，结果缓存或反馈给指定数据接收方
     *      deliver：  被其它数据源投递消息，可调用request或cache，可返回数据投递方数据
     *      cycler：   定时器，可请求第三方数据，或定时投递数据
    */

    using QGaChannelActionList = std::vector<QGaDataAction*>;

    class JE_API QGaDataAction : public QGAActionObject, QGaDataActionBase {
    protected:
        QGADataPoolBase& data_pool_;
        qlibc::QSharedObjectHolder<QGaDataActionController>*
                        controllers_ = nullptr;
        std::mutex  m_;

        //添加针对每个通道的行为
        QGaChannelActionList* subActions_ = nullptr;
        std::string channel_;
        std::string channel_call_;
        std::string full_key_;
        std::string control_;
        std::string cond_;
        std::string templ_;
        const int order_;
    protected:
        void makeChannelParams();

    public:
        explicit QGaDataAction(QGADataPoolBase& dp) : QGAActionObject(), data_pool_(dp), order_(9999)  {}

        explicit QGaDataAction(QGADataPoolBase& dp, const qlibc::QData& reqParam) :
                QGAActionObject(reqParam), data_pool_(dp), order_(9999)  {
        }

        explicit QGaDataAction(QGADataPoolBase& dp, std::string channel, const qlibc::QData& reqParam) :
                QGAActionObject(reqParam), data_pool_(dp), channel_(std::move(channel)), order_(9999) {
            makeChannelParams();
        }

        explicit QGaDataAction(QGADataPoolBase& dp, std::string channel) :
                QGAActionObject(), data_pool_(dp),channel_(std::move(channel)), order_(9999) {
            makeChannelParams();
        }

        explicit QGaDataAction(QGADataPoolBase& dp, int line, std::string control,  std::string cond) :
                QGAActionObject(qlibc::QData()), data_pool_(dp), control_(std::move(control)), cond_(std::move(cond)), order_(line) {
            StringUtils::trimString(control_);
            StringUtils::trimString(cond_);
        }

        ~QGaDataAction() override;

        virtual bool performAction(qlibc::QData *req, qlibc::QData *resp);

        void setUpSubChannelActions(QGaChannelActionList &connActions);

        SyncerPool &getSyncerPool() override;

    public:
        int getActionOrder() {
            return order_;
        }

        void setPathKey(const std::string& pathKey);

        void setMsgTemplateName(const std::string& templName) {
            templ_ = templName;
        }

        inline const std::string& getTemplateName() {
            return templ_;
        }

        const std::string& getPathKey() override;

        const std::string& getChannel() {
            return channel_;
        };

        void addSubAction(QGaDataAction *subDataAction);

        QGaChannelActionList* getSubActions();

        bool hasSubActions();

        virtual void setAutoCache(bool autoCache);

        void updateCommonParam(qlibc::QData &commonParam);

        void clearSubActions();

        void parseParam(Json::Value& ret, const std::string& src, const qlibc::QData* req) override;;

        bool checkCondition(QData *req, QData *resp) override;

        bool runThisAction(QData *req, QData *resp) override;

        bool runActionStopIfFail(QData *req, QData *resp) override;

        QGaDataActionControllerR findCacheControl(qlibc::QData *req, qlibc::QData *resp);

        void clearController();

        //不同的应用下，在Action调用之前执行
        virtual void beforeActionExcecute() { }

        bool handleActionVar(const std::string &src, std::string &dest, const qlibc::QData * context) override;

    protected:
        void prepareChannelCall(qlibc::QData& realReq, qlibc::QData* req);
    };

    class JE_API QGaCachedVar : public QGAActionObject {
    protected:
        QGAChannelHolder& pool_;
        std::string channel_;
        std::string indexKey_;
        std::string bind_key_;
        const gaoFinder* finder_;   //不可能为空,但不能删除该指针。

    public:
        explicit QGaCachedVar(QGAChannelHolder& pl, const qlibc::QData& data, const std::string &idxKey, const gaoFinder* finder);

        void checkUpdated();

        void addBindedKey(const std::string &idxKey) {
            bind_key_ = idxKey;
        }

        const std::string& getBindKey() {
            return bind_key_;
        }

        inline const std::string& getPathKey() {
            return indexKey_;
        }
    };

    using QGaActionImpl = std::function<bool(QGAChannelHolder& pool, qlibc::QData *req, qlibc::QData *resp)>;

    class JE_API QGAUserDefAction : public QGaDataAction {
    protected:
        QGaActionImpl& handler_;

    public:
        explicit QGAUserDefAction(QGADataPoolBase& dp,const QGaActionImpl& func) :
            QGaDataAction(dp),  handler_(*new QGaActionImpl(func)) {
        }

        ~QGAUserDefAction() {
            delete &handler_;
        }

        bool performAction(qlibc::QData *req, qlibc::QData *resp) override {
            return handler_.operator()(data_pool_.getChannelPool(), req, resp);
        }

    };

    class JE_API QGAStringRefAction : public QGaDataAction {
    protected:
        std::string index_key_;

    public:
        explicit QGAStringRefAction(QGADataPoolBase& dp, std::string channel, std::string indexKey) :
            QGaDataAction(dp, std::move(channel)),index_key_(std::move(indexKey)) {
        }

        //引用, 主要是针对 request 进行, 需要从pool_等地方找到这个GAO,然后调用它
        bool performAction(qlibc::QData *req, qlibc::QData *resp) override;
    };

    /**
     *  request :   被本地调用,
     *      向外部投递或请求数据, 更多的是请求, 结果定向转发或cache
     */
    class JE_API QGARequestAction : public QGaDataAction {

    public:
        explicit QGARequestAction(QGADataPoolBase& dp, qlibc::QData& reqParam, QGaChannelActionList& subConns) :
                QGaDataAction(dp, reqParam) {
            QGaDataAction::setUpSubChannelActions(subConns);
        }
    };

    /**
     *  deliver :   被外部调用,
     *      外部向节点投递数据,  再通过request/return等进行数据转发,也可以被本地cache
     */
    class JE_API QGADeliverAction : public QGaDataAction {
    public:
        explicit QGADeliverAction(QGADataPoolBase& dp, qlibc::QData& reqParam, QGaChannelActionList& subConns) :
            QGaDataAction(dp, reqParam) {
            QGaDataAction::setUpSubChannelActions(subConns);
        }

        //ac选项无效
        void setAutoCache(bool autoCache) override {}
    };

    /**
     *
     *      数据处理通道
     *
     *
     */
    class JE_API LogChannel : public QGADataChannel {
    public:
        explicit LogChannel() : QGADataChannel() { fast_str_call_ = true; }
        bool handleChannelMessage(QGaDataAction* action, qlibc::QData &msg, qlibc::QData* resp) override;
    };

    using QGaRedirector = std::function<bool(const std::string &userKey, const std::string &indexKey,qlibc::QData &req,qlibc::QData *resp)>;
    class JE_API ReDicrectChannel : public QGADataChannel {
    protected:
        QJAMgServer &opr_;
        const QGaRedirector* redirector_;
    public:
        explicit ReDicrectChannel(const QGaRedirector* red, QJAMgServer &opr): opr_(opr), redirector_(red) {}
        bool handleChannelMessage(QGaDataAction* action, qlibc::QData &msg, qlibc::QData* resp) override;
    };

    class JE_API QSyncerChannel : public QGADataChannel {
    protected:
        SyncerPool &pool_;
    public:
        explicit QSyncerChannel(SyncerPool &opr): pool_(opr) {
            fast_str_call_ = true;
        }

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

    using QGaCachedVarUpdater = std::function<void(QGaCachedVar*)>;

    class JE_API QGaCacheChannel : public QGADataChannel {
    protected:
        qlibc::QPObjectHolder<QGaCachedVar> &cachePool_;
        QGaCachedVarUpdater*                 auto_savor_;
        QGAChannelHolder                      &pool_;
        const gaoFinder*                     gao_finder_;   //不可能为空,但不能删除该指针。

    public:
        explicit QGaCacheChannel(qlibc::QPObjectHolder<QGaCachedVar>& vars, QGaCachedVarUpdater* updater,
                                 QGAChannelHolder& pl, const gaoFinder* finder) :
                cachePool_(vars), auto_savor_(updater), pool_(pl), gao_finder_(finder) { }
        //保存到 DataPool的cached中
        bool handleChannelMessage(QGaDataAction* action, qlibc::QData &msg, qlibc::QData* resp) override;
    };

    class JE_API QGaReturnChannel : public QGADataChannel {
    protected:
        QJAMgService &service_;
    public:
        explicit QGaReturnChannel(jedge::QJAMgService& service) : service_(service) { }

        //需要把mgbus的调用源置入其中
        bool handleChannelMessage(QGaDataAction* action, qlibc::QData &msg, qlibc::QData* resp) override;
    };

    using GaAutoCacher = std::function<void(const std::string& cacherKey, qlibc::QData& result)>;

    class JE_API QGaMgbusChannel : public QGADataChannel {
    protected:
        QJAMgService &service_;
        GaAutoCacher *auto_cacher_;
    public:
        explicit QGaMgbusChannel(jedge::QJAMgService& service, GaAutoCacher* cacher) :
                service_(service), auto_cacher_(cacher) { }

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

    class JE_API QGaHttpChannel : public QGADataChannel {
    protected:
        jedge::QHttpClient &client_;
        GaAutoCacher       *auto_cacher_;

    public:
        explicit QGaHttpChannel(jedge::QHttpClient& client, GaAutoCacher* cacher) :
                client_(client), auto_cacher_(cacher){ }

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

    class JE_API QGaSSLChannel : public QGADataChannel {
    protected:
        jedge::QHttpSSLClient &client_;
        GaAutoCacher       *auto_cacher_;
    public:
        explicit QGaSSLChannel(jedge::QHttpSSLClient& client, GaAutoCacher* cacher) :
                client_(client), auto_cacher_(cacher) { }

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

    class JE_API QStringRefChannel : public QGADataChannel {
    protected:
        std::string channel_ref_;
    public:
        explicit QStringRefChannel(string chn) : channel_ref_(std::move(chn)) { }

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

    using GaMsgEncryptor = std::function<bool(const std::string& src, std::string &target)>;

    class JE_API QGaMqttChannel : public QGADataChannel {
    protected:
        jedge::QMqttClient &client_;
        GaMsgEncryptor*    encryptor_;
        std::string        default_topic_;
    public:
        explicit QGaMqttChannel(jedge::QMqttClient& client, GaMsgEncryptor* encryptor, std::string dftTopic="") :
            client_(client), encryptor_(encryptor), default_topic_(std::move(dftTopic)) { }

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

    class JE_API QGaMsgTemplate {
    public:
        explicit QGaMsgTemplate(std::string key):  command_key_(std::move(key)){}

        std::string command_key_;
    };

    //变量响应访问接口, 对 ${type.xxx.xxx} 类型的变量做出响应
    class JE_API QGaVarHandler {
    public:
        virtual bool handleExTypeVar(Json::Value &ret, const string &type, const string &varKey) = 0;
    };

    using QGaVarHandlerFunc = std::function<bool(Json::Value &ret, const string &type, const string &varKey)>;


    using QGaControllActionHandler = std::function<bool(qlibc::QData &req, qlibc::QData *resp)>;
    using QGacHandlerPool = qlibc::QPObjectHolder<QGaControllActionHandler>;
    //
    class JE_API QGaControllableChannel {
    protected:
        QGacHandlerPool handlers_;

    public:

    };

    class JE_API QGaFileChannel :
            public QGaControllableChannel,
            public QGADataChannel {
    protected:
        QGADataPoolBase& pool_;

    public:
        explicit QGaFileChannel(QGADataPoolBase &site);

        //需要把mgbus的调用源置入其中
        bool handleChannelMessage(QGaDataAction* action, qlibc::QData &msg, qlibc::QData* resp) override;


        bool cc_read(qlibc::QData &req, qlibc::QData *resp);
        bool cc_write(qlibc::QData &req, qlibc::QData *resp);
        bool cc_exists(qlibc::QData &req, qlibc::QData *resp);

        bool cc_clearDir(qlibc::QData &data, qlibc::QData *pData);
    };

#define defineCall(_name, _call) \
        defineChannelCall(_name, [this](qlibc::QData& _msg, qlibc::QData* _resp)->bool{ \
            return _call(_msg, _resp); \
        })
}
#endif //INC_1_LIBDEVCPP_QGAACTIONOBJECTS_H
