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

#ifndef LIBDEVCPP_MGBUSSERVER_H
#define LIBDEVCPP_MGBUSSERVER_H

#include <mutex>
#include <string>

#include <qlibc/QTimerEngine.h>
#include <qlibc/NetUtils.h>
#include <utility>
#include "mgbus/MgbusNode.h"
#include "mgbus/MgbusProtocol.h"
#include "mgbus/ChannelOperator.h"
#include "mgbus/MgServerIntf.h"
#include "mgbus/QCMDnsServer.h"
#include <qlibc/cmd/JCCmdRunner.h>
#include <jadom2/JAIndexedDom.h>
#include "mgbus/MgBusHolder.h"
#include <mgbus/MgVersionShower.h>

namespace jedge {

#define MAX_SERVER_THREAD_COUNTS ( 256 )      //服务器线程池最大数量

    class MgBusServer;

    using ServerServiceCreator = JE_API
            std::function <MgService*(jedge::MgBusServer& server,
                    const std::string& name, const qlibc::QData& service_cfg)>;

    class JE_API MgBusServer :
        public jedge::MgServerIntf,
        public jedge::ChannelOperator,
        public jedge::MgVersionShower,
        public ja::JAIndexNodeContext,
//        public qlibc::QSelfRefObject,
        public jedge::MgTriggerManagerOperator {
    private:
        bool                        quit_ = false;
        bool                        as_cloud_ = false;

        QJsonSocketServer           sock_sever_;

        MgbusProtocol               protocol_;
        MgBusServiceHolder          mg_services_;

        qlibc::QSharedObjectHolder<MgNode>
                                    client_nodes_;

        qlibc::QRTimer                 heart_timer_ = nullptr;

        QCMDnsServer                   cmdns_server_;
        QCMDnsClient                   cmdns_client_;
        CMDnsServicePublish*           cmdns_pub_udp_ = nullptr;
        CMDnsServicePublish*           cmdns_pub_tcp_ = nullptr;

        std::string                    mode_name_;
        std::recursive_mutex           server_mutex_;
        qlibc::QSelfRefControl         self_ctrl_;

    public:
        explicit MgBusServer(const qlibc::QData& initConfig);

        ~MgBusServer() override ;

        const std::string &getVersionHolderName() override;

        bool handleSocketMessage(SocketClientNode* node, qlibc::QData &datamsg);

        bool handleUdpSocketMessage(const string &host, int port, qlibc::QData &message);

        QCMDnsClient &getCmdnsClient() override;

        void onTcpConnectionClosed(SocketClientNode &node);

        void shutdown() override;

        bool isActive() override;

        bool start(const qlibc::QData &config) override;

        bool deliverDataMessage(qlibc::QData &datamsg);

        void appendMessageSrc(const std::string& sourceKey , qlibc::QData &datamsg);

        void heart_beat();

        bool isReservedKey(const std::string &key);

        bool onHeartBeatMsg(const std::string& sockKey, const std::string &cmd, qlibc::QData &msg, SocketMode mode);

        void markLocalAddress(const std::string& local, int port);

        //登录返回消息, 如果code不为200,则在发送后将自动关闭socket
        void returnLoginMessage(const std::string& sockKey, SocketMode mode, qlibc::QData &msg,
                                int code, const std::string &log);

    protected:
        MgTriggerManager * getTrigerService() override;

        virtual void clearService();

        virtual void prepareService(const qlibc::QData& config);

        bool onClientAuth(const std::string& sockKey, const std::string &cmd, qlibc::QData &msg, SocketMode mode);

        bool onClientQuit(const std::string& sockKey, const std::string &cmd, qlibc::QData &msg, SocketMode mode);

        virtual bool
            onMgbusServiceCommand(const std::string& sockKey, const std::string &cmd, qlibc::QData &msg, SocketMode mode);

    public:
        bool postSyncMessage(const std::string &src, const std::string &target, qlibc::QData &message,
                             qlibc::QData &response) override;

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

        const string &name() override;

        virtual void markCommandInput() {}

        virtual void markLineKeyInputed() {}

        inline int getNodeSize() {
            return client_nodes_.size();
        }

        void getServiceKeyList(QStringList &kl);

        void iterateNode(const qlibc::QSharedObjectHolder<MgNode>::SharedObjAccessorConst & accessor);

        //发送service-service消息, 跨mgmodule的消息格式：
        bool postServiceRequest(const std::string& mod, const std::string& uri, qlibc::QData& req, qlibc::QData& rsp, int to_ms = -1);

        bool postServiceMessage(const std::string& mod, const std::string& uri, qlibc::QData& msg);

        inline bool broadcastMgbusMessage(const std::string &uri, qlibc::QData &msg) {
            return postServiceMessage("#", uri, msg);
        }

        inline bool broadcastMgbusNetWorkMessage(const std::string &mod, const std::string &uri, qlibc::QData &msg) {
            return postServiceMessage(mod+"@#", uri, msg);
        }

        void postSocketMessage(const std::string &sockKey, SocketMode mode, qlibc::QData &msg, bool closeSock = false);

        void postClientMessage(const std::string &modKey, qlibc::QData &resp);

        bool closeMgbusClient(const std::string &modKey);

        bool closeMgbusClientBySocketKey(const std::string &sockKey);


        void registerUserDefineCommand ( const std::string& cmd, const qlibc::QCmdRunnerHandler& handler, const std::string& helpInfo);

        //从服务器向所有的module进行广播
        void serverBroadCastMessage(qlibc::QData &datamsg);

        //从服务器向所有的module进行广播
        void serverGroupCastMessage(const std::string &dest, qlibc::QData &datamsg);

        bool appendService(const std::string &key, const qlibc::QData &config, const jedge::ServerServiceCreator &creator);

        template<typename T = MgService>
        inline auto findService(const std::string &key) -> T* {
            return dynamic_cast<T*>(mg_services_.findService(key).get());
        }

        inline auto findServiceRef(const std::string &key) -> const std::shared_ptr<MgService> {
            return mg_services_.findService(key);
        }

        template<typename T>
        inline std::shared_ptr<T> findServerService(const std::string& svcKey) {
            auto org = findServiceRef(svcKey);   //拷贝一个引用
            auto ref = std::dynamic_pointer_cast<T>(org);
            return ref;
        }

        virtual void prepareMgbusServer(qlibc::QData &config);

        virtual void defineProtocolCommand();

        virtual void afterServiceInit();

        void handleErrorDeliverMessage(qlibc::QData &datamsg, const std::string &errMsg);

        bool deliverDataMessageToCommandService(qlibc::QData& msg);

        //派生时、尽可能引用基类方法
        virtual std::shared_ptr<MgService> findCommandService(const std::string &cmd, qlibc::QData &resp);

        void stopServices();

        const std::string &getMgbusHostName();

        //获取可接入云端地址列表
        void getCloudHosts(QStringList &hostList);

        bool isCloudMode();

        //mgs本地命令
        bool listMgbusClients(qlibc::JCArgNode &param, qlibc::QData *re);
        bool listOnlineMgbusNodeSn(qlibc::JCArgNode &param, qlibc::QData *re);
        bool kickMgbusModule(qlibc::JCArgNode &param, qlibc::QData *re);
        bool listMgbusNodeOnline(qlibc::JCArgNode &param, qlibc::QData *re);
        bool showMgsModuleName(qlibc::JCArgNode &param, qlibc::QData *re);
        bool showPoolInfo(qlibc::JCArgNode &param, qlibc::QData *re);
        bool findModules(qlibc::JCArgNode &param, qlibc::QData *re);
        bool scanForOtherNode(qlibc::JCArgNode &param, qlibc::QData *re);

        static std::string defaultFilePath(const qlibc::QData &cfg, const std::string &name);

    protected:
        MgNodeRef handleNewNodeLogin(std::string &nodeKey, const std::string& sockKey,
                                     qlibc::QData &msg, SocketMode mode);

        void clearNodeClientInfo(const string &modKey);
    };

