//
// Created by Ht on 2021/10/14.
//

#ifndef INC_0_LIBDEVCPP_CPAD_MGTRIGGERMANAGER_H
#define INC_0_LIBDEVCPP_CPAD_MGTRIGGERMANAGER_H

#include <jebase/config.h>
#include <qlibc/qlibc.h>
#include "MgBusCommon.h"
#include "ChannelOperator.h"

namespace jedge {
    class MgEvent;
    class MgTriggerWatcher;

    using MgAction = std::function<bool(jedge::MgTriggerWatcher& w, const std::string &keyVal, const qlibc::QData& msg)>;
    using MgRAction = std::shared_ptr<MgAction>;
    using MgActionList = std::vector<MgRAction>;

    //通用的watcher： 调度即触发。
    class JE_API MgTriggerWatcher {
    protected:
        MgActionList* actions_ = nullptr;                   //Watcher的动作
        MgAction*     action_ = nullptr;                    //Watcher的动作
        const std::string   event_;                         //event to watch
        const std::string   watcher_key_;                   //监听哪个关键字
        qlibc::QData  watcher_param_;                       //监听器的执行参数
        const int watcher_id_;                              //id
        std::string   src_uri_key_;                         //监听哪个关键字
        unsigned short  ttl_ = ival_watcher_timeout_ttl_;   //watcher必须在ttl时间内重新刷新对watcher的注册，刷新时间默认为180 S /3 min

    public:
        explicit MgTriggerWatcher(std::string   event, std::string  key, const qlibc::QData& param);

        virtual ~MgTriggerWatcher();

        virtual void doActions(jedge::MgEvent& e, const std::string& keyVal, qlibc::QData& param);

        void appendAction(const MgRAction& action);

        inline void appendSingleAction(const MgAction& a) {
            action_ = new MgAction (a);
        }

        inline const std::string &getKey() {
            return watcher_key_;
        }

        inline const std::string &getEvent() {
            return event_;
        }

        inline bool refreshOutWatcher() {
            return !isRemote() || ttl_-->0;  //本地watcher 永不超时
        }

        void setWatcherOkResult(qlibc::QData *resp);

        inline const std::string getId() {
            return StringUtils::intToString(watcher_id_);
        }

        inline void resetTtl() {
            ttl_ = ival_watcher_timeout_ttl_;
        }

        inline void resetSourceModule(qlibc::QData &param) {
            auto srcMod = GetMgModSource(param);
            auto evtSrc = GetWatchSrc(watcher_param_);
            if(evtSrc!=srcMod) {
                SetWatchSrc(watcher_param_, srcMod);
            }
        }

        inline const qlibc::QData& getWatcherParam(){
            return watcher_param_;
        }

        inline bool isRemote() {
            return watcher_param_.containsKey(JEDGE_MGBUS_EVENT_CALLBACK);
        }

        inline std::string getSourceModule() {
            return watcher_param_.getString(JEDGE_MGBUS_EVENT_SRC);
        }

        inline std::string getCallbackUri() {
            return watcher_param_.getString(JEDGE_MGBUS_EVENT_CALLBACK);
        }

        void setSrcUriKey(const std::string &uriKey);

        const std::string &getSrcUriKey();
    };

