#include <Vk/DescriptorPool/DescriptorPool.hpp>
#include <Utilities/Utilities.hpp>

Vk::DescriptorPool::Builder& Vk::DescriptorPool::Builder::addDescriptorType(VkDescriptorType type, uint32_t count)
{
    VkDescriptorPoolSize poolSize{};
    poolSize.type = type;
    poolSize.descriptorCount = count;

    m_poolSizes.push_back(poolSize);
    return *this;
}

std::shared_ptr<Vk::DescriptorPool> Vk::DescriptorPool::Builder::build(std::shared_ptr<Vk::Device> device, uint32_t maxSets)
{
    VkDescriptorPoolCreateInfo poolInfo{};
    poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
    poolInfo.poolSizeCount = m_poolSizes.size();
    poolInfo.pPoolSizes = m_poolSizes.data();
    poolInfo.maxSets = maxSets;
    poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;

    VkDescriptorPool pool;
    if (vkCreateDescriptorPool(device->inner(), &poolInfo, nullptr, &pool) != VK_SUCCESS)
    {
        crash("Failed to create descriptor pool!");
    }

    return std::make_shared<Vk::DescriptorPool>(device, pool);
}

Vk::DescriptorPool::DescriptorPool(
    std::shared_ptr<Vk::Device> device,
    VkDescriptorType descriptorType,
    uint32_t descriptorCount,
    uint32_t maxSets
) : m_device(device)
{
    VkDescriptorPoolSize poolSize{};
    poolSize.type = descriptorType;
    poolSize.descriptorCount = descriptorCount;

    VkDescriptorPoolCreateInfo poolInfo{};
    poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
    poolInfo.poolSizeCount = 1;
    poolInfo.pPoolSizes = &poolSize;
    poolInfo.maxSets = maxSets;
    poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;

    if (vkCreateDescriptorPool(device->inner(), &poolInfo, nullptr, &m_descriptorPool) != VK_SUCCESS)
    {
        crash("Failed to create descriptor pool!");
    }
}

Vk::DescriptorPool::DescriptorPool(
    std::shared_ptr<Vk::Device> device,
    VkDescriptorPool pool
) : m_device(device), m_descriptorPool(pool) {}

Vk::DescriptorPool::~DescriptorPool()
{
    vkDestroyDescriptorPool(m_device->inner(), m_descriptorPool, nullptr);
}

VkDescriptorPool Vk::DescriptorPool::inner()
{
    return m_descriptorPool;
}