#pragma once

#include <balancer/kernel/balancing/per_worker_backend.h>
#include <balancer/kernel/balancer/algorithm.h>
#include <balancer/kernel/balancing/backend.h>
#include <balancer/kernel/balancer/policy.h>
#include <balancer/kernel/pinger/pinger.h>

namespace NSrvKernel {

class IBackends;
template <class> class INodeHandle;

namespace NModBalancer::Nleastconn {
    constexpr char NAME[] = "leastconn";
    struct TTls;
    struct TBackends;
}  // namespace NModBalancer::Nleastconn

namespace NModBalancer::NLeastConn {

struct TCmp {
    template<class T>
    static bool Compare(const T& l, const T& r) noexcept {
        return std::make_tuple(l.Connections_, l.Usage_, &l) <
               std::make_tuple(r.Connections_, r.Usage_, &r);
    }
};

class TNode : public TRbTreeItem<TNode, TCmp> {
public:
    TNode(int connections, IBackend* backend) noexcept
            : Connections_(connections), Backend_(backend) {}

    int Connections_;
    size_t Usage_ = 0;
    IBackend* Backend_ = nullptr;
};

class TBackend : public TPerWorkerBaseBackend {
public:
    TBackend(TBackendDescriptor::TRef descr, Nleastconn::TTls& tls)
        : TPerWorkerBaseBackend(std::move(descr))
        , Tls_(tls)
        , BackendNode_(0, this)
    {}

    void DoOnCompleteRequest(const TDuration&) noexcept override;

    void DoOnFailRequest(const TError&, const TDuration&) noexcept override;

    TNode* GetBackendNode() noexcept;

    void PrintInfo(NJson::TJsonWriter& out) const noexcept;

private:
    Nleastconn::TTls& Tls_;
    TNode BackendNode_;
};

INodeHandle<IBackends>* Handle();

}  // namespace NModBalancer::NLeastConn

namespace NModBalancer::Nleastconn {
struct TTls {
    TDeque<NLeastConn::TBackend> Backends;
    THashMap<TString, NLeastConn::TBackend*> NamedBackends;
    TRbTree<NLeastConn::TNode, NLeastConn::TCmp> BackendsTree;
};
}  // namespace NModBalancer::Nleastconn



}  // namespace NSrvKernel
