BareGit
#pragma once

#include <chrono>
#include <condition_variable>
#include <coroutine>
#include <cstddef>
#include <memory>
#include <mutex>
#include <functional>
#include <stop_token>
#include <thread>
#include <vector>

namespace agent_smith::internal
{

class TimerService
{
private:
    struct Entry;

public:
    TimerService();
    ~TimerService();

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

    class SleepAwaiter
    {
    public:
        SleepAwaiter(TimerService& service, std::chrono::milliseconds duration,
                     std::stop_token stop);

        bool await_ready() const;
        bool await_suspend(std::coroutine_handle<> continuation);
        void await_resume() const noexcept {}

    private:
        TimerService* service_;
        std::chrono::milliseconds duration_;
        std::shared_ptr<Entry> entry_;
        std::unique_ptr<std::stop_callback<std::function<void()>>> callback_;
    };

    SleepAwaiter sleepFor(std::chrono::milliseconds duration,
                         std::stop_token stop = {});

private:
    struct Entry
    {
        std::chrono::steady_clock::time_point deadline;
        std::coroutine_handle<> continuation = nullptr;
        std::stop_token stop;
    };

    void schedule(const std::shared_ptr<Entry>& entry,
                  std::coroutine_handle<> continuation);
    void worker(std::stop_token stop);

    std::mutex mutex_;
    std::condition_variable condition_;
    std::vector<std::shared_ptr<Entry>> entries_;
    std::jthread worker_;
};

} // namespace agent_smith::internal