/**
 * 这是一个线程不安全(单线程)版的event,不可以用于多线程
 */
#ifndef ZCPPWIN_EVENT_HPP
#define ZCPPWIN_EVENT_HPP
#include <cstdint>
#include <functional>
#include <memory>
#include <unordered_map>
#include <vector>
#include <utility>
namespace Z {
template<typename... Args>
class Event {
public:
    using Callback = std::function<void(Args...)>;
private: //region Event::private
    struct Handle {
        uint64_t id{};
        std::weak_ptr<void> guard;
        Callback cb;
    };
    struct State {
        uint64_t nextID{1};
    };
    void Disconn_(uint64_t id) {
        m_handles.erase(id);
    }
    static bool IsAlive(Handle &h) {
        // guard为null->活
        if (!h.guard.owner_before(std::weak_ptr<void>{}) &&
            !std::weak_ptr<void>{}.owner_before(h.guard)) {
            return true;
        }
        // guard非null且已死->死
        if (h.guard.expired())return false;
        // guard非null且活->活
        return true;
    }
private:
    std::shared_ptr<State> m_state;
    std::unordered_map<uint64_t, Handle> m_handles;
public:
    class Connection { //region class Connection
    public:
        Connection() = default;
        Connection(const Connection &) = delete;
        Connection &operator=(const Connection &) = delete;

        Connection(Connection &&other) noexcept { MoveFrom(std::move(other)); }
        Connection &operator=(Connection &&other) noexcept {
            if (this != &other) {
                Disconnect();
                MoveFrom(std::move(other));
            }
            return *this;
        }

        ~Connection() { Disconnect(); }
    private:
        friend class Event;
        Connection(uint64_t id, Event *owner, std::weak_ptr<State> wp) :
            m_id(id), m_owner(owner), guard_state(wp) {}
        void Disconnect() {
            if (m_id == 0 || guard_state.expired()) { return; }
            m_owner->Disconn_(m_id);
            m_id = 0;
        }
        void MoveFrom(Connection &&other) noexcept {
            m_owner = other.m_owner;
            m_id = other.m_id;
            other.m_owner = nullptr;
            other.m_id = 0;
        }
    private:
        uint64_t m_id;
        Event *m_owner;
        const std::weak_ptr<State> guard_state;
    }; //Class Connection

    Event() {
        m_state = std::make_shared<State>();
    }
    Connection Subscribe(Callback cb) {

        Handle h{m_state->nextID++, {}, std::move(cb)};
        m_handles.emplace(h.id, std::move(h));
        return {h.id, this, std::weak_ptr{m_state}};
    }
    void EmitEvent(Args... args) {
        std::vector<uint64_t> cleanIds{};
        for (auto &kv: m_handles) {
            if (!IsAlive(kv.second)) {
                cleanIds.push_back(kv.first);
            } else {
                kv.second.cb(args...);
            }
        }
        if (!cleanIds.empty()) {
            for (auto &id: cleanIds) {
                m_handles.erase(id);
            }
        }
    }
};

}


#endif //ZCPPWIN_EVENT_HPP
