#ifndef DEVICE_CTRL_MQTT_SVR_H
#define DEVICE_CTRL_MQTT_SVR_H

#include <mqtt_server_cpp.hpp>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>

#include "mqtt/mqtt_config.pb.h"
#include "app/bean.h"

namespace zsy
{
    class MQTTSvr : public Bean
    {
        inline static std::shared_ptr<MQTTSvr> MQTT_SVR;
        using con_t = MQTT_NS::server<>::endpoint_t;
        using con_sp_t = std::shared_ptr<con_t>;

        struct sub_con
        {
            sub_con(MQTT_NS::buffer topic, con_sp_t con, MQTT_NS::qos qos_value)
                : topic(std::move(topic)), con(std::move(con)), qos_value(qos_value)
            {
            }

            MQTT_NS::buffer topic;
            con_sp_t con;
            MQTT_NS::qos qos_value;
        };

        struct tag_topic
        {
        };

        struct tag_con
        {
        };

        struct tag_con_topic
        {
        };

        using mi_sub_con = boost::multi_index::multi_index_container<
            sub_con,
            boost::multi_index::indexed_by<
                boost::multi_index::ordered_unique<
                    boost::multi_index::tag<tag_con_topic>,
                    boost::multi_index::composite_key<
                        sub_con,
                        BOOST_MULTI_INDEX_MEMBER(sub_con, con_sp_t, con),
                        BOOST_MULTI_INDEX_MEMBER(sub_con, MQTT_NS::buffer, topic)
                    >
                >,
                boost::multi_index::ordered_non_unique<
                    boost::multi_index::tag<tag_topic>,
                    BOOST_MULTI_INDEX_MEMBER(sub_con, MQTT_NS::buffer, topic)
                >,
                boost::multi_index::ordered_non_unique<
                    boost::multi_index::tag<tag_con>,
                    BOOST_MULTI_INDEX_MEMBER(sub_con, con_sp_t, con)
                >
            >
        >;

        void run();

        void close_proc(con_sp_t const &con);

        std::atomic_bool running;
        MQTTConfig_Svr config;
        std::mutex connections_mutex;
        std::mutex subs_mutex;
        std::unique_ptr<std::jthread> eventLoop;
        std::shared_ptr<std::set<con_sp_t> > connections;
        std::shared_ptr<mi_sub_con> subs;
        std::shared_ptr<boost::asio::io_context> ioc;
        std::shared_ptr<MQTT_NS::server<> > svr;

        bool matchTopic(const std::string &topic_filter, const std::string &topic);

    public:
        std::string name() const noexcept override;

        std::string sn() const noexcept override;

        static void init();

        static void destroy();

        static std::shared_ptr<MQTTSvr> get();

        MQTTSvr(const MQTTConfig_Svr &config);

        ~MQTTSvr() override;
    };
} // zsy

#endif //DEVICE_CTRL_MQTT_SVR_H