#include "pinger_backend_group_manager.h"

#include <util/random/random.h>

namespace NSrvKernel {
    void TPingerBackendGroupManager::AddPinger(TString name, THolder<IBackendPinger> pinger) {
        const ui64 currentTime = Now().Seconds();
        LastPingTimeOfBackends_[name] = currentTime;
        ++PingTimeCount_[currentTime];

        auto pingerCont = TCoroutine{
            "backend_pinger", Executor_,
            [this, p = pinger.Get(), name = std::move(name)]() noexcept {
                auto* const cont = Executor_->Running();
                cont->SleepT(TDuration::Seconds(RandomNumber<double>() * p->Delay().SecondsFloat()));

                while (!cont->Cancelled()) {
                    const TDuration sleepTime = TDuration::Seconds((RandomNumber<double>() * 0.1 + 0.9) * p->Delay().Seconds());
                    const TInstant nextRequest = sleepTime.ToDeadLine();
                    auto backendStatus = p->Ping();
                    p->ProcessPingResult(backendStatus);
                    UpdatePingTimeOfBackend(name, Now().Seconds());
                    cont->SleepD(nextRequest);
                }
            }
        };

        pinger->LoadCounters(Counters_);
        Pingers_.push_back(std::move(pinger));
        PingerContsList_.push_back(std::move(pingerCont));
    }

    void TPingerBackendGroupManager::UpdatePingTimeOfBackend(const TString& backendName, ui64 pingTime) {
        auto flatMapIter = LastPingTimeOfBackends_.find(backendName);
        Y_ASSERT(flatMapIter != LastPingTimeOfBackends_.end());

        auto mapIter = PingTimeCount_.find(flatMapIter->second);
        Y_ASSERT(mapIter != PingTimeCount_.end());

        --mapIter->second;
        if (!mapIter->second) {
            PingTimeCount_.erase(mapIter);
        }
        flatMapIter->second = pingTime;
        ++PingTimeCount_[pingTime];
    }

    ui64 TPingerBackendGroupManager::GetTheOldestPingTime() const {
        if (PingTimeCount_.empty()) {
            return 0;
        }
        return PingTimeCount_.begin()->first;
    }

    TPingerBackendGroupManager::TPingerBackendGroupManager(TContExecutor* executor, TPingerStatsCounters* counters)
        : Executor_(executor)
        , Counters_(counters)
    {}
}
