#ifndef MQTT_CLI_H
#define MQTT_CLI_H
#include "mqtt_properties.h"
#include "mqtt_client_cpp.hpp"
#include "common/event_manager.h"

namespace zsy
{
    struct MqttCliConfig
    {
        std::vector<MqttProperties> mqtts;
    };

    inline void from_json(const nlohmann::json &j, MqttCliConfig &o)
    {
        PARSE_JSON(mqtts, o.mqtts);
    }

    class MqttCli
    {
        using CLI = MQTT_NS::callable_overlay<MQTT_NS::sync_client<MQTT_NS::tcp_endpoint<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::asio::strand<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0> > > > >;
        using CLI_PTR = std::shared_ptr<CLI>;
        using packet_id_t = CLI::packet_id_t;
        MqttProperties config;
        // 0-->不可用、1-->可用、2-->已停止
        uint8_t status;
        std::shared_mutex status_mtx;
        std::shared_ptr<EventManager> eventManager;
        std::unique_ptr<std::jthread> eventLoop;
        std::shared_ptr<boost::asio::io_context> ioc;
        CLI_PTR cli;

        void connect();

        void run();

        bool onConnAck(bool sp, MQTT_NS::connect_return_code connack_return_code);

        void onClose();

        void onError(MQTT_NS::error_code ec);

        bool onMessage(MQTT_NS::optional<packet_id_t> packet_id, MQTT_NS::publish_options pubopts, MQTT_NS::buffer topic_,MQTT_NS::buffer payload_);

        void reconnect();

    public:
        static const std::string TYPE_REMOTE;
        static const std::string TYPE_LOCAL;

        MqttCli(MqttProperties &config, std::shared_ptr<EventManager> eventManager);

        std::string getClientId() const;

        template<typename Fn>
        void subscribe(std::string topic, uint8_t qos, Fn &&handler)
        {
            std::shared_lock lock(status_mtx);
            if (status == 0)
            {
                LOGGER_ERROR("MQTT 未连接，无法订阅：{}", config.clientId);
                return;
            }
            cli->subscribe(topic, static_cast<MQTT_NS::qos>(qos));
            eventManager->subscribe(config.clientId + "/" + topic, std::forward<Fn>(handler));
            LOGGER_INFO("MQTT：{} 已订阅：【{} {}】", config.clientId, topic, qos);
        }

        void publish(std::string topic, std::string payload, uint8_t qos);

        ~MqttCli();
    };

    class MqttCliHolder
    {
        std::vector<MqttProperties> configs;
        std::unordered_map<std::string, std::shared_ptr<MqttCli> > mqttClis;

    public:
        MqttCliHolder(const nlohmann::json &config, std::shared_ptr<EventManager> eventManager);

        std::shared_ptr<MqttCli> localCli();

        std::shared_ptr<MqttCli> remoteCli();
    };
} // zsy

#endif //MQTT_CLI_H
