#pragma once

#include "async_coro_i.h"

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

#include <util/network/socket.h>
#include <util/memory/smallobj.h>

#include <functional>

class TCont;

namespace NSrvKernel::NDns {

class ICoroRequests;
class ICounters;
class IRequest;
class TAsyncWrapper;
class TAsyncCoro;

class TPollEvent final : public NCoro::IPollEvent
                       , public TIntrusiveListItem<TPollEvent>
                       , public TObjectFromPool<TPollEvent>
{
public:
    using PollCallback = std::function<void(SOCKET)>;

    TPollEvent(TContExecutor& e, SOCKET s, int what, PollCallback callback);
    TPollEvent(const TPollEvent&) = delete;
    TPollEvent(TPollEvent&&) = delete;
    TPollEvent& operator=(const TPollEvent&) = delete;
    TPollEvent& operator=(TPollEvent&&) = delete;
    ~TPollEvent() override;

    void OnPollEvent(int) noexcept override;

private:
    TContExecutor& Executor_;
    PollCallback Callback_;
};


class TAsyncCoro final : public IAsyncCoro {
    using EventHolder = THolder<TPollEvent>;

public:
    TAsyncCoro(TContExecutor& e, const TOptions& opts, ICounters& counters, const TDnsServer& server);
    TAsyncCoro(const TAsyncCoro&) = delete;
    TAsyncCoro(TAsyncCoro&&) = delete;
    TAsyncCoro& operator=(const TAsyncCoro&) = delete;
    TAsyncCoro& operator=(TAsyncCoro&&) = delete;
    ~TAsyncCoro() override;

    bool Resolve(const TString& host, int family, TInstant deadline, IEntry& result) noexcept override;

private:
    TCont* ResolveCont() noexcept;

    void StubForHttp2(TCont* c);
    void RunAsyncDns(TCont*) noexcept;

    // Handle notification about state change from socket in wrapper
    void OnStateChange(SOCKET s, bool read, bool write) noexcept;

private:
    TContExecutor& Executor_;
    TPollEvent::TPool Pool_;

    TIntrusiveList<TPollEvent> Events_;
    TSocketMap<EventHolder> Sockets_;

    THolder<ICoroRequests> Requests_;
    TCont* CoroAsyncDns_ = nullptr;
    THolder<TAsyncWrapper> AsyncDns_; // should be first to destroy
    ICounters& Counters_;
};

}