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

import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkShaderModuleCreateInfo;
import static org.lwjgl.vulkan.VK13.vkCreateShaderModule;
import static org.lwjgl.vulkan.VK13.vkDestroyShaderModule;
import org.tinylog.Logger;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.nio.file.Files;


public class ShaderModule {
    private final long Handle;
    private final int ShaderStage;

    public ShaderModule(VulkanContext VkCtx, int ShaderStage, String ShaderSPVFile){
        try{
            byte[] Contents = Files.readAllBytes(new File(ShaderSPVFile).toPath());
            Handle = CreateShaderModule(VkCtx, Contents);
            this.ShaderStage = ShaderStage;
        } catch(IOException exception){
            Logger.error("Cannot Read Shader Files",exception);
            throw new RuntimeException(exception);
        }
    }

    private static long CreateShaderModule(VulkanContext VkCtx, byte[] Code){
        try(var MemStack = MemoryStack.stackPush()){
            ByteBuffer CodePointer = MemStack.malloc(Code.length).put(0,Code);
            var ShaderModuleCreateInfo = VkShaderModuleCreateInfo.calloc(MemStack)
                    .sType$Default()
                    .pCode(CodePointer);
            LongBuffer LongPoiner = MemStack.mallocLong(1);
            VulkanUtils.vkCheck(vkCreateShaderModule(VkCtx.GetDevice().FetchVulkanDevice(), ShaderModuleCreateInfo, null, LongPoiner),"Failed to create a new Shader Module");
            return LongPoiner.get(0);
        }
    }

    public void CleanUp(VulkanContext VkCtx){
        vkDestroyShaderModule(VkCtx.GetDevice().FetchVulkanDevice(), Handle, null);
    }

    public long GetHandle(){return Handle;}
    public int GetShaderStage(){return ShaderStage;}
}
