#pragma once

#include "http2_frame.h"

#include <balancer/kernel/http2/server/common/http2_common.h>
#include <balancer/kernel/http2/server/utils/http2_queue.h>
#include <balancer/kernel/http/parser/headers.h>
#include <balancer/kernel/module/iface.h>
#include <balancer/kernel/memory/chunks.h>

#include <util/generic/noncopyable.h>
#include <util/generic/ptr.h>


namespace NSrvKernel::NHTTP2 {
    class TStats;
    class TLogger;
    class TConnOutput;
    class TClientSettings;
    class TServerSettings;
    class TAuxServerSettings;
    class TPrioTreeNode;
    class TEdgePrioFix;

    enum class EErrorSource {
        BeforePreface,
        RecvFrame,
        SendFrames,
        Other,
    };

    // TStreamId =======================================================================================================

    class TStreamId {
    public:
        explicit TStreamId(ui32 streamId) noexcept
            : StreamId_(streamId)
        {}

        void PrintTo(IOutputStream& out) const;

        [[nodiscard]] ui32 GetStreamId() const noexcept {
            return StreamId_;
        }

    protected:
        const ui32 StreamId_;
    };


    // TODO (velavokr): devirtualize these as a final optimization
    // IStreamOutput ===================================================================================================

    class IStreamOutput : public TStreamId {
    public:
        using TStreamId::TStreamId;
        using TPrioHandle = TQueueItem<IStreamOutput>;

        [[nodiscard]] virtual const TPrioTreeNode& GetPrioTreeNode() const noexcept = 0;

        virtual TErrorOr<TData> DequeueNextDataFrame(ui32 frameSize) noexcept = 0;

        virtual void OnConnOutputClose() noexcept = 0;

        virtual void OnConnFlowBlockedForever() noexcept = 0;
    };


    // IConnection =====================================================================================================

    class TStream;

    class IConnection {
    public:
        virtual ~IConnection() = default;


        virtual void OnConnReset(TError err, EErrorSource dir) noexcept = 0;

        virtual void OnConnInternalError(TError err) noexcept = 0;

        virtual void OnConnError(EErrorCode errorCode, TStringBuf debugData, TConnErrorReason reason) noexcept = 0;

        [[nodiscard]] virtual bool IsConnError() const noexcept = 0;

        virtual TError OnHTTP(const TConnDescr&) const = 0;

        virtual void DisposeStream(TStream&) noexcept = 0;

        [[nodiscard]] virtual TConnOutput& GetClientOutput() noexcept = 0;

        [[nodiscard]] virtual TPrioTreeNode& GetPrioTreeRoot() noexcept = 0;

        [[nodiscard]] virtual TEdgePrioFix& GetEdgePrioFix() noexcept = 0;


        [[nodiscard]] virtual const TClientSettings& GetClientSettings() const noexcept = 0;

        [[nodiscard]] virtual const TServerSettings& GetServerSettings() const noexcept = 0;

        [[nodiscard]] virtual const TAuxServerSettings& GetAuxServerSettings() const noexcept = 0;

        [[nodiscard]] virtual ui32 GetMaxClientStreamId() const noexcept = 0;


        [[nodiscard]] virtual const TConnDescr& GetMainDescr() const noexcept = 0;

        [[nodiscard]] virtual TCont& GetMainCont() noexcept = 0;

        [[nodiscard]] virtual TContExecutor& GetExecutor() noexcept = 0;


        [[nodiscard]] virtual TStats& GetStats() noexcept = 0;

        [[nodiscard]] virtual TLogger& GetLogger() noexcept = 0;

        [[nodiscard]] virtual TSocketIo* GetSocketIo() noexcept = 0;
    };
}
