#include "mqtt_svr.h"

#include "common/spdlog/logging.h"
#include <string>
#include <vector>

#include "app/app.h"
#include "common/utils/str_util.h"

namespace zsy
{
    void MQTTSvr::run()
    {
        svr->listen();
        reportAvailable();
        LOGGER_INFO("MQTT 服务启动成功，端口：{}", config.port());
        ioc->run();
        reportTerminated();
        LOGGER_INFO("MQTT 服务已停止");
    }

    void MQTTSvr::close_proc(con_sp_t const &con)
    {
        if (!running)return;
        try
        {
            {
                std::lock_guard lock(connections_mutex);
                connections->erase(con);
            }
            std::lock_guard lock(subs_mutex);
            auto &idx = subs->get<tag_con>();
            auto r = idx.equal_range(con);
            idx.erase(r.first, r.second);
        } catch (...)
        {
            LOGGER_ERROR("MQTT 服务关闭失败");
        }
    }

    bool MQTTSvr::matchTopic(const std::string &topic_filter, const std::string &topic)
    {
        // ======================================
        // 步骤1：前置合法性校验（遵循 MQTT 规范）
        // ======================================
        // 1.1 空主题/空过滤器直接不匹配
        if (topic_filter.empty() || topic.empty())
        {
            return false;
        }

        // 1.2 发布者主题（topic）不允许包含任何通配符（+ / #）
        if (topic.find('+') != std::string::npos || topic.find('#') != std::string::npos)
        {
            return false;
        }

        // 1.3 校验多层通配符 # 的合法性（MQTT 严格规则）
        size_t hash_pos = topic_filter.find('#');
        if (hash_pos != std::string::npos)
        {
            // # 必须是最后一个字符，且只能出现一次
            if (hash_pos != topic_filter.size() - 1)
            {
                return false;
            }
            // # 前面必须紧跟 '/'（唯一例外：单独的 "#"）
            if (topic_filter.size() > 1 && (hash_pos == 0 || topic_filter[hash_pos - 1] != '/'))
            {
                return false;
            }
        }

        // ======================================
        // 步骤2：拆分主题和过滤器为层级列表
        // ======================================
        const std::vector<std::string> filter_levels = StrUtil::split(topic_filter, "/");
        const std::vector<std::string> topic_levels = StrUtil::split(topic, "/");

        // ======================================
        // 步骤3：逐层级进行匹配（核心逻辑）
        // ======================================
        size_t filter_idx = 0; // 过滤器层级索引
        size_t topic_idx = 0; // 主题层级索引

        while (filter_idx < filter_levels.size() && topic_idx < topic_levels.size())
        {
            const std::string &current_filter = filter_levels[filter_idx];
            const std::string &current_topic = topic_levels[topic_idx];

            // 3.1 匹配多层通配符 #（匹配当前及所有子层级，直接返回成功）
            if (current_filter == "#")
            {
                return true;
            }

            // 3.2 匹配单层通配符 +（仅匹配当前层级，双方索引都+1）
            if (current_filter == "+")
            {
                filter_idx++;
                topic_idx++;
                continue;
            }

            // 3.3 普通层级（严格大小写匹配，完全相等才继续）
            if (current_filter != current_topic)
            {
                return false;
            }

            // 3.4 普通层级匹配成功，推进索引
            filter_idx++;
            topic_idx++;
        }

        // ======================================
        // 步骤4：处理层级遍历完毕后的边界场景
        // ======================================
        // 场景4.1：过滤器遍历完毕，且最后一个层级是 #（已在步骤3中处理，此处兜底）
        if (filter_idx < filter_levels.size() && filter_levels[filter_idx] == "#")
        {
            return true;
        }

        // 场景4.2：过滤器和主题都恰好遍历完毕（完全匹配，无剩余层级）
        if (filter_idx == filter_levels.size() && topic_idx == topic_levels.size())
        {
            return true;
        }

        // 场景4.3：过滤器还有剩余普通层级，或主题还有剩余层级（不匹配）
        // 例如：过滤器 "sensor/+"，主题 "sensor/temperature/room1"（过滤器层级不足）
        // 例如：过滤器 "sensor/temperature"，主题 "sensor"（主题层级不足）
        return false;
    }

