package net.halbear.Terrain4J.EngineCore.Logic.Rendering;

import net.halbear.Terrain4J.EngineCore.Display.Window;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PipelineCache;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorAllocator;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.PhysicalDevice;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.Surface;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.SwapChain;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.VulkanInstance;
import org.tinylog.Logger;

public class VulkanContext {
    public static int VulkanLayersOpen = 0;
    private final VulkanInstance Instance;
    private final Device device;
    private Surface surface;
    private final PhysicalDevice PhysDevice;
    private SwapChain swapChain;
    private final PipelineCache VkPipelineCache;
    private final DescriptorAllocator descriptorAllocator;

    public VulkanContext(Window window){
        var EngineGlobals = EngineConfig.getInstance();
        Instance = new VulkanInstance(EngineGlobals.VkValidated());
        PhysDevice =  PhysicalDevice.createPhysicalDevice(Instance,EngineGlobals.GetPhysicalDeviceName());
        device = new Device(PhysDevice);
        surface = new Surface(Instance, PhysDevice, window);
        swapChain = new SwapChain(window, device, surface, EngineGlobals.GetRequestedImages(), EngineGlobals.GetVSYNC());
        VulkanLayersOpen+=5;
        VkPipelineCache = new PipelineCache(device);
        descriptorAllocator = new DescriptorAllocator(PhysDevice, device);
    }
    public void Resize(Window window){
        swapChain.cleanup(device);
        surface.cleanup(Instance);
        var EngCfg = EngineConfig.getInstance();
        surface = new Surface(Instance,PhysDevice,window);
        swapChain = new SwapChain(window, device, surface, EngCfg.GetRequestedImages(),EngCfg.GetVSYNC());
    }
    public void cleanup(){
        descriptorAllocator.CleanUp(device);
        swapChain.cleanup(device);
        surface.cleanup(Instance);
        VkPipelineCache.CleanUp(device);
        device.cleanup();
        PhysDevice.cleanup();
        Instance.cleanup();
        Logger.debug("Render Thread Finished ending Vulkan Processes\nVulkan Layers Open:[{}]", VulkanContext.VulkanLayersOpen < 0 ? "All processes closed and vulkan instance removed" : VulkanContext.VulkanLayersOpen);
        VulkanLayersOpen--;
    }
    public PipelineCache GetVkPipelineCache(){return VkPipelineCache;}
    public SwapChain GetSwapChain(){return swapChain;}
    public Device GetDevice(){
        return device;
    }
    public PhysicalDevice GetPhysicalDevice(){
        return PhysDevice;
    }
    public Surface GetSurface(){
        return surface;
    }
    public DescriptorAllocator GetDescriptorAllocator(){return descriptorAllocator;}
}