    using MgRTriggerWatcher = std::shared_ptr<MgTriggerWatcher>;
    using MgTriggerWatcherList = std::vector<MgRTriggerWatcher>;
    class JE_API MgEvent :
            public qlibc::QSelfRefObject {
    protected:
        jedge::ChannelOperator&          operator_;             //传递线程池访问
        const std::string                event_name_;           //区分键值的key，用于同一事件、触发不同的watcher
        qlibc::QPObjectHolder<MgTriggerWatcherList> watchers_;  //事件监听者。当事件被触发时，调用watcher的执行机构。
        std::recursive_mutex             mutex_;
    public:
        explicit MgEvent(jedge::ChannelOperator& opr, std::string evtname) :
            operator_(opr),
            event_name_(std::move(evtname)) {}

        virtual ~MgEvent () = default;

        const std::string& getEventName() {
            return event_name_;
        }

        void onEvent(const std::string& keyVal, qlibc::QData& param);

        void addEventWatcher(const std::string& key, MgRTriggerWatcher& watcher);

        void removeAllWatchers(const std::string &key) {
            RECURSIVE_LOCK(mutex_);
            auto *wl = watchers_.findObject(key);
            if (wl != nullptr) {
                watchers_.eraseObject(key);
            }
        }

        const string &objId() override;

        void removeWatcher(MgRTriggerWatcher &w){
            RECURSIVE_LOCK(mutex_);
            const auto& kk = w->getKey();
            auto *wl = watchers_.findObject(kk);
            if (wl != nullptr) {
                VECTOR_REMOVE(*wl, w);
                QHLog("Watch removed to (%s : %s) ok with id : %s", w->getEvent().c_str(), w->getKey().c_str(), w->getId().c_str());
                if(wl->empty()){
                    watchers_.eraseObject(kk);
                }
            }
        }
    };

    using MgREvent = std::shared_ptr<MgEvent>;
    using PMgEventList = std::vector<MgREvent>;

    class JE_API MgTriggerCondition {
    public:
        virtual bool isMatched(qlibc::QData& param) = 0;
    };

    using MgRTriggerCondition = std::shared_ptr<MgTriggerCondition>;
    using PMgTriggerConditionList = std::vector<MgRTriggerCondition>;

    class JE_API MgTrigger {
    protected:
        PMgTriggerConditionList         conds_;   //满足条件才触发。条件可能是多个条件的，都需要满足才行
        PMgEventList                    events_;             //与trigger捆绑的事件

    public:
        explicit MgTrigger(const qlibc::QData& def)  : events_(false) {
            //TODO::解析条件，当条件满足时触发 action
        }

        void appendEvent(const MgREvent& event) {
            if(event!=nullptr)
                events_.emplace_back(event);  //创建了持有指针
        }

        bool trig(const std::string& keyVal, qlibc::QData &param) {
            //当条件被match后，对每个event，触发其所欲watcher的对应action
            for(auto& cond : conds_ ) {
                if(cond==nullptr || !cond->isMatched(param))
                    return false;
            }
            for(auto& e : events_)
                if(e!=nullptr) e->onEvent(keyVal, param);
            return true;
        }
    };

    class JE_API MgTriggerManager {
    protected:
        ChannelOperator& _tr_opr_;
        qlibc::QSharedObjectHolder<MgAction>    actions_;  //触发器可以执行的动作库。
        qlibc::QSharedObjectHolder<MgTrigger>   triggers_; //触发器定义库，
        qlibc::QSharedObjectHolder<MgEvent>     events_;   //事件池，  注意，可能定期清理watcher
        qlibc::QSharedObjectHolder<MgTriggerWatcher>   remoteWatchers_;     //外部注册到本地的事件
        qlibc::QSharedObjectHolder<MgTriggerWatcher>   remoteWatchers_by_uris_; //外部注册到本地的事件
        qlibc::QRTimer                          remote_watcher_timer_;

        std::recursive_mutex                    mgr_mutex_;
    public:
        explicit MgTriggerManager(jedge::ChannelOperator& opr) : _tr_opr_(opr) {}

        virtual ~MgTriggerManager() {
            if(remote_watcher_timer_ != nullptr)
                onStop();
        }

    protected:
        void onStart();
        void onStop();
        /**
         * 定义trigger的文件，格式如下
         *  {
         *      "defTrigger" : {
         *          ...
         *      },
         *      ...
         *  }
         * @param triggerDefFn
         */

        void loadTriggersFromFile(const std::string &triggerDefFn);

