#pragma once

#include "hpack_definitions.h"

namespace NSrvKernel::NHTTP2 {

    template <ui8 FlagMask>
    [[nodiscard]]
    ui8 GetPrefixMask() noexcept {
        return (ui8)(~FlagMask & 0xFF);
    }

    template <ui8 FlagMask>
    [[nodiscard]]
    size_t GetEncodedIntSize(ui32 integer) noexcept {
        const ui8 prefixMask = GetPrefixMask<FlagMask>();
        return integer < prefixMask ? 1 : 2 + MostSignificantBit(integer - prefixMask) / 7;
    }

    TErrorOr<ui32> ReadIntSuffix(TInputRegion& input) noexcept;

    template <ui8 FlagMask>
    TErrorOr<ui32> ReadInt(TInputRegion& headerBlock) noexcept {
        Y_REQUIRE(headerBlock.SizeAvailable(),
            CompressionError(ECompressionError::HeaderBlockEnd));

        const ui8 prefixMask = GetPrefixMask<FlagMask>();
        ui32 value = (headerBlock[0] & prefixMask);
        headerBlock.Consume(1);

        if (value < prefixMask) {
            return value;
        } else {
            ui32 suffix = 0;
            Y_PROPAGATE_ERROR(ReadIntSuffix(headerBlock).AssignTo(suffix));
            return prefixMask + suffix;
        }
    }

    void WriteIntSuffix(ui32 value, ui32 length, TOutputRegion& output) noexcept;

    template <ui8 FlagMask, ui8 Flag>
    void WriteInt(ui32 value, TOutputRegion& buffer) noexcept {
        const ui8 prefixMask = GetPrefixMask<FlagMask>();
        const auto length = GetEncodedIntSize<FlagMask>(value);

        Y_VERIFY(value <= IMPL_HPACK_INT_SUFFIX_LIMIT + prefixMask);

        Y_VERIFY(buffer.SizeAvailable() >= length);

        const ui8 prefix = length > 1 ? prefixMask : value;
        buffer[0] = (prefix & prefixMask) | (Flag & FlagMask);
        buffer.Consume(1);

        if (length > 1) {
            WriteIntSuffix(value - prefix, length - 1, buffer);
        }
    }
}
