package net.vulkanmod.render.engine;

import com.mojang.blaze3d.opengl.GlStateManager;
import com.mojang.blaze3d.textures.AddressMode;
import com.mojang.blaze3d.textures.FilterMode;
import com.mojang.blaze3d.textures.GpuTexture;
import com.mojang.blaze3d.textures.TextureFormat;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.class_10868;
import net.vulkanmod.gl.VkGlTexture;
import net.vulkanmod.vulkan.texture.SamplerManager;
import net.vulkanmod.vulkan.texture.VulkanImage;
import org.jetbrains.annotations.Nullable;

@Environment(EnvType.CLIENT)
public class VkGpuTexture extends class_10868 {
   private static final Reference2ReferenceOpenHashMap<class_10868, VkGpuTexture> glToVkMap = new Reference2ReferenceOpenHashMap();
   protected VkGlTexture glTexture;
   protected final int id;
   private final Int2ReferenceMap<VkFbo> fboCache = new Int2ReferenceOpenHashMap();
   protected boolean closed;
   protected boolean modesDirty = true;
   boolean needsClear = false;
   int clearColor = 0;
   float depthClearValue = 1.0F;

   protected VkGpuTexture(int usage, String string, TextureFormat textureFormat, int width, int height, int layers, int mipLevel, int id, VkGlTexture glTexture) {
      super(usage, string, textureFormat, width, height, layers, mipLevel, id);
      this.id = id;
      this.glTexture = glTexture;
   }

   public void close() {
      if (!this.closed) {
         this.closed = true;
         GlStateManager._deleteTexture(this.id);
         ObjectIterator var1 = this.fboCache.values().iterator();

         while(var1.hasNext()) {
            VkFbo fbo = (VkFbo)var1.next();
            fbo.close();
         }
      }

   }

   public boolean isClosed() {
      return this.closed;
   }

   public void flushModeChanges() {
      if (this.modesDirty) {
         int maxLod = this.useMipmaps ? this.getMipLevels() - 1 : 0;
         int magFilterVk = this.magFilter == FilterMode.LINEAR ? 1 : 0;
         int minFilterVk = this.minFilter == FilterMode.LINEAR ? 1 : 0;
         int addressModeUVk = this.addressModeU == AddressMode.REPEAT ? 0 : 2;
         int addressModeVVk = this.addressModeV == AddressMode.REPEAT ? 0 : 2;
         long sampler = SamplerManager.getSampler(addressModeUVk, addressModeVVk, minFilterVk, magFilterVk, 1, (float)maxLod, false, 0.0F, -1);
         this.glTexture.getVulkanImage().setSampler(sampler);
         this.modesDirty = false;
      }

   }

   public int method_68427() {
      return this.id;
   }

   public void setAddressMode(AddressMode addressMode, AddressMode addressMode2) {
      super.setAddressMode(addressMode, addressMode2);
      this.modesDirty = true;
   }

   public void setTextureFilter(FilterMode filterMode, FilterMode filterMode2, boolean bl) {
      super.setTextureFilter(filterMode, filterMode2, bl);
      this.modesDirty = true;
   }

   public void setUseMipmaps(boolean bl) {
      super.setUseMipmaps(bl);
      this.modesDirty = true;
   }

   public void setClearColor(int clearColor) {
      this.needsClear = true;
      this.clearColor = clearColor;
   }

   public void setDepthClearValue(float depthClearValue) {
      this.needsClear = true;
      this.depthClearValue = depthClearValue;
   }

   public boolean needsClear() {
      return this.needsClear;
   }

   public VkFbo getFbo(@Nullable GpuTexture depthAttachment) {
      int depthAttachmentId = depthAttachment == null ? 0 : ((VkGpuTexture)depthAttachment).id;
      return (VkFbo)this.fboCache.computeIfAbsent(depthAttachmentId, (j) -> new VkFbo(this, (VkGpuTexture)depthAttachment));
   }

   public VulkanImage getVulkanImage() {
      return this.glTexture.getVulkanImage();
   }

   public static VkGpuTexture fromGlTexture(class_10868 glTexture) {
      return (VkGpuTexture)glToVkMap.computeIfAbsent(glTexture, (glTexture1) -> {
         String name = glTexture.getLabel();
         int id = glTexture.method_68427();
         VkGlTexture vglTexture = VkGlTexture.getTexture(id);
         VkGpuTexture gpuTexture = new VkGpuTexture(0, name, glTexture.getFormat(), glTexture.getWidth(0), glTexture.getHeight(0), 1, glTexture.getMipLevels(), glTexture.method_68427(), vglTexture);
         return gpuTexture;
      });
   }

   public static TextureFormat textureFormat(int format) {
      TextureFormat var10000;
      switch (format) {
         case 9:
            var10000 = TextureFormat.RED8;
            break;
         case 37:
         case 43:
         case 44:
            var10000 = TextureFormat.RGBA8;
            break;
         case 126:
            var10000 = TextureFormat.DEPTH32;
            break;
         default:
            var10000 = null;
      }

      return var10000;
   }

   public static int vkFormat(TextureFormat textureFormat) {
      byte var10000;
      switch (textureFormat) {
         case RGBA8 -> var10000 = 37;
         case RED8 -> var10000 = 9;
         case RED8I -> var10000 = 14;
         case DEPTH32 -> var10000 = 126;
         default -> throw new MatchException((String)null, (Throwable)null);
      }

      return var10000;
   }

   public static int vkImageViewType(int usage) {
      int viewType;
      if ((usage & 16) != 0) {
         viewType = 3;
      } else {
         viewType = 1;
      }

      return viewType;
   }
}
