//
// Created by Ht on 2020/5/8.
//

#ifndef TESTBIN_MUFISOPERATOR_H
#define TESTBIN_MUFISOPERATOR_H


#include <mutex>
#include <condition_variable>
#include <utility>
#include <qlibc/QDataMemoryPool.h>
#include <qlibc/qlibc.h>
#include <qlibc/QTimerEngine.h>
#include <qlibc/cmd/JCCmdRunner.h>
#include <qlibc/efflog.h>
#include <qlibc/QTriggerUtil.h>
#include "MgBusCommon.h"
#include "MgReqeustQueue.h"
#include "MgbusPathSetter.h"
#include "QCMDnsClient.h"

namespace jedge {

    #define MESSAGE_POOL_SIZE (128)                             //预设消息内存池大小

    #define MIN_THREAD_POOL_SIZE (3)                            //预设线程池大小
    #define DEFAULT_THREAD_POOL_SIZE \
        (CPPHTTPLIB_THREAD_POOL_COUNT>MIN_THREAD_POOL_SIZE?CPPHTTPLIB_THREAD_POOL_COUNT:MIN_THREAD_POOL_SIZE)

    static const char* vkey_efflog_mgnet_ = "logger_mgnet";
    static const char* vkey_qlog_module_file_ = "file_log";

    class JE_API ChannelOperator :
            public jedge::MgbusPathSetter {
    protected:
        qlibc::QData            runData_;
        qlibc::QData            initData_;
        const unsigned short    thread_cnt = DEFAULT_THREAD_POOL_SIZE;
        const bool outter_timer_engine_:1;
        bool   quit_:1;
        qlibc::QObjectMemoryPool<qlibc::QData, MESSAGE_POOL_SIZE>*
                                mg_message_pool_;
        httplib::RThreadPool    mg_thread_pool_;
        qlibc::QRTimerEngine    timer_engine_;
        qlibc::QRTriggerEngine  trigger_engine_;
        const bool global_trigger_engine_:1;
        int         days_of_log_reserved_;    //默认保留3天的日志

        MgReqeustQueue          mg_req_que_;
        std::string             cache_fn_;
        std::string             log_file_;

        qlibc::JCCmdRunner*     cmdRunner = nullptr;
        std::recursive_mutex    mqm_;       //消息队列锁
        std::recursive_mutex    opm_;       //opr操作锁

        CMLogIntf *eff_logger_ = nullptr;

    public:
        explicit ChannelOperator(const qlibc::QData& initConfig, const std::string &modulename,
                                 const httplib::RThreadPool& pool = nullptr, const qlibc::QRTimerEngine& engine = nullptr,
                                 qlibc::QRTriggerEngine tr_engine = nullptr);

        inline bool isOprQuitting() {
            return quit_;
        }

        void setupLogToFile();

        void setupLogToLocalNetwork();

        void clearLogToLocalNetwork();

        void clearLogToFile();

        /**
         *  第二天0点0分0秒 修改文件名
          */
        void resetLogFileName(const std::string &modName);

        /**
          *  检查天数，删除超过天数的log文件
          *     列举目标目录下的所有log文件名，检查其文件名时间与当前日期的差值，大于 days_of_log_reserved_ 的文件全部清理
          *
          *
          */
        void clearLogsExpired(long base, int dayExpire);

        virtual ~ChannelOperator() {
            releaseOperator();
            RECURSIVE_LOCK(opm_);
            if (thread_cnt > 0 && mg_thread_pool_ != nullptr) {
                QDWarn("Releasing operator ...");
                mg_thread_pool_->shutdown();
                mg_thread_pool_ = nullptr;
            }
        }

        virtual const std::string& name() = 0;

        virtual bool isActive() = 0;

        virtual QCMDnsClient& getCmdnsClient() = 0;

        void saveRunDataCache(const char* key_orders[]);

        void updateRunCacheProperty(const std::string& k, const Json::Value& v);

        void putRunCachePropertyString(const std::string& k, const std::string& v);

        void putRunCachePropertyData(const std::string& k, const qlibc::QData& v);

        int getRunCachePropertyInt(const std::string& k, int dft = -1);

        std::string getRunCachePropertyString(const std::string& k, const std::string& dft = "");

        Json::Value getRunCachePropertyValue(const std::string& k, const Json::Value& dft = Json::nullValue);

        bool getRunCachePropertyBool(const std::string& k, bool dft = false);

        qlibc::QData getRunCachePropertyData(const std::string& k);

        virtual bool postSyncMessage(const std::string& src, const std::string& target, qlibc::QData& message, qlibc::QData &response) = 0;

        virtual bool postAsyncMessage(const std::string &src, const std::string& target, qlibc::QData& message) = 0;

        inline virtual bool checkMessageLegal(qlibc::QData& message) { return true; }

        template <typename T = qlibc::QData>
        T* getBlankMessage(){
            RECURSIVE_LOCK(mqm_);
            if(quit_) return new T;
            if(mg_message_pool_!= nullptr) {
                auto *p = mg_message_pool_->getBlankObject();
                auto r = dynamic_cast<T *>(p);
                if (r != nullptr) {
                    p->clear();
                    return r;
                }
                mg_message_pool_->releaseObject(p);
            }
            return new T;
        };

        template <typename T = qlibc::QData>
        void releaseMessage(T* message){
            RECURSIVE_LOCK(mqm_);
            auto *p = dynamic_cast<T *>(message);
            if(p!=nullptr && mg_message_pool_!= nullptr)
                mg_message_pool_->releaseObject(message);
            else
                delete message;
        }

        httplib::ThreadPool& threadPool();

        httplib::RThreadPool threadPoolRef();

        qlibc::QTimerEngine& timerEngine() {
            RECURSIVE_LOCK(opm_);
            if(timer_engine_==nullptr) {
                timer_engine_ = std::make_shared<qlibc::QTimerEngine>(threadPoolRef());
            }
            return *timer_engine_;
        }

        qlibc::QRTimerEngine timerEngineRef();

        qlibc::QTriggerEngine& triggerEngine();

        qlibc::QRTriggerEngine triggerEngineRef();

        void enqueueMessage(const std::string &src, MgbusRequest &mf_req);

        void waitForResponse(MgbusRequest &mreq, int to_ms = -1);

        void pullbackRequest(int callid);

        bool handleBlockedRequest(const qlibc::QData &message);

        void setRunnerInstance(qlibc::JCCmdRunner *runner);

        qlibc::JCCmdRunner *getRunnerInstance();

        virtual void getProtocolMessage(const char *msgType, qlibc::QData &data) {}

        virtual void onJsonMessageReceived(qlibc::QData &msg) {}

    protected:
        void prepareOperator();

        void releaseOperator();
    };
}

#endif //TESTBIN_MUFISOPERATOR_H
