#pragma once

#include <library/cpp/bucket_quoter/bucket_quoter.h>

#include <util/generic/fwd.h>
#include <util/generic/ptr.h>
#include <util/thread/pool.h>

#include <functional>

#include <atomic>

namespace NRTYServer {
    class TNehSender;
}

namespace NRTYServer {
    class TMessage;
    class TReply;
}

namespace NSaas {
    class TAction;
}

namespace NFusion {

    using TActionPtr = TAtomicSharedPtr<NSaas::TAction>;
    struct TIndexingClientOptions;

    class TBaseIndexingClient: TNonCopyable {
    public:
        void Send(TActionPtr action, std::function<void(const NRTYServer::TReply&)> handler, bool useQuota = true) const;
        NRTYServer::TReply Send(TActionPtr action) const;

        void Shutdown();

        size_t GetQueueSize() const;
        size_t GetInFlight() const;
        void* CreateThreadSpecificResource() const;
        void DestroyThreadSpecificResource(void*) const;
        ~TBaseIndexingClient();

    protected:
        TBaseIndexingClient(const TString& scheme, const TString& host, ui16 port, const TIndexingClientOptions& options);

    protected:
        const TIndexingClientOptions& Options;
        mutable TThreadPoolBinder<TThreadPool, TBaseIndexingClient> Queue;
        THolder<NRTYServer::TNehSender> NehSender;

        mutable TBucketQuoter<int> Quota;
        mutable TAtomic LastMessageId;
        mutable TAtomic InFlight;
        std::atomic<bool> Active;
    };

    class TRemoteIndexingClient: public TBaseIndexingClient {
    public:
        TRemoteIndexingClient(const TString& host, ui16 port, const TIndexingClientOptions& options);
    };

    class TInternalIndexingClient : public TBaseIndexingClient {
    public:
        TInternalIndexingClient(ui16 port, const TIndexingClientOptions& options);
    };
}