    //定义一个Service
#define  DefineMgbusServerService(name_str, service_class, config) \
    static const char* service_class##_##name = (name_str); \
    appendService(service_class##_##name, config.getData(service_class##_##name), [](jedge::MgBusServer& opr, const std::string& name, const qlibc::QData& service_cfg)->jedge::MgService* {   \
        return new service_class(opr, name, service_cfg);   \
    })

    //定义一个以类成员变量作为Service最后初始化参数的Service
#define  DefineMgbusServerServiceWithInitFieldObj(name_str, service_class, config, obj) \
    static const char* service_class##_##name = (name_str); \
    appendService(service_class##_##name, config.getData(service_class##_##name), [this](jedge::MgBusServer& opr, const std::string& name, const qlibc::QData& service_cfg)->jedge::MgService* {   \
        return new service_class(opr, name, service_cfg, obj);   \
    })

#define MgServer(opr)\
    (*(dynamic_cast<jedge::MgBusServer*>(&(opr))))

#define IsMgServer(opr) \
    (dynamic_cast<jedge::MgBusServer*>(&(opr)) !=nullptr)

#define GetServerServiceRef(_v,_k,_t) \
    auto _v = findServerService<_t>(_k)

#define GetServerServiceRefFrom(_v,_k,_t,_o) \
    auto _v = (_o).findServerService<_t>(_k)

#define GetDebugService(_v) \
    GetServerServiceRef(_v,mg_protocol_key_debug_,MgbusDebugService)
#define GetMgnetService(_v) \
    GetServerServiceRef(_v,mg_protocol_key_mgnet_,MgServerManagerService)
#define GetGroupService(_v) \
    GetServerServiceRef(_v,mg_protocol_key_group_,MgNodeGroupService)
#define GetTriggerService(_v) \
    GetServerServiceRef(_v,JEDGE_MGBUS_EVENT_SERVICE_NAME,MgbusServerTriggerService)
#define GetNodeService(_v) \
    GetServerServiceRef(_v,mg_protocol_key_node_,MgbusNodeService)

#define GetMgnetServiceFrom(_v,_o) \
    GetServerServiceRefFrom(_v,mg_protocol_key_mgnet_,MgServerManagerService,_o)

#define GetNodeServiceFrom(_v,_o) \
    GetServerServiceRefFrom(_v,mg_protocol_key_node_,MgbusNodeService,_o)

#define GetDebugServiceFrom(_v,_o) \
    GetServerServiceRefFrom(_v,mg_protocol_key_debug_,MgbusDebugService,_o)

#define GroupService \
    GetServerServiceRef(_gs,mg_protocol_key_group_,MgNodeGroupService); \
    if(_gs!=nullptr) _gs

#define DebugService \
    GetServerServiceRef(_ds,mg_protocol_key_debug_,MgbusDebugService); \
    if(_ds!=nullptr) _ds

#define MgnetService \
    GetServerServiceRef(_ms,mg_protocol_key_mgnet_,MgServerManagerService);\
    if(_ms!=nullptr) _ms

#define NodeService \
    GetServerServiceRef(_ns,mg_protocol_key_node_,MgbusNodeService); \
    if(_ns!=nullptr) _ns

#define EventService \
    GetServerServiceRef(_es,JEDGE_MGBUS_EVENT_SERVICE_NAME,MgbusServerTriggerService); \
    if(_es!=nullptr) _es


#define BindServerCommand(_cmd, _help, _Handler) \
    registerUserDefineCommand(_cmd, [this](unsigned int *retCode, void **d, void* ctx)->bool { \
        GET_CMD_PARAM(args, d);                    \
        return _Handler(*args);              \
    }, _help)

}

#endif //LIBDEVCPP_MGBUSSERVER_H