    MQTTSvr::MQTTSvr(const MQTTConfig_Svr &config)
        : running(true),
          config(config),
          connections(std::make_shared<std::set<con_sp_t> >()),
          subs(std::make_shared<mi_sub_con>())
    {
        reportInitializing();

        uint32_t port = config.port();
        LOGGER_INFO("MQTT 服务正在启动，端口：{}", port);

        ioc = std::make_shared<boost::asio::io_context>();

        svr = std::make_shared<MQTT_NS::server<> >(
            boost::asio::ip::tcp::endpoint(
                boost::asio::ip::tcp::v4(),
                boost::lexical_cast<std::uint16_t>(port)),
            *ioc);

        svr->set_error_handler([this](MQTT_NS::error_code ec)
        {
            reportTerminated();
            LOGGER_ERROR("MQTT 服务启动失败: {}", StrUtil::str_w_a(StrUtil::str_a_w(ec.message(), "GBK")));
        });
        svr->set_accept_handler([this](con_sp_t spep)
        {
            auto &ep = *spep;
            std::weak_ptr<con_t> wp(spep);

            using packet_id_t = std::remove_reference_t<decltype(ep)>::packet_id_t;

            ep.start_session(std::move(spep));

            ep.set_close_handler([this, wp]
            {
                LOGGER_INFO("MQTT 客户端断开连接");
                auto sp = wp.lock();
                close_proc(sp);
            });
            ep.set_error_handler([this, wp](MQTT_NS::error_code ec)
            {
                LOGGER_ERROR("MQTT 客户端断开连接: {}", StrUtil::str_w_a(StrUtil::str_a_w(ec.message(), "GBK")));
                const auto sp = wp.lock();
                close_proc(sp);
            });

            ep.set_connect_handler([this, wp](MQTT_NS::buffer client_id, MQTT_NS::optional<MQTT_NS::buffer> username, MQTT_NS::optional<MQTT_NS::buffer> password, MQTT_NS::optional<MQTT_NS::will> will_, bool clean_session, std::uint16_t keep_alive)
            {
                if (!running)return true;
                using namespace MQTT_NS::literals;
                LOGGER_INFO("MQTT 客户端连接成功:{}、{}、{}", client_id, username.has_value() ? std::string(username.value().begin(), username.value().end()) : "none", password.has_value() ? std::string(password.value().begin(), password.value().end()) : "none");
                auto sp = wp.lock();
                std::lock_guard<std::mutex> lock(connections_mutex);
                connections->insert(sp);
                sp->connack(false, MQTT_NS::connect_return_code::accepted);
                return true;
            });
            ep.set_disconnect_handler([this, wp]
            {
                LOGGER_INFO("MQTT 客户端断开连接");
                auto sp = wp.lock();
                close_proc(sp);
            });
            ep.set_pingreq_handler([wp]
            {
                auto sp = wp.lock();
                sp->pingresp();
                return true;
            });

            ep.set_puback_handler([](packet_id_t packet_id)
            {
                // LOGGER_INFO("MQTT 客户端发布消息确认:{}", packet_id);
                return true;
            });
            ep.set_pubrec_handler([](packet_id_t packet_id)
            {
                // LOGGER_INFO("MQTT 客户端发布消息确认:{}", packet_id);
                return true;
            });
            ep.set_pubrel_handler([](packet_id_t packet_id)
            {
                // LOGGER_INFO("MQTT 客户端发布消息确认:{}", packet_id);
                return true;
            });
            ep.set_pubcomp_handler([](packet_id_t packet_id)
            {
                // LOGGER_INFO("MQTT 客户端发布消息确认:{}", packet_id);
                return true;
            });
            ep.set_publish_handler([this](MQTT_NS::optional<packet_id_t> packet_id, MQTT_NS::publish_options pubopts, MQTT_NS::buffer topic_name, MQTT_NS::buffer contents)
            {
                // LOGGER_INFO("MQTT 客户端发布消息:{}、{}", topic_name, contents);
                if (!running)return true;
                std::lock_guard<std::mutex> lock(subs_mutex);
                auto const &idx = subs->get<tag_topic>();

                const std::string &pub_topic = std::string(topic_name.begin(), topic_name.end());
                for (const auto &sub: idx)
                {
                    if (const std::string &sub_topic = std::string(sub.topic.begin(), sub.topic.end()); matchTopic(sub_topic, pub_topic))
                    {
                        // LOGGER_INFO("MQTT 服务发布消息:接收主题：{}、发布主题：{}、内容：{}",sub_topic, pub_topic, contents);
                        sub.con->publish(
                            topic_name,
                            contents,
                            std::min(sub.qos_value, pubopts.get_qos())
                        );
                    }
                }

                return true;
            });
            ep.set_subscribe_handler([this, wp](packet_id_t packet_id, std::vector<MQTT_NS::subscribe_entry> entries)
            {
                // LOGGER_INFO("MQTT 客户端订阅消息:{}", packet_id);
                if (!running)return true;
                std::vector<MQTT_NS::suback_return_code> res;
                res.reserve(entries.size());
                auto sp = wp.lock();
                for (auto const &e: entries)
                {
                    res.emplace_back(MQTT_NS::qos_to_suback_return_code(e.subopts.get_qos()));
                    std::lock_guard<std::mutex> lock(subs_mutex);
                    subs->emplace(std::move(e.topic_filter), sp, e.subopts.get_qos());
                }
                sp->suback(packet_id, res);
                return true;
            });
            ep.set_unsubscribe_handler([this, wp](packet_id_t packet_id, std::vector<MQTT_NS::unsubscribe_entry> entries)
            {
                if (!running)return true;
                auto sp = wp.lock();
                for (auto const &e: entries)
                {
                    std::lock_guard<std::mutex> lock(subs_mutex);
                    auto it = subs->find(std::make_tuple(sp, e.topic_filter));
                    if (it != subs->end())
                    {
                        subs->erase(it);
                    }
                }
                sp->unsuback(packet_id);
                return true;
            });
        });

        eventLoop = std::make_unique<std::jthread>(&MQTTSvr::run, this);
        waitStarted();
    }

    std::string MQTTSvr::name() const noexcept
    {
        return config.name();
    }

    std::string MQTTSvr::sn() const noexcept
    {
        return config.sn();
    }

    void MQTTSvr::init()
    {
        if (!App::APP_CONFIG->has_mqtt_config())return;
        if (!App::APP_CONFIG->mqtt_config().has_svr())return;
        MQTT_SVR = std::make_shared < MQTTSvr > (App::APP_CONFIG->mqtt_config().svr());
    }

    void MQTTSvr::destroy()
    {
        MQTT_SVR.reset();
        MQTT_SVR = nullptr;
    }

    std::shared_ptr<MQTTSvr> MQTTSvr::get()
    {
        return MQTT_SVR;
    }

    MQTTSvr::~MQTTSvr()
    {
        reportTerminated();
        running = false;
        LOGGER_INFO("MQTT 服务正在关闭");
        svr->close();
        std::lock_guard lock1(connections_mutex);
        std::lock_guard lock2(subs_mutex);
        connections->clear();
        subs->clear();
        ioc->stop();
        eventLoop->join();
        LOGGER_INFO("MQTT 服务已关闭");
    }
} // zsy