#pragma once

#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

namespace dragonx {
namespace util {

class AsyncTaskManager {
public:
    class Token {
    public:
        Token() = default;
        explicit Token(std::shared_ptr<std::atomic<bool>> cancelled)
            : cancelled_(std::move(cancelled)) {}

        bool cancelled() const {
            return cancelled_ && cancelled_->load(std::memory_order_relaxed);
        }

    private:
        std::shared_ptr<std::atomic<bool>> cancelled_;
    };

    using Task = std::function<void(const Token&)>;

    AsyncTaskManager() = default;
    ~AsyncTaskManager();

    AsyncTaskManager(const AsyncTaskManager&) = delete;
    AsyncTaskManager& operator=(const AsyncTaskManager&) = delete;

    void submit(std::string name, Task task);
    void cancelAll();
    void join(const std::string& name);
    void joinAll();
    void reapCompleted();
    bool isRunning(const std::string& name) const;

private:
    struct TaskEntry {
        std::string name;
        std::shared_ptr<std::atomic<bool>> cancelled;
        std::shared_ptr<std::atomic<bool>> done;
        std::thread worker;
    };

    mutable std::mutex mutex_;
    std::vector<TaskEntry> tasks_;
};

} // namespace util
} // namespace dragonx
