#pragma once

#include "http2_stream.h"

#include <util/generic/hash.h>
#include <util/generic/intrlist.h>
#include <util/generic/noncopyable.h>
#include <util/generic/ptr.h>
#include <util/generic/vector.h>

#include <utility>

namespace NSrvKernel::NHTTP2 {

    class IConnection;

    // A simplification:
    //      we expect the idle list length (StreamsIdleMax) and closed list length (StreamsClosedMax)
    //      both to be bounded by a small constant (~10).
    class TStreamsManager : public TMoveOnly {
    public:
        using TStreamsMap = THashMap<ui32, TStream::TPtr, THash<ui32>, TEqualTo<ui32>>;
        using TSnapshot = TVector<TStream::TPtr>;

    public:
        explicit TStreamsManager(IConnection& conn, const TAuxServerSettings& settings) noexcept;

        ~TStreamsManager();

        void PrintTo(IOutputStream& out) const;

        [[nodiscard]] size_t GetOpenCount() const noexcept;

        [[nodiscard]] TStream::TPtr Find(ui32 streamId) noexcept;

        [[nodiscard]] TStream::TPtr FindOrCreateIdle(ui32 streamId) noexcept;

        [[nodiscard]] TStream::TPtr Open(ui32 streamId) noexcept;

        void Close(TStream& s) noexcept;

        // Returns an iterable snapshot with nonzero refcounted pointers to all the streams.
        [[nodiscard]] TSnapshot GetSnapshotOfRunning() noexcept;

    private:
        // Refresh streams referenced by other streams, update its queue accordingly
        void TouchStream(TStream::TPtr streamPtr) noexcept;

        void ShrinkAndPush(TIntrusiveList<TStream>& lru, const ui32 maxSize, TStream* newItem) noexcept;

        [[nodiscard]] TStream::TPtr DoFindOrCreate(ui32 streamId, ui32 maxStreamId) noexcept;

    private:
        IConnection& Conn_;
        TLogger& Logger_;
        TStreamsMap Streams_;
        TIntrusiveList<TStream> Idle_;
        TIntrusiveList<TStream> Closed_;
        TAuxServerSettings AuxServerSettings_;
    };
}
