#include "sender_neh.h"
#include "protocol.h"
#include <saas/protos/reply.pb.h>
#include <saas/protos/rtyserver.pb.h>
#include <saas/util/logging/exception_process.h>

namespace NRTYServer {

    TNehContext::TNehContext(NNeh::THandleRef handle, const NRTYServer::TMessage& message)
        : TInfoContext(message)
        , Handle(handle)
    {
    }

    TNehContext::~TNehContext() = default;

    void TNehContext::Cancel() {
        Handle->Cancel();
    }

    TNehSender::TNehSender(const TString& protocol, const TString& host, const ui16 port)
        : Address(NRTYServer::GetScheme(protocol) + "://" + host + ":" + ToString(port) + "/")
        , Protocol(protocol)
    {
    }

    TNehSender::TNehSender(const TString& host, const ui16 port)
        : TNehSender(NRTYServer::IndexingNehProtocol, host, port)
    {
    }

    TNehSender::~TNehSender() {
    }

    IContext::TPtr TNehSender::Send(const NRTYServer::TMessage& message, const TString& /*request*/) const {
        TStringStream data;
        message.SerializeToArcadiaStream(&data);
        NNeh::TMessage nehMessage(Address, data.Str());
        TRY
            return new TNehContext(NNeh::ProtocolFactory()->Protocol(Protocol)->ScheduleRequest(nehMessage, nullptr, Stat), message);
        CATCH("while writing document " + ToString(message.GetMessageId()));
        return nullptr;
    }

    bool TNehSender::Recv(IContext::TPtr context, NRTYServer::TReply& reply, TDuration timeout) const {
        TNehContext* nehContext = dynamic_cast<TNehContext*>(context.Get());
        Y_ASSERT(nehContext);
        NNeh::THandleRef& hndl = nehContext->GetHandle();
        NNeh::TResponseRef resp;
        reply.SetMessageId(nehContext->GetId());

        const bool result = (timeout != TDuration::Zero()) ? hndl->Wait(resp, timeout) : hndl->Wait(resp);
        if (!result)
            return false;

        if (!resp) {
            DEBUG_LOG << "action=recv_failed;message=null;" << nehContext->BuildId() << Endl;
            return false;
        }

        if (resp->IsError()) {
            reply.SetStatusMessage(resp->GetErrorText() + " for " + nehContext->BuildId());
            DEBUG_LOG << "action=recv_failed;message=" << resp->GetErrorText() << ";" << nehContext->BuildId() << Endl;
            return false;
        }

        return reply.ParseFromArray((void*)resp->Data.data(), resp->Data.size());
    }

};