        /**
         * 定义event的文件，格式如下
         *  {
         *      "defEvent" : {
         *          ...
         *      },
         *      ...
         *  }
         * @param triggerDefFn
         */

        void loadEventsFromFile(const std::string &triggerDefFn);

        /**
         * 定义action的文件，格式如下
         *  {
         *      "actions" : [
         *          {
         *              "name": "<actionName>"
         *              "action":[
         *                  ...
         *              ]
         *          }
         *          ...
         *      ]
         *  }
         * @param actionDefFn
         */
        void loadActionsFromFile(const std::string &actionDefFn);

//添加事件定义
        virtual void prepareEvents();

        virtual void prepareActions();

        auto addRemoteWatcher(jedge::MgEvent& e, const std::string &key, qlibc::QData &param, qlibc::QData *rsp) -> MgRTriggerWatcher;

        auto isRemoteWatcher(const std::string &wid) -> bool;

        auto handleRemoteEventWatcherAdding(const std::string &event, qlibc::QData &param, qlibc::QData *rsp) -> bool;

        virtual auto removeEventWatcher(const std::string& wid) -> bool;

        void startWatcherTtlCheck();

        void stopWatcherTtlCheck();

        void checkOutWatcherTtl();

        //响应远程事件的触发
        auto _reh_(jedge::MgTriggerWatcher &w, const std::string& keyVal, const qlibc::QData &msg) -> bool;

        virtual auto watched(jedge::MgTriggerWatcher &w, const std::string& keyVal, const qlibc::QData &msg) -> bool;

        virtual auto unwatch(jedge::MgTriggerWatcher &w, const std::string& keyVal, const qlibc::QData &msg) -> bool;

    public:
        //声明一个trigger
        auto declareTrigger(const std::string& trKey, const qlibc::QData& d) -> bool;

        //声明一个事件
        auto defineEvent(const std::string& event, const qlibc::QData& d) -> bool;

        //声明一个事件，并指定trigger
        auto defineEvent(const std::string& event, const std::string& triggerList, const qlibc::QData& d) -> bool;

        //声明一个action带lamda回调函数
        auto defineAction(const std::string& acKey, const MgAction& action) -> bool;

        //声明一个配置脚本的action
        auto defineAction(const std::string& acKey, const qlibc::QData& d) -> bool;

        //w为一个watcher添加响应函数
        void appendDefinedAction(MgTriggerWatcher& w, const std::string& act);

        //获取本地回调
        auto addLocalWatch(const std::string &event, const std::string &key, const MgAction& action) -> std::string;

        // /@t/watchEvent --event ... --key ... --callback ... --condition ...
        // autoClearJedgeCallInfo = false
        virtual auto watch(qlibc::QData &msg, qlibc::QData *rsp) -> bool;

        // /@t/removeWatch --event ... --key ...
        //清理某个指定的Watcher ID的watcher。
        virtual auto remove(qlibc::QData &msg, qlibc::QData *rsp) -> bool;

        //主要是本地来触发，而并非通过远程调用来触发。
        virtual void appendEventAppendixInfo(qlibc::QData &event_data) = 0;

        //调用一个触发器
        auto trigEvent(const std::string& trKey, const std::string& keyVal, qlibc::QData& param) -> bool;

        //调用一个触发器不带参数
        auto trigEvent(const std::string& trKey, const std::string& keyVal = JEDGE_MGBUS_EVENT_KEY_DEFAULT) -> bool;

        //主要是本地来触发，而并非通过远程调用来触发。
        auto trigEvent(const std::string& trKey, qlibc::QData& param) -> bool;

        const MgREvent findEvent(const std::string &evKey);

        void removeLocalWatcher(const std::string &id);
        void removeOperatorEvent(const std::string &id);
        void removeOperatorTrigger(const std::string &id);
        void removeOperatorAction(const std::string &id);
    };

