//
// Created by Ht on 2020/12/3.
//

#ifndef LIBDEVCPP_QMQTTCLIENT_H
#define LIBDEVCPP_QMQTTCLIENT_H

#include <string>
#include <queue>

#include <qlibc/httplib.h>
#include <qlibc/qlibc.h>
#include <mgbus/MgDataChannel.h>
#include <mgbus/SocketBuffer.h>
#include <mqtt/MQTTAsync.h>
#include <unordered_set>
#include <qlibc/QObjectEventHolder.h>

#include "QMqttMessageDeliver.h"

namespace jedge {


    static const char* _default = "@mq_dft";
    static const char* _pre_hook = "@mq_prehook";

    static const char* sval_event_lost_connection = "onConnectionLost";
    static const char* sval_event_get_connection =  "onConnect";
    static const char* sval_event_dis_connection =  "onDisconnect";
    static const char* sval_event_subscribed =      "onSubscribe";
    static const char* sval_event_subscribe_fail =  "onSubscribeFail";

    static int ival_mqtt_connect_timeout = 10000;

    using QMqttDataHooker = std::function<bool(const std::string& topic, void *payload, int payloadLen, char* buffer, int* len)>;
    using QMqttMessageHandler = std::function<bool(const std::string& topic, qlibc::QData& message)>;

    typedef struct {
        int mQos;
        int retained;
        std::string topicName;
        std::string message;
    } QWillDef;

    class JE_API QMqttClient :
        public jedge::MgDataChannel,
        public qlibc::QObjectEventHolder {

    private:
        MQTTAsync client = nullptr;
        int mQos = 2;
        int mbKeepAlive = 60;  //超时退出
        bool mConnected:1;
        bool mUsingSSL:1;
        bool subscribeOk:1;
        bool mQuit:1;

        std::string mServerUrl;
        std::string mClientId;

        std::string mMqttUserName;
        std::string mMqttPassword;

        std::string mSslCertFileName;

        QWillDef mWillDef;

        qlibc::QSharedObjectHolder<QMqttDataHooker>*
                mHookers = nullptr;

        qlibc::QSharedObjectHolder<QMqttMessageHandler>
                mHandlers;

        std::unordered_set<std::string>
                mSubscribedTopics;

        std::recursive_mutex mStatusMutex;

        std::mutex              m_;
        std::condition_variable cnntd_;

        jedge::QMqttMessageDeliver *mMsgDeliver;
        bool                    inner_deliver_;

        static int onMsgArrvd(void *context, char *topicName, int topicLen, MQTTAsync_message *message);
        static void onConnectionLost(void *context, char *cause);
        static void onConnectFailure(void *context, MQTTAsync_failureData *response);
        static void onConnect(void *context, char *cause);
        static void onSubscribeFailure(void *context, MQTTAsync_failureData *response);
        static void onSubscribe(void *context, MQTTAsync_successData *response);
        static void onSend(void *context, MQTTAsync_successData *response);
        static void onDisconnect(void *context, MQTTAsync_successData *response);

    public:
        explicit QMqttClient(ChannelOperator &opr, QMqttMessageDeliver &deliver, const std::string& name = "mqttClient");
        explicit QMqttClient(ChannelOperator &opr, const std::string& name = "mqttClient");

        ~QMqttClient();

        //初始化参数设置
        void resetWithInitData(const std::string &server, int port, const std::string &username, const std::string &password, const std::string &clientId);

        bool isConnected();
        bool connect();
        bool disConnect();

        void setDefaultHandler(const QMqttMessageHandler& handler);
        void setTopicHandler(const std::string& topic, const QMqttMessageHandler& handler);
        void removeTopicHandler(const std::string& topic);

        void addDataHooker(const QMqttDataHooker& handler, const std::string& key = "");
        void removeDataHooker(const std::string& key);

        bool publish(const std::string &topic, const char* strMsg, int iQos = 0);
        bool subscribe(const std::string& topic);

        void setEventConnectionLostHandler(const qlibc::QObjectEventHandler &handler);

        void setWillInfo(const std::string &serverTopic, const std::string &panelSn);

        void removeDefaultHandler();

        bool postRawMessage(qlibc::QData &message) override;

        bool unsubscribe(const std::string& topic);

        //用于动态设置uri响应器
        jedge::QMqttMessageDeliver& getMessageDeliver() {
            return *mMsgDeliver;
        }

        const std::string& getServer() {
            return mServerUrl;
        }

        const std::string& getClientId() {
            return mClientId;
        }

    protected:
        void onMessageArrived(const std::string &topic, int msgid, int qos, void *payload, int payloadLen);
        void onConnected();
        void onConnectionLost(const char *cause);
        void onDisconnected(MQTTAsync_successData *resp);
        void onMessageSentOK(MQTTAsync_successData *resp);
        void onSubscribeOk(MQTTAsync_successData *resp);
        void onSubscribeFail(MQTTAsync_failureData *failData);
    };

};



#endif //LIBDEVCPP_QMQTTCLIENT_H
