#pragma once

#include <balancer/kernel/http2/server/common/http2_common.h>

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

namespace NSrvKernel::NHTTP2 {

    class IPrioCallback {
    public:
        virtual ~IPrioCallback() {}
    };

    class TPrioTreeNode : private TIntrusiveListItem<TPrioTreeNode>, TNonCopyable {
        friend class TIntrusiveList<TPrioTreeNode>;
        friend class TIntrusiveListItem<TPrioTreeNode>;

    public:
        TPrioTreeNode() noexcept = default;

        explicit TPrioTreeNode(TPrioTreeNode& root, ui32 streamId) noexcept;

        ~TPrioTreeNode();

        void PrintTo(IOutputStream& out) const;

        [[nodiscard]] double GetRelWeight() const noexcept {
            return RelWeight_;
        }

        [[nodiscard]] ui32 GetDepth() const noexcept {
            return Depth_;
        }

        const TPrioTreeNode* GetParent() const noexcept {
            return Parent_;
        }

        const TIntrusiveList<TPrioTreeNode>& GetChildren() const noexcept {
            return Children_;
        }

        [[nodiscard]] bool UpdatePrio(TPrioTreeNode& newParent, ui8 newRawWeight, bool exclusive) noexcept;

    private:
        void UpdateWeight() noexcept;

        void UpdateAllWeights() noexcept;

        [[nodiscard]] bool CycleFormed(TPrioTreeNode& parent) noexcept;

        [[nodiscard]] static double AsRelWeight(ui32 rawWeight) noexcept;

    private:
        TPrioTreeNode* Parent_ = nullptr;
        TIntrusiveList<TPrioTreeNode> Children_;
        ui32 StreamId_ = 0u;
        ui32 Depth_ = 0u;
        ui32 RawWeight_ = RFC_PRIO_RAW_WEIGHT_MAX;
        double RelWeight_ = AsRelWeight(RawWeight_);
    };
}
