#pragma once

#include "raw_socket_io.h"

#include <balancer/server/server.h>

#include <library/cpp/coroutine/engine/network.h>

#include <library/cpp/http/io/stream.h>

#include <library/cpp/openssl/io/stream.h>

#include <library/cpp/testing/unittest/registar.h>

#include <util/thread/pool.h>

namespace NBalancerServer::NTesting {

struct TRequestResult {
    TString Data;
    bool WasEncoded = false;
};

TServerCallback GetOkCallback();

TServerCallback GetEchoCallback();

template <typename TEnv>
void RunConcurrent(TServerCallback serverCallback, std::function<void(TEnv&)> requestCallback, const TOptions& options,
                   size_t nReqsPerThread = 1000, bool useTwoPorts = false)
{
    TEnv env;

    const size_t nThreads = 5;

    env.Start(serverCallback, TOptions(options).SetNetworkThreads(nThreads), useTwoPorts);

    TThreadPool shoot;
    shoot.Start(nThreads, 0);

    TAtomic requestCount = 0;
    for (size_t i = 0; i < nThreads; ++i) {
        UNIT_ASSERT(
            shoot.AddFunc([&env, &requestCount, &requestCallback, nReqsPerThread]() {
                for (size_t j = 0; j < nReqsPerThread; ++j) {
                    requestCallback(env);
                    AtomicIncrement(requestCount);
                }
            })
        );
    }

    shoot.Stop();

    UNIT_ASSERT_VALUES_EQUAL(requestCount, nThreads * nReqsPerThread);

    env.Stop();
}

TString Repeat(const TString& v, size_t n);

void SendRequest(THttpOutput& out, const TString& request, const TString& data, const TString& compression,
                 const TString& acceptEncoding);

TRequestResult SendHttpRequest(TCont* cont, size_t port, const TString& request, const TString& data,
                               const TString& compression = {}, const TString& acceptEncoding = {});

TRequestResult SendHttpsRequest(TCont* cont, size_t sslPort, const TString& request, const TString& data,
                                const TString& compression = {}, const TString& acceptEncoding = {});

}  // namespace NBalancerServer::NTesting

