#pragma once

#include <balancer/client/client.h>
#include <balancer/kernel/process_common/main_options.h>

#include <infra/yp_service_discovery/libs/sdlib/server_mock/server.h>

#include <library/cpp/config/config.h>
#include <library/cpp/testing/unittest/tests_data.h>

#include <util/thread/pool.h>


namespace NBalancerClient::NTesting {
    using namespace NSrvKernel;
    using NThreading::TFuture;

    struct TMainTaskOptions {
        size_t NetworkThreads = 1;
        size_t MaxConnPerNetworkThread = 8 * 1024;
        TDuration WorkerStartDelay = TDuration::Seconds(0);
    };

    struct TBalancerInstanceConfig {
    public:
        explicit TBalancerInstanceConfig(const TMainTaskOptions& options, size_t sdPort = 0);
    public:
        NJson::TJsonValue InstanceConfig;
        NConfig::TGlobals Globals;
        TMainOptions MainOptions;
    };

    class TEnv {
    public:
        TEnv();

        void Start();

        THolder<TBalancerClient> CreateSource(const NJson::TJsonValue& config);
        void DeleteSource(const TString& name);
        void CreateSimpleSource(const TString& name, ui16 status, const TString& content = "");

        THolder<TRequestContext> SendRequest(const TString& source, TRequest request, TString data);

        auto& SDServer() {
            return SDServer_;
        }

        auto& MainTask() {
            return *MainTask_;
        }

        ~TEnv();
    private:
        void WaitStart();

    private:
        TPortManager PM_;
        NYP::NServiceDiscovery::NTesting::TSDServer SDServer_;

        TMutex Lock_;
        TMainTaskOptions MainTaskOptions_;
        TBalancerInstanceConfig BalancerInstanceConfig_;
        TNodeFactory<IModule> Factory_;
        TAtomicSharedPtr<NProcessCore::TMainTask> MainTask_;
        TThreadPool MainTaskPool_;

        THashMap<TString, THolder<TBalancerClient>> NameToSource_;

        bool Started_ = false;
    };

    struct TBalancerProxyInstanceConfig {
    public:
        explicit TBalancerProxyInstanceConfig(ui16 proxyPort, ui16 serverPort, bool http2Backend);
    public:
        NJson::TJsonValue InstanceConfig;
        NConfig::TGlobals Globals;
        TMainOptions MainOptions;
        TMainTaskOptions MainTaskOptions;
    };

    class TProxy {
    public:
        TProxy(TBalancerProxyInstanceConfig&& config);

        void Start();

        void Stop();

        auto& MainTask() {
            return *MainTask_;
        }

        ~TProxy();
    private:
        void WaitStart();

    private:
        TMainTaskOptions MainTaskOptions_;
        TBalancerProxyInstanceConfig BalancerProxyInstanceConfig_;
        TNodeFactory<IModule> Factory_;
        TAtomicSharedPtr<NProcessCore::TMainTask> MainTask_;
        TThreadPool MainTaskPool_;
    };
}  // namespace NBalancerClient::NTesting
