#pragma once

#include <library/cpp/neh/neh.h>
#include <library/cpp/neh/factory.h>

namespace NRTYServer {

    struct TQueryInfo {
        TStringBuf Host;
        ui16 Port = 0;
        TStringBuf Addr;
        TDuration Duration;
        ui16 Attempts = 0;
        bool SendComplete;
    };

    class IHandleListener {
    public:
        typedef TAtomicSharedPtr<IHandleListener> TPtr;

        virtual ~IHandleListener() {}
        virtual void OnStart(const TQueryInfo& info) const = 0;
        virtual void OnNotify(const TQueryInfo& info, NNeh::TResponseRef& ref) const = 0;
        virtual bool OnResend(const TQueryInfo& info, TString& newAdrr, const NNeh::TMessage& msg, const NNeh::TResponse* resp) const;
        virtual bool ReplyIsOk(const TQueryInfo& info, const NNeh::TResponse& rep) const;
        virtual void OnCancel(const TQueryInfo& info, const TString& reason) const = 0;
        virtual TDuration GetRecvTimeout() const = 0;
    };

    class TMultiRequesterBase {
    public:
        class TRequestData : public TAtomicRefCount<TRequestData> {
        public:
            virtual ~TRequestData() = default;
            using TPtr = TIntrusivePtr<TRequestData>;
        };

        using TResendDurations = TVector<TDuration>;

    public:
        TMultiRequesterBase(ui32 attemptsCount, const TResendDurations& resendDurations = TResendDurations(), const TString& threadName = "NehMultiReq");
        ~TMultiRequesterBase();

        ui32 QueueSize() const;
        ui32 SendQueueSize() const;
        void Start(ui32 threadsNum);
        void Stop(bool wait = false);

        //request data will be destroed when request will be fully processed;
        void Send(const NNeh::TMessage& message, const IHandleListener* handleCallback, TRequestData::TPtr requestData);
        void Send(NNeh::TMessage&& message, const IHandleListener* handleCallback, TRequestData::TPtr requestData);
    private:
        class TImpl;
        THolder<TImpl> Impl_;
    };

    class TMultiRequester : public TMultiRequesterBase {
    public:
        TMultiRequester(ui32 attemptsCount, NNeh::IProtocol* protocol, const TResendDurations& resendDurations = TResendDurations(), const TString& threadName = "NehMultiReq");
        void Send(const TString& host, ui16 port, NNeh::TMessage& message, const IHandleListener* handleCallback);
    private:
        TString ProtocolScheme;
    };

};
