#include "client.h"

#include <balancer/kernel/process/thread_info.h>
namespace NBalancerClient {

    TBalancerClient::TBalancerClient(TAtomicSharedPtr<NSrvKernel::NProcessCore::TMainTask> mainTask,
        NSrvKernel::TNodeFactory<NSrvKernel::IModule>& modulesFactory, const TString& moduleName,
        const NJson::TJsonValue& jsonConfig)
        : ModulesFactory_(modulesFactory)
        , MainTask_(std::move(mainTask))
        , ChannelListener_(MainTask_->GetChannelListener())
        , Tree_(MainTask_->CreateTree(::ToString(jsonConfig), moduleName, ModulesFactory_))
    {
        MainTask_->AddExternalTree(*Tree_);
    }


    THolder<TRequestContext>
    TBalancerClient::SendRequest(NSrvKernel::TRequest request, TString data,
        THolder<NSrvKernel::IAttemptsHolder> attemptsHolder,
        TAtomicSharedPtr<NSrvKernel::TU2WChannel<TString>> inputChannel, bool inplace, TLog* errorLog)
    {
        return SendRequest(std::move(request), std::move(data), nullptr, std::move(attemptsHolder), std::move(inputChannel), nullptr, inplace, errorLog);
    }

    THolder<TRequestContext>
    TBalancerClient::SendRequest(NSrvKernel::IClientRequestRef clientRequest,
        THolder<NSrvKernel::IAttemptsHolder> attemptsHolder,
        TAtomicSharedPtr<NSrvKernel::TU2WChannel<TString>> inputChannel, bool inplace, TLog* errorLog)
    {
        return SendRequest(NSrvKernel::TRequest(), TString(), std::move(clientRequest), std::move(attemptsHolder), std::move(inputChannel), nullptr, inplace, errorLog);
    }

    TBalancerClient::~TBalancerClient() {
        MainTask_->RemoveExternalTree(*Tree_);
    }

    THolder<TRequestContext>
    TBalancerClient::SendRequest(NSrvKernel::TRequest request,
                                 TString data,
                                 NSrvKernel::IClientRequestRef clientRequest,
                                 THolder<NSrvKernel::IAttemptsHolder> attemptsHolder,
                                 TAtomicSharedPtr<NSrvKernel::TU2WChannel<TString>> inputChannel,
                                 TAtomicSharedPtr<NSrvKernel::TW2UChannel<TString>> outputChannel,
                                 bool inplace,
                                 TLog* errorLog) {
        auto promise = NThreading::NewPromise<TBalancerClientResponseContext>();
        auto future = promise.GetFuture();

        auto context = MakeHolder<TRequestContext>(
                *Tree_->Entry,
                std::move(request),
                std::move(data),
                std::move(attemptsHolder),
                std::move(clientRequest),
                std::move(inputChannel),
                std::move(outputChannel),
                std::move(promise),
                errorLog
        );

        if (inplace) {
            auto* worker = FastTlsSingleton<NSrvKernel::NProcessCore::TThreadInfo>()->WorkerProcess;
            Y_ENSURE(worker, "call inplace request outside of worker thread");
            context->RunRequest(worker);
        } else {
            Y_ENSURE(ChannelListener_.SendRequest(context.Get()) == NSrvKernel::EChannelStatus::Success, "channel error");
        }
        return context;
    }
}
