#ifndef BLOCK_TINT_MANAGER_HPP_
#define BLOCK_TINT_MANAGER_HPP_

#include <HostVisibleVector/HostVisibleVector.hpp>
#include <Vk/CommandBuffer/CommandBuffer.hpp>
#include <Vk/DescriptorSet/DescriptorSet.hpp>
#include <Vk/ShaderConst.hpp>

class FrameDrawer;

/**
 * @brief Manages the hash table of block tints.
 */
class BlockTintManager final
{
private:
    FrameDrawer &frameDrawer;

    /**
     * @brief A hash table node which we send to the GPU.
     * 
     * Bit 31 (GLSL_TINT_TABLE_NODE_RESOLVED) is set if an entry points to a BlockTint;
     * the remaining bits are then the index into the block tint table.
     *
     * If the bit is clear, then the remaining bits are an index into the hash node table;
     * if that index is zero, it means the entry is empty.
     */
    struct HashTableNode
    {
        uint32_t entries[GLSL_TINT_TABLE_NODE_SIZE];
    };

    /**
     * @brief Entries in the tint table referenced by the hash table.
     * 
     * X, Y, Z are the coordinates of the tinted block in world space, and W is the XYZW
     * encoded tint.
     */
    struct TintEntry
    {
        glm::uvec4 blockPosAndTint;
    };

    HostVisibleVector<HashTableNode> hashTableNodes;
    HostVisibleVector<TintEntry> tintTable;
    std::shared_ptr<Vk::DescriptorPool> tintDescriptorPool;

    static uint32_t posHash(const glm::ivec3 &blockPos, uint32_t depth);

    uint32_t createHashNode();

public:
    BlockTintManager(FrameDrawer &frameDrawer);

    /**
     * @brief Set the tint at the specified block position.
     * 
     * @param blockPos The block to tint.
     * @param tint The tint color (alpha is ignored).
     */
    void setTintAt(const glm::ivec3 &blockPos, const glm::vec4 &tint);

    std::shared_ptr<Vk::DescriptorSet> getDescSet();
};

#endif