#ifndef DEVICE_CTRL_MITT_H
#define DEVICE_CTRL_MITT_H

#include <coroutine>
#include <functional>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <oneapi/tbb/concurrent_unordered_map.h>
#include <oneapi/tbb/concurrent_vector.h>
#include <taskflow/taskflow.hpp>

#include "common/spdlog/logging.h"

/**
 * 发布订阅（回调函数为异步执行）
 * <pre>示例：
// 1、声明事件（带参），模板参数为常引
zsy::Mitt::MittEvent<const int &> e1{};
// 2、订阅事件，模板参数为常引
e1.$on([](const int &i)
{
    std::cout << i << std::endl;
});
// 3、发布事件
int e = 1;
e1.$emit(e);
int &a = e;
e1.$emit(a);
e1.$emit(1);

// 1、声明事件（无参）
zsy::Mitt::MittVoidEvent e2;
// 2、订阅事件
e2.$on([]
{
    std::cout << 1 << std::endl;
});
// 3、发布事件
e2.$emit();
</pre>
 */
namespace zsy::Mitt
{
    struct EventKey
    {
        const void *ptr;
        const std::type_info *type;
        const std::shared_ptr<std::shared_mutex> mtx;

        EventKey(const void *p, const std::type_info *ti) noexcept;

        bool operator==(const EventKey &other) const noexcept;
    };

    struct EventKeyHash
    {
        std::size_t operator()(const EventKey &key) const noexcept;
    };

    // 常左值引用约束
    template<typename T>
    concept IsConstLvalueReference =
            std::is_lvalue_reference_v<T> &&
            std::is_const_v<std::remove_reference_t<T> >;

    // 带参回调函数约束 (val: any) -> void
    template<typename F, typename T>
    concept EventCallbackConcept =
            IsConstLvalueReference<T> &&
            std::invocable<F, T> &&
            std::same_as<std::invoke_result_t<F, T>, void>;

    // 无参回调函数约束 () -> void
    template<typename F>
    concept EventCallbackWithoutArgConcept =
            std::invocable<F> &&
            std::same_as<std::invoke_result_t<F>, void>;

    // 带参回调函数
    template<typename E>
    using EventCallback = std::function<void(E)>;
    // 无参回调函数
    using EventCallbackWithoutArg = std::function<void()>;

    // 事件池
    using MittEventPool = oneapi::tbb::concurrent_unordered_map<EventKey, oneapi::tbb::concurrent_vector<std::shared_ptr<void> >, EventKeyHash>;
    inline MittEventPool EventPool;

    // 线程池
    inline tf::Executor Exec(std::thread::hardware_concurrency() * 2);

    /**
     * 事件（有参），同一个事件实例应全局保留一份
     *
     * @tparam T 事件回调函数的参数类型，常引类型
     */
    template<IsConstLvalueReference T>
    class MittEvent
    {
        std::shared_ptr<EventKey> key;

    public:
        MittEvent() : key(nullptr)
        {
            const auto event_ptr = static_cast<const void *>(this);
            const std::type_info *event_type = &typeid(MittEvent);
            key = std::make_shared<EventKey>(event_ptr, event_type);
        }

        static std::shared_ptr<MittEvent<T> > make_event()
        {
            return std::shared_ptr<MittEvent<T> >(new MittEvent<T>());
        }


        template<typename H>
            requires EventCallbackConcept<H, T>
        void $on(H &&handler)
        {
            std::unique_lock lock(*key->mtx);
            auto handler_ptr = std::make_shared<EventCallback<T> >(std::forward<H>(handler));
            EventPool[*key].push_back(std::static_pointer_cast<void>(handler_ptr));
        }

        void $emit(const std::remove_reference_t<T> &e)
        {
            std::shared_lock lock(*key->mtx);

            const auto it = EventPool.find(*key);
            if (it == EventPool.end()) return;
            tf::Taskflow tf;
            auto count = 0;
            for (const auto &callback_list = it->second; const auto &void_ptr: callback_list)
            {
                if (auto callback_ptr = std::static_pointer_cast<EventCallback<T> >(void_ptr))
                {
                    count++;
                    std::remove_reference_t<T> param = e;
                    tf.emplace([callback_ptr, param ]
                    {
                        try
                        {
                            (*callback_ptr)(std::as_const(param));
                        } catch (const std::exception &ex)
                        {
                            LOGGER_ERROR("任务执行失败：{}", ex.what());
                        } catch (...)
                        {
                            LOGGER_ERROR("任务执行失败：未知错误");
                        }
                    });
                }
            }

            if (count > 0) Exec.run(std::move(tf));
        }

        ~MittEvent()
        {
            std::unique_lock lock(*key->mtx);
            EventPool.unsafe_erase(*key);
        }
    };

    /**
     * 事件（无参），同一个事件实例应全局保留一份
     */
    class MittVoidEvent
    {
        std::shared_ptr<EventKey> key;

    public:
        MittVoidEvent();

        static std::shared_ptr<MittVoidEvent> make_event();

        template<typename H>
            requires EventCallbackWithoutArgConcept<H>
        void $on(H &&handler)
        {
            std::unique_lock lock(*key->mtx);
            auto handler_ptr = std::make_shared<EventCallbackWithoutArg>(std::forward<H>(handler));
            EventPool[*key].push_back(std::static_pointer_cast<void>(handler_ptr));
        }

        void $emit() const;

        ~MittVoidEvent();
    };
}

#endif //DEVICE_CTRL_MITT_H