//
// Created by Ht on 2021/2/1.
//

#ifndef LIBDEVCPP_QNODECLIENT_H
#define LIBDEVCPP_QNODECLIENT_H

#include <mgbus/QJsonSocketClient.h>
#include <mgbus/MgBusService.h>
#include <mgbus/MgServerIntf.h>
#include <mgbus/MgBusHolder.h>
#include <mgbus/QCMDnsClient.h>

#include <exlib/http/QHttpClient.h>
#include "JESockCommProtocol.h"

namespace jedge {

    static const char* DATA_CHANNEL_SOCKET_CLIENT = "sockc";           //socket client的名字
    static const char* DATA_CHANNEL_HTTP_CLIENT = "httpc";     //描述http返回的目标服务的信息

    static const char*  vkey_sock_client_config_host_    = "sc_host";
    static const char*  vkey_sock_client_config_port_    = "sc_port";
    static const char*  vkey_sock_client_config_sock_mode_    = "sc_udp";

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

    class JE_API QNodeClient :
            public jedge::MgServerIntf,
            public jedge::ChannelOperator {
    protected:
        qlibc::QData init_config_;
        qlibc::QData run_param_;
        qlibc::QData runData_;
        std::string  name_;
        std::string  service_name_;
        std::string  cache_fn_;

        std::string host;
        int port = -1;

        qlibc::QObjectMemoryPool<MgbusRequest, CLIENT_MESSAGE_POOL_SIZE> mg_req_pool_;

        jedge::QHttpClient       client_http_;
        jedge::QJsonSocketClient client_sock_;
        QCMDnsClient             cmdns_client_;

        std::mutex              mgconn_wait_mutex_;
        std::condition_variable mgconn_wait_;

        jedge::JECommSockProtocol   protocol_;

        qlibc::QRTimer   heart_timer_ = nullptr;

        QByte  tick = 0;

        bool   quit_ = false;
        bool   udp_login_ok_ = false;       //在收到login ok 之前，都需要不断地注册
        bool   starting_ = false;

        std::recursive_mutex  holder_op_mutex_;
    public:

        explicit QNodeClient(const qlibc::QData& config, const std::string& name = "",
                             const httplib::RThreadPool& pool = nullptr, const qlibc::QRTimerEngine& engine = nullptr);

        bool isActive() override;

        explicit QNodeClient(const std::string& config, const std::string& name = "",
                             const httplib::RThreadPool& pool = nullptr, const qlibc::QRTimerEngine& engine = nullptr);

        QCMDnsClient &getCmdnsClient() override;

        ~QNodeClient() override = default;

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

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

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

        void shutdown() override;

        const string &name() override {
            return name_;
        };

        bool postSyncHttpRequestByHost(const std::string& name, qlibc::QData& request, qlibc::QData& response);

        bool postASyncHttpRequestByHost(const std::string& name, qlibc::QData& request, const JsonSocketHandler& handler);

        bool postSyncHttpRequestByUri(const std::string& uri, qlibc::QData& request, qlibc::QData& response);

        bool postASyncHttpRequestByUri(const std::string& uri, qlibc::QData& request, const JsonSocketHandler& handler);

        void appendMessageHandler(const string &pattern, const JsonSocketHandler& handler);

        inline void Uri(const std::string&uri, const JsonSocketHandler& handler) {
            client_sock_.Uri(uri, handler);
        };

        inline void Regex(const std::string& pattern, const JsonSocketHandler& handler) {
            client_sock_.Regex(pattern, handler);
        };

        MgDataChannel &getClientChannel();

    protected:
        bool startNodeClient(const qlibc::QData &config, SocketMode mode = typeTCP);

        bool OnASyncHttpResponse(httplib::Client *fromClient, const string &uri, qlibc::QData &message);

        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);

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

        void heart_beat();

        void putRequestInQueue(qlibc::QData &request, const JsonSocketHandler *handler);

        void preppareHandler(const std::string &name);

        virtual bool targetDecided();

        virtual void findTargetHost(const std::string& name, const std::string& subnet, SocketMode mode);

        virtual int findProperIndex(const CMdnsServiceQueried services[], int cnt);
    };

}
#endif //LIBDEVCPP_QNODECLIENT_H
