#pragma once

#include "admin_manager.h"

#include <balancer/kernel/cpu/cpu_limiter.h>
#include <balancer/kernel/module/conn_descr.h>
#include <balancer/kernel/module/iface.h>
#include <balancer/kernel/net/address.h>

#include <library/cpp/coroutine/engine/impl.h>
#include <library/cpp/coroutine/listener/listen.h>
#include <util/system/type_name.h>

using namespace NConfig;

namespace NSrvKernel::NProcessCore {
    using TAcceptFull = TContListener::ICallBack::TAcceptFull;

    class TBaseConnection {
    public:
        explicit TBaseConnection(const TAcceptFull& a);
        virtual ~TBaseConnection() = default;

        TCont* GetCont() noexcept;

        void Run(TCont* cont);
        virtual TError DoRun(TCont* cont) = 0;

    protected:
        TSocketHolder S_;
        const NAddr::TOpaqueAddr RemoteAddrOwner_;
        const NAddr::TOpaqueAddr LocalAddrOwner_;
        const TAddrHolder RemoteAddress_;
        const TAddrHolder LocalAddress_;
        TCont* C_ = nullptr;
    };

    class IConnectionCallback;
    class TMainTask;
    class TConnection : public TBaseConnection, public TIntrusiveListItem<TConnection> {
    public:
        class TPriorityIo;

    public:
        TConnection(IConnectionCallback* parent, const IModule& module, const TAcceptFull& a, TCpuLimiter* cpuLimiter);
        ~TConnection() override;

        void Acquire(IConnectionCallback* task) noexcept;
        void Release(IConnectionCallback* task) noexcept;
        void Cancel() noexcept;
        void OnConnIo() noexcept;

        TError DoRun(TCont* cont) override;

    private:
        IConnectionCallback* const Parent_ = nullptr;  // This is gonna become useless
        const IModule& Module_;
        TCpuLimiter* CpuLimiter_ = nullptr;
    };

    class TStatsCallback;
    class TStatsConnection : public TBaseConnection, public TIntrusiveListItem<TStatsConnection> {
    public:
        TStatsConnection(TStatsCallback* parent, const TAcceptFull& a, TSharedStatsManager& statsManager, TMasterProcess& masterProcess);
        ~TStatsConnection() override;

        void Acquire(TStatsCallback* cb) noexcept;
        void Release(TStatsCallback* cb) noexcept;
        void Cancel() noexcept;

        TError WriteResponse(TCont* cont, IIoInput* input, IIoOutput* output) noexcept;

        TError DoRun(TCont* cont) override;

    private:
        TSharedStatsManager& StatsManager_;
        TMasterProcess& MasterProcess_;
        TStatsCallback* Parent_ = nullptr;  // This is gonna become useless too
        TRegexp JsonRegexp_;
    };

    class TAdminCallback;
    class TAdminConnection : public TBaseConnection, public TIntrusiveListItem<TAdminConnection> {
    public:
        TAdminConnection(TAdminCallback* parent, const TAcceptFull& a, TAdminManager& adminManager);
        ~TAdminConnection() override;

        void Acquire(TAdminCallback* cb) noexcept;
        void Release(TAdminCallback* cb) noexcept;
        void Cancel() noexcept;

        TError DoRun(TCont* cont) override;

    private:
        TAdminManager& AdminManager_;
        TAdminCallback* Parent_ = nullptr;  // This is gonna become useless too
    };
}
