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

#ifndef INC_0_LIBDEVCPP_CPAD_MGEVENTWATCHER_H
#define INC_0_LIBDEVCPP_CPAD_MGEVENTWATCHER_H

namespace jedge {
    using MgEventWatcherCallback    = std::function<bool(qlibc::QData& msg)>;
    using MgREventWatcherCallback    = std::shared_ptr<MgEventWatcherCallback>;
    using MgEventWatcherCallbackList = std::vector<MgREventWatcherCallback>;
    class MgService;

    class JE_API MgEventWatcher :
            public qlibc::QSelfRefObject {
    protected:
        int watcher_id_ = 0;
        ChannelOperator& operator_;
        MgService& service_;
        short  ttl_ = ival_watcher_refresh_ttl_;        //watcher必须在ttl时间内重新刷新对watcher的注册，刷新时间默认为120 S /2 min
        std::string module_;
        qlibc::QData msg_;
        std::string watcher_key_;
        MgEventWatcherCallbackList callbacks_;
        bool posting_watch_:1;
        bool posting_remove:1;
        std::recursive_mutex watch_mutex_;
        std::mutex posting_, check_;

    public:
        explicit MgEventWatcher(ChannelOperator& opr, MgService& service, std::string  wk) :
            operator_(opr),service_(service), watcher_key_(std::move(wk)), posting_watch_(false), posting_remove(false) {
        }

        virtual ~MgEventWatcher() {
            RECURSIVE_LOCK(watch_mutex_);
            {   //防止再进入posting message流程
                SINGLE_LOCK(check_);
                posting_remove = true;
                posting_watch_ = true;
            }
            posting_.lock();
            callbacks_.clear();
        }

        //建立对场景的检测
        const std::string& watchEvent(const std::string& mod, const std::string& event, const std::string& key,
                        const std::string& callback);

        void appendCallbackHandler(const MgEventWatcherCallback& cb) {
            RECURSIVE_LOCK(watch_mutex_);
            if(callbacks_.size()>1) {
                QWarn("May duplicated callback set on %s!", watcher_key_.c_str());
            }
            callbacks_.emplace_back(std::make_shared<MgEventWatcherCallback>(cb));
        }

        const string &objId() override;

        void onEventWatchCallback(qlibc::QData &cbMsg) {
            RECURSIVE_LOCK(watch_mutex_);
            for(auto& cb: callbacks_) {
                if(cb!=nullptr) {
                    //增加一次拷贝数量，避免双向死锁。
                    auto* msg = operator_.getBlankMessage();
                    msg->setInitData(cbMsg);
                    operator_.threadPool().enqueue([this, cb, msg]{ //拷贝了cb
                        try { cb->operator()(*msg);
                        } catch (std::bad_function_call& e) {}
                        operator_.releaseMessage(msg);
                    });
                }
            }
        }

        bool refreshWatch();

        void postRemoveMessage();

        void postWatchMessage();

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

        inline int getWatcherId(){
            return watcher_id_;
        }

        static string makeWatcherKey(const string &module, const string &event,
                                     const std::string &backMethod="_ecb",
                                     const string &key = JEDGE_MGBUS_EVENT_KEY_DEFAULT);

        bool isValid();
    };

    class JE_API MgWatcherPool {
    protected:
        ChannelOperator& operator_;
        MgService& service_;
        //按照 目标mod、event和watch的key进行区分，可以存在多个callback函数或uri
        //按照 watchid建立索引?
        qlibc::QSharedObjectHolder<MgEventWatcher>   mOutGoingWatchers;
        qlibc::QSharedObjectHolder<MgEventWatcher>   mOutGoingWatchersById;
        std::recursive_mutex  mutex_;
    public:
        explicit MgWatcherPool(ChannelOperator&opr, MgService &service) :
            operator_(opr), service_(service) { }
        ~MgWatcherPool() {}

        //针对回调型事件注册，单一键值
        MgEventWatcher& createNewWatcher(const std::string &module, const std::string &event,
                                         const std::string &key, const MgEventWatcherCallback& cb);

        MgEventWatcher& createNewWatcher(const std::string &module, const std::string &event,
                                         const std::string &key, const std::string &backMethod);

        void onEventCallback(qlibc::QData &cbMsg);

        void checkInWatcherTtl();

        inline bool existsWatcher(const std::string& wkey) {
            return mOutGoingWatchers.existObject(wkey);
        }

        void refreshWatcher(const std::string& wkey);

        void clearWatcherByKey(const std::string& wkey);

        void addWatcherIndexPool(int id, MgEventWatcher &watcher);

        void emptyWatcher();

        bool isEventWatched(const string &mod, const string &event, const string &cbUri, const string &key);

        void refreshAllWatchers();
    };

}

#endif //INC_0_LIBDEVCPP_CPAD_MGEVENTWATCHER_H
