#pragma once

#include <balancer/kernel/helpers/errors.h>
#include <balancer/kernel/module/module_face.h>
#include <balancer/kernel/balancing/backend.h>
#include <balancer/kernel/pinger/common/backend_pinger.h>
#include <balancer/kernel/pinger/pinger2.h>
#include <library/cpp/json/json_writer.h>
#include <util/datetime/base.h>
#include <util/generic/ptr.h>

namespace NSrvKernel {
    class TPerWorkerBaseBackend : public IBackend, public IPingableV2 {
    public:
        TPerWorkerBaseBackend(TBackendDescriptor::TRef backend) noexcept
            : Backend_(std::move(backend))
        {}

        TPerWorkerBaseBackend(TPerWorkerBaseBackend&&) noexcept = default;
        TPerWorkerBaseBackend& operator=(TPerWorkerBaseBackend&&) noexcept = default;

        IModule* Module() const noexcept override {
            return Backend_->Module();
        }

        IModule* ActiveCheckModule() const noexcept override {
            return Backend_->Module();
        }

        const TString& Name() const noexcept override {
            return Backend_->Name();
        }

        bool Enabled() const noexcept override {
            return Backend_->Enabled();
        }

        void SetEnabled(bool value) noexcept override {
            Backend_->SetEnabled(value);
        }

        bool Degraded() const noexcept override {
            return Backend_->Degraded();
        }

        void SetDegraded(bool value) noexcept override {
            Backend_->SetDegraded(value);
        }

        void SetGroupName(TString groupName) noexcept override {
            Backend_->SetGroupName(std::move(groupName));
        }

        void OnCompleteRequest(const TDuration& answerTime) noexcept override {
            Succ_++;
            DoOnCompleteRequest(answerTime);
        }

        void OnFailRequest(const TError& error, const TDuration& answerTime) noexcept override {
            Fail_++;
            DoOnFailRequest(error, answerTime);
        }

        virtual double WeightFromPing() const noexcept {
            return Backend_->WeightFromPing();
        }

        void SetWeightFromPing(double value, bool) noexcept override {
            Backend_->SetWeightFromPing(value);
        }

        double OriginalWeight() const noexcept override {
            return Backend_->Weight();
        }

        void PrintSuccFailRate(NJson::TJsonWriter& out) const noexcept {
            out.Write("succ", Succ_);
            out.Write("fail", Fail_);
        }

        void PrintProxyInfo(NJson::TJsonWriter& out) const noexcept {
            if (Backend_) {
                Backend_->Module()->PrintInfo(out);
            }
        }

    private:
        virtual void DoOnCompleteRequest(const TDuration&) /* noexcept */ {};
        virtual void DoOnFailRequest(const TError&, const TDuration&) /* noexcept */ {};

    protected:
        TBackendDescriptor::TRef Backend_;

    private:
        ui64 Succ_ = 0;
        ui64 Fail_ = 0;
    };
}
