#include "pinger.h"

#include <balancer/kernel/requester/requester.h>

namespace NSrvKernel {

TPinger::TPinger(IPingable& backend, const TInstant& lastRequestTime, TContExecutor* const exec,
                const TPingerConfig& config, IWorkerCtl& process, bool steady)
    : Backend_(backend)
    , LastRequestTime_(lastRequestTime)
    , Config_(config)
    , Process_(process)
    , Steady_(steady)
    , LastPingTime_(Now().Seconds())
{
    PingerCont_ = TCoroutine{"backend_pinger", exec, [this](TContExecutor* const exec) noexcept {
        auto* const cont = exec->Running();
        cont->SleepT(TDuration::Seconds(RandomNumber<double>() * Config_.Delay.SecondsFloat()));
        while (!cont->Cancelled()) {
            if (Steady_ || Now() - LastRequestTime_ < Config_.Delay) {
                Backend_.SetEnabled(Ping());
            }

            cont->SleepT(Config_.Delay);
        }
    }, exec};
}

bool TPinger::Ping() noexcept {
    TAsyncRequester requester(*Backend_.ActiveCheckModule(), nullptr, Process_);
    requester.Props().SkipKeepalive = true;
    bool ok = false;

    Y_TRY(TError, error) {
        if (Config_.PingRequest) {
            TResponse response;
            Y_PROPAGATE_ERROR(requester.Requester().Request(TRequest(*Config_.PingRequest), response));
            ok = response.ResponseLine().StatusCode == HTTP_OK;
        } else {
            TNullStream in;
            TNullStream out;
            Y_PROPAGATE_ERROR(requester.Requester().TcpRequest(in, out));
            ok = true;
        }
        return {};
    } Y_CATCH {
    }

    if (ok) {
        LastPingTime_ = Now().Seconds();
    }

    return ok;
}

}  // namespace NSrvKernel