    class JE_API MgTriggerManagerOperator {
    protected:
        ChannelOperator& _svc_tropr_opr_;
        QStringList      _trList;
        QStringList      _wcList;
        QStringList      _evList;
        QStringList      _acList;
        //a、记录本服务的event/triggers列表；
        //b、

    public:
        explicit MgTriggerManagerOperator(jedge::ChannelOperator& opr) : _svc_tropr_opr_(opr) {}

    protected:
        //定义事件
        bool DefEvent(const std::string& event);
        //定义事件、捆绑到触发器
        bool DefEvent(const std::string& event, const std::string& trigger_list);

        bool DefAction(const std::string& acKey, const MgAction& handler);
        //定义触发器
        bool DefTrigger(const std::string& trigger);
        //监听本地事件
        bool watchLocalEvent(const std::string& event, const std::string &key,const MgAction& handler);

        void releaseEventResources();

        //处理监听器被watch时的事件
        bool handleEventWatching(const std::string& event, const MgAction& handler);

        //处理监听器被unwatch时的事件
        bool handleEventUnwatching(const std::string& event, const MgAction& handler);

        //根据event的key获取Event对象
        MgREvent findEvent(const std::string& evKey);

        //
        virtual auto getTrigerService() -> MgTriggerManager * = 0;

    public:
        //调用一个触发器
        bool trigEvent(const std::string& trKey, const std::string& keyVal, qlibc::QData& param);

        //调用一个触发器不带参数
        bool trigEvent(const std::string& trKey, const std::string& keyVal = JEDGE_MGBUS_EVENT_KEY_DEFAULT);

        //主要是本地来触发，而并非通过远程调用来触发。
        bool trigEvent(const std::string& trKey, qlibc::QData& param);

    };

#define  SysDefineWatchAfterAction(__e, __method) \
            defineAction(std::string("after_")+(__e), [this] (jedge::MgTriggerWatcher &__w, const std::string& __k, const qlibc::QData &__msg)-> bool { \
                return __method(__w, __k, __msg);    \
            })

#define  SysDefineWatchBeforeAction(__e, __method) \
           defineAction(std::string("before_")+(__e), [this] (jedge::MgTriggerWatcher &__w, const std::string& __k, const qlibc::QData &__msg)-> bool { \
                return __method(__w, __k, __msg);    \
           })

#define  SysDefineServiceAction(__cb) \
           defineAction(#__cb, [this] (jedge::MgTriggerWatcher &__w, const std::string& __k,  const qlibc::QData &__msg)-> bool { \
                return __cb(__w, __k, __msg);         \
           })

#define SysAddLocalWatch(__act) \
           addLocalWatch(#__act, jedge::JEDGE_MGBUS_EVENT_KEY_DEFAULT, [this](jedge::MgTriggerWatcher &__w, const std::string& __k, const qlibc::QData &__m)->bool { \
                return this->__act(__w,__k,__m);  \
           })

#define SetEventType(m,n)   (m).putObjFmtString("~e.e", n)
#define SetEventTime(m)     (m).putObjFmtString("~e.t", DateUtils::getNowTimeStringMs())
#define SetEventKey(m,k)    (m).putObjFmtString("~e.k", k)
#define SetEventSrc(m,k)    (m).putObjFmtString("~e.m", k)

#define getEventType(m)    (m).getObjFmtString("~e.n")
#define getEventTime(m)    (m).getObjFmtString("~e.t")
#define GetEventKey(m)     (m).getObjFmtString("~e.k")
#define GetEventSrc(m)     (m).getObjFmtString("~e.m")

#define GetMgbusEventModuleName(_mm,_var) \
        auto _var = _mm.getString("mgnet"); \
        if(!_var.empty()) \
            _var.insert(0,"@").insert(0,GetEventKey(_mm)); \
        else \
            _var = GetEventKey(_mm)

}

#endif //INC_0_LIBDEVCPP_CPAD_MGTRIGGERMANAGER_H
