package dev.crucifixbeta.mod.modules.impl.render;

import com.mojang.blaze3d.systems.RenderSystem;
import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.ColorSetting;
import dev.crucifixbeta.mod.modules.settings.impl.EnumSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import java.awt.Color;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.BufferRenderer;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.render.VertexFormat.DrawMode;
import net.minecraft.resource.Resource;
import net.minecraft.util.Identifier;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL20;

@Environment(EnvType.CLIENT)
public class CustomSky extends Module {
   public static CustomSky INSTANCE;
   private final BooleanSetting replaceVanilla = this.add(new BooleanSetting("ReplaceVanilla", true));
   public final EnumSetting<CustomSky.SkyShader> mode = this.add(new EnumSetting<>("Mode", CustomSky.SkyShader.SkyBox));
   public final SliderSetting speed = this.add(new SliderSetting("Speed", 4.0, 0.0, 20.0, 0.1));
   public final ColorSetting color = this.add(new ColorSetting("Color", new Color(255, 255, 255, 255)));
   public final ColorSetting secondColor = this.add(new ColorSetting("SecondColor", new Color(255, 255, 255, 255)));
   public final SliderSetting step = this.add(new SliderSetting("Step", 0.5, 0.0, 4.0, 0.01));
   private int skyShaderProgram = -1;
   private long lastShaderLoad;

   public CustomSky() {
      super("SkyBox", "Render shader skybox.", Module.Category.Render);
      this.setChinese("\u5929\u7a7a\u76d2");
      INSTANCE = this;
   }

   @Override
   public String getInfo() {
      return this.mode.getValue().name();
   }

   @Override
   public void onToggle() {
      this.reloadLocalShader();
      CrucifixBeta.SHADER.reloadShaders();
   }

   @Override
   public void onLogin() {
      this.reloadLocalShader();
      CrucifixBeta.SHADER.reloadShaders();
   }

   public boolean shouldReplaceVanilla() {
      return this.isOn() && this.replaceVanilla.getValue();
   }

   public void renderSkybox(Matrix4f positionMatrix, float tickDelta) {
      if (this.isOn() && mc.world != null && mc.player != null) {
         this.renderShaderSky();
      }
   }

   private void renderShaderSky() {
      long var1 = System.currentTimeMillis();
      if (this.skyShaderProgram < 0 || var1 - this.lastShaderLoad > 5000L) {
         int var3 = this.loadShaderProgram();
         this.lastShaderLoad = var1;
         if (var3 >= 0) {
            if (this.skyShaderProgram >= 0) {
               GL20.glDeleteProgram(this.skyShaderProgram);
            }

            this.skyShaderProgram = var3;
         }
      }

      if (this.skyShaderProgram >= 0) {
         RenderSystem.enableBlend();
         RenderSystem.defaultBlendFunc();
         RenderSystem.depthMask(false);
         RenderSystem.disableCull();
         RenderSystem.disableDepthTest();
         GL20.glUseProgram(this.skyShaderProgram);
         this.setUniform2f("u_Resolution", (float)mc.getWindow().getFramebufferWidth(), (float)mc.getWindow().getFramebufferHeight());
         this.setUniform2f("u_Mouse", 0.5F, 0.0F);
         this.setUniform1f("u_Time", (float)(System.currentTimeMillis() % 1000000L) / 1000.0F * (this.speed.getValueFloat() / 4.0F));
         this.setUniform1f("u_Scale", this.step.getValueFloat());
         this.setUniform1i("u_Mode", this.mode.getValue().ordinal());
         this.setUniformColor("u_Color", this.color.getValue());
         this.setUniformColor("u_SecondColor", this.secondColor.getValue());
         this.drawShaderFullscreen();
         GL20.glUseProgram(0);
         RenderSystem.enableDepthTest();
         RenderSystem.enableCull();
         RenderSystem.depthMask(true);
         RenderSystem.disableBlend();
      }
   }

   private void setUniform1f(String name, float value) {
      int var3 = GL20.glGetUniformLocation(this.skyShaderProgram, name);
      if (var3 >= 0) {
         GL20.glUniform1f(var3, value);
      }
   }

   private void setUniform1i(String name, int value) {
      int var3 = GL20.glGetUniformLocation(this.skyShaderProgram, name);
      if (var3 >= 0) {
         GL20.glUniform1i(var3, value);
      }
   }

   private void setUniform2f(String name, float x, float y) {
      int var4 = GL20.glGetUniformLocation(this.skyShaderProgram, name);
      if (var4 >= 0) {
         GL20.glUniform2f(var4, x, y);
      }
   }

   private void setUniformColor(String name, Color c) {
      int var3 = GL20.glGetUniformLocation(this.skyShaderProgram, name);
      if (var3 >= 0) {
         GL20.glUniform4f(var3, (float)c.getRed() / 255.0F, (float)c.getGreen() / 255.0F, (float)c.getBlue() / 255.0F, (float)c.getAlpha() / 255.0F);
      }
   }

   private void drawShaderFullscreen() {
      Tessellator var1 = Tessellator.getInstance();
      BufferBuilder var2 = var1.begin(DrawMode.QUADS, VertexFormats.POSITION_TEXTURE);
      var2.vertex(-1.0F, -1.0F, 0.0F).texture(0.0F, 0.0F);
      var2.vertex(1.0F, -1.0F, 0.0F).texture(1.0F, 0.0F);
      var2.vertex(1.0F, 1.0F, 0.0F).texture(1.0F, 1.0F);
      var2.vertex(-1.0F, 1.0F, 0.0F).texture(0.0F, 1.0F);
      BufferRenderer.draw(var2.end());
   }

   private int loadShaderProgram() {
      try {
         Resource var1 = mc.getResourceManager().getResource(Identifier.of("alien", "shaders/sky.frag")).orElse(null);
         if (var1 == null) {
            return -1;
         } else {
            String var3;
            try (InputStream var2 = var1.getInputStream()) {
               var3 = new String(var2.readAllBytes(), StandardCharsets.UTF_8);
            }

            String var10 = "#version 330 core\nin vec3 Position;in vec2 UV0;out vec2 texCoord0;void main(){gl_Position=vec4(Position.xy,0.0,1.0);texCoord0=UV0;}";
            int var4 = this.compileShader(35633, var10, "Vertex");
            if (var4 < 0) {
               return -1;
            } else {
               int var5 = this.compileShader(35632, var3, "Fragment");
               if (var5 < 0) {
                  GL20.glDeleteShader(var4);
                  return -1;
               } else {
                  int var6 = GL20.glCreateProgram();
                  GL20.glAttachShader(var6, var4);
                  GL20.glAttachShader(var6, var5);
                  GL20.glLinkProgram(var6);
                  GL20.glDeleteShader(var4);
                  GL20.glDeleteShader(var5);
                  if (GL20.glGetProgrami(var6, 35714) == 0) {
                     System.out.println("[SkyBox] Shader link failed: " + GL20.glGetProgramInfoLog(var6));
                     GL20.glDeleteProgram(var6);
                     return -1;
                  } else {
                     return var6;
                  }
               }
            }
         }
      } catch (Exception var9) {
         var9.printStackTrace();
         return -1;
      }
   }

   private int compileShader(int type, String source, String label) {
      int var4 = GL20.glCreateShader(type);
      GL20.glShaderSource(var4, source);
      GL20.glCompileShader(var4);
      if (GL20.glGetShaderi(var4, 35713) == 0) {
         System.out.println("[SkyBox] " + label + " shader compile failed: " + GL20.glGetShaderInfoLog(var4));
         GL20.glDeleteShader(var4);
         return -1;
      } else {
         return var4;
      }
   }

   private void reloadLocalShader() {
      if (this.skyShaderProgram >= 0) {
         GL20.glDeleteProgram(this.skyShaderProgram);
         this.skyShaderProgram = -1;
      }

      this.lastShaderLoad = 0L;
   }
@Environment(EnvType.CLIENT)
   public static enum SkyShader {
      SkyBox,
      Meteor,
      Aurora,
      Nebula,
      Starfield,
      Galaxy;

}
}
