package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;

import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkDescriptorSetLayoutBinding;
import org.lwjgl.vulkan.VkDescriptorSetLayoutCreateInfo;
import org.tinylog.Logger;

import java.nio.LongBuffer;

import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck;
import static org.lwjgl.vulkan.VK10.vkCreateDescriptorSetLayout;
import static org.lwjgl.vulkan.VK10.vkDestroyDescriptorSetLayout;

public class DescriptorSetLayout {
    private final LayoutInformation[] LayoutInfos;
    protected long VkDescriptorLayout;
    public DescriptorSetLayout(VulkanContext VkCtx, LayoutInformation LayoutInfo){
        this(VkCtx, new DescriptorSetLayout.LayoutInformation[]{LayoutInfo});
    }
    public DescriptorSetLayout(VulkanContext VkCtx, LayoutInformation[] LayoutInfos){
        this.LayoutInfos = LayoutInfos;
        try(var MemStack = MemoryStack.stackPush()){
            int LayoutCount = LayoutInfos.length;
            var LayoutBindings = VkDescriptorSetLayoutBinding.calloc(LayoutCount,MemStack);
            for(int i = 0; i < LayoutCount; i++){
                LayoutInformation LayoutInfo = LayoutInfos[i];
                LayoutBindings.get(i)
                        .binding(LayoutInfo.Binding())
                        .descriptorType(LayoutInfo.DescriptorType())
                        .descriptorCount(LayoutInfo.DescriptorCount())
                        .stageFlags(LayoutInfo.Stage());
            }
            var VkLayoutInfo = VkDescriptorSetLayoutCreateInfo.calloc(MemStack)
                    .sType$Default()
                    .pBindings(LayoutBindings);
            LongBuffer SetLayoutPointer = MemStack.mallocLong(1);
            vkCheck(vkCreateDescriptorSetLayout(VkCtx.GetDevice().FetchVulkanDevice(), VkLayoutInfo,null,SetLayoutPointer),
            "Failed to create Descriptor Set Layout");
            VkDescriptorLayout = SetLayoutPointer.get(0);
        }
    }

    public LayoutInformation GetLayoutInfo(){return GetLayoutInfos()[0];}
    public LayoutInformation[] GetLayoutInfos(){return LayoutInfos;}
    public long GetVkDescriptorLayout(){return VkDescriptorLayout;}
    public void CleanUp(VulkanContext VkCtx){
        Logger.debug("Destroying Descriptor Set Layout");
        vkDestroyDescriptorSetLayout(VkCtx.GetDevice().FetchVulkanDevice(),VkDescriptorLayout,null);
    }

    public record LayoutInformation(int DescriptorType, int Binding, int DescriptorCount, int Stage){}
}
