BareGit
#include "agent_smith/runtime.hpp"

#include "detail/timer_service.hpp"
#include "agent_smith/detail/gather_all.hpp"
#include "agent_smith/sync_wait.hpp"
#include <algorithm>

namespace agent_smith
{

Runtime::Runtime(RuntimeConfig cfg)
    : cfg_(cfg), http_(std::make_unique<mw::HTTPSessionAsync>()),
      blocking_pool_(std::make_unique<internal::BlockingPool>(
          cfg_.blocking_pool_size)),
      timer_service_(std::make_unique<internal::TimerService>())
{
    auto& http = static_cast<mw::HTTPSessionAsyncInterface&>(*http_);
    [[maybe_unused]] auto connection_timeout =
        http.connectionTimeout(cfg_.connection_timeout);
    [[maybe_unused]] auto transfer_timeout =
        http.transferTimeout(cfg_.transfer_timeout);
}

Runtime::~Runtime()
{
    // Keep HTTP, workers, and timers alive until timed-out work finishes.
    // A background operation may itself register additional work.
    for(;;)
    {
        std::vector<internal::StartedTask<void>> pending;
        {
            std::lock_guard lock(background_mutex_);
            pending.swap(background_tasks_);
        }
        if(pending.empty())
        {
            break;
        }
        [[maybe_unused]] auto results =
            syncWait(internal::gatherAllStarted(std::move(pending)));
    }
    http_.reset();
}

void Runtime::retain(internal::StartedTask<void> task)
{
    std::lock_guard lock(background_mutex_);
    std::erase_if(background_tasks_,
                  [](const auto& item) { return item.complete(); });
    background_tasks_.push_back(std::move(task));
}

mw::HTTPSessionAsync& Runtime::http()
{
    return *http_;
}

mw::Task<mw::E<void>> Runtime::sleepFor(std::chrono::milliseconds duration)
{
    co_return co_await sleepFor(duration, {});
}

mw::Task<mw::E<void>> Runtime::sleepFor(std::chrono::milliseconds duration,
                                     std::stop_token stop)
{
    if(duration < std::chrono::milliseconds::zero())
    {
        co_return std::unexpected(
            mw::runtimeError("sleep duration cannot be negative"));
    }

    co_await timer_service_->sleepFor(duration, stop);
    co_return mw::E<void>{};
}

} // namespace agent_smith