package asm.mixins;

import com.mojang.blaze3d.systems.RenderSystem;
import dev.crucifixbeta.api.utils.render.ModelPlayer;
import dev.crucifixbeta.mod.modules.impl.render.Chams;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EndCrystalEntityRenderer;
import net.minecraft.client.render.entity.EnderDragonEntityRenderer;
import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.render.entity.EntityRendererFactory.Context;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.decoration.EndCrystalEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import org.joml.Quaternionf;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Environment(EnvType.CLIENT)
@Mixin({EndCrystalEntityRenderer.class})
public abstract class MixinEndCrystalEntityRenderer extends EntityRenderer<EndCrystalEntity> {
   @Mutable
   @Final
   @Shadow
   private static RenderLayer END_CRYSTAL;
   @Shadow
   @Final
   private static Identifier TEXTURE;
   @Unique
   private static final Identifier BLANK = Identifier.of("textures/blank.png");
   @Final
   @Shadow
   private static float SINE_45_DEGREES;
   @Final
   @Shadow
   private ModelPart core;
   @Final
   @Shadow
   private ModelPart frame;
   @Final
   @Shadow
   private ModelPart bottom;

   protected MixinEndCrystalEntityRenderer(Context ctx) {
      super(ctx);
   }

   @Unique
   private float yOffset(int age, float tickDelta, Chams module) {
      float var4 = ((float)age + tickDelta) * module.floatValue.getValueFloat();
      float var5 = MathHelper.sin(var4 * 0.2F) / 2.0F + 0.5F;
      var5 = (var5 * var5 + var5) * 0.4F * module.bounceHeight.getValueFloat();
      return var5 - 1.4F + module.floatOffset.getValueFloat();
   }

   @Inject(
      method = {"render(Lnet/minecraft/entity/decoration/EndCrystalEntity;FFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V"},
      at = {@At("HEAD")},
      cancellable = true
   )
   public void render(
      EndCrystalEntity endCrystalEntity, float f, float g, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci
   ) {
      Chams var8 = Chams.INSTANCE;
      if (var8 != null && var8.customCrystal()) {
         ci.cancel();
         int var9 = var8.spinSync.getValue() ? var8.age : endCrystalEntity.endCrystalAge;
         float var10 = this.yOffset(var9, g, var8);
         float var11 = ((float)var9 + g) * 3.0F * var8.spinValue.getValueFloat();
         matrixStack.push();
         if (var8.custom.getValue()) {
            if (var8.depth.getValue()) {
               RenderSystem.enableDepthTest();
            } else {
               RenderSystem.disableDepthTest();
            }

            RenderSystem.enableBlend();
            RenderSystem.setShader(GameRenderer::getPositionColorProgram);
            matrixStack.push();
            matrixStack.scale(2.0F * var8.scale.getValueFloat(), 2.0F * var8.scale.getValueFloat(), 2.0F * var8.scale.getValueFloat());
            matrixStack.translate(0.0F, -0.5F, 0.0F);
            matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(var11));
            matrixStack.translate(0.0F, 1.5F + var10 / 2.0F, 0.0F);
            matrixStack.multiply(new Quaternionf().setAngleAxis((float) (Math.PI / 3), SINE_45_DEGREES, 0.0F, SINE_45_DEGREES));
            if (var8.outerFrame.booleanValue) {
               ModelPlayer.render(matrixStack, this.frame, var8.fill, var8.line, 1.0, var8.chamsTexture.getValue());
            }

            matrixStack.scale(0.875F, 0.875F, 0.875F);
            matrixStack.multiply(new Quaternionf().setAngleAxis((float) (Math.PI / 3), SINE_45_DEGREES, 0.0F, SINE_45_DEGREES));
            matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(var11));
            if (var8.innerFrame.booleanValue) {
               ModelPlayer.render(matrixStack, this.frame, var8.fill, var8.line, 1.0, var8.chamsTexture.getValue());
            }

            matrixStack.scale(0.875F, 0.875F, 0.875F);
            matrixStack.multiply(new Quaternionf().setAngleAxis((float) (Math.PI / 3), SINE_45_DEGREES, 0.0F, SINE_45_DEGREES));
            matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(var11));
            if (var8.core.booleanValue) {
               ModelPlayer.render(matrixStack, this.core, var8.fill, var8.line, 1.0, var8.chamsTexture.getValue());
            }

            matrixStack.pop();
            RenderSystem.disableBlend();
            RenderSystem.disableDepthTest();
         }

         VertexConsumer var12 = ItemRenderer.getItemGlintConsumer(vertexConsumerProvider, END_CRYSTAL, false, var8.glint.getValue());
         matrixStack.push();
         matrixStack.scale(2.0F * var8.scale.getValueFloat(), 2.0F * var8.scale.getValueFloat(), 2.0F * var8.scale.getValueFloat());
         matrixStack.translate(0.0F, -0.5F, 0.0F);
         int var13 = OverlayTexture.DEFAULT_UV;
         if (endCrystalEntity.shouldShowBottom()) {
            this.bottom.render(matrixStack, var12, i, var13);
         }

         matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(var11));
         matrixStack.translate(0.0F, 1.5F + var10 / 2.0F, 0.0F);
         matrixStack.multiply(new Quaternionf().setAngleAxis((float) (Math.PI / 3), SINE_45_DEGREES, 0.0F, SINE_45_DEGREES));
         if (var8.outerFrame.booleanValue) {
            this.frame.render(matrixStack, var12, i, var13, var8.outerFrame.getValue().getRGB());
         }

         matrixStack.scale(0.875F, 0.875F, 0.875F);
         matrixStack.multiply(new Quaternionf().setAngleAxis((float) (Math.PI / 3), SINE_45_DEGREES, 0.0F, SINE_45_DEGREES));
         matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(var11));
         if (var8.innerFrame.booleanValue) {
            this.frame.render(matrixStack, var12, i, var13, var8.innerFrame.getValue().getRGB());
         }

         matrixStack.scale(0.875F, 0.875F, 0.875F);
         matrixStack.multiply(new Quaternionf().setAngleAxis((float) (Math.PI / 3), SINE_45_DEGREES, 0.0F, SINE_45_DEGREES));
         matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(var11));
         if (var8.core.booleanValue) {
            this.core.render(matrixStack, var12, i, var13, var8.core.getValue().getRGB());
         }

         matrixStack.pop();
         matrixStack.pop();
         BlockPos var14 = endCrystalEntity.getBeamTarget();
         if (var14 != null) {
            float var15 = (float)var14.getX() + 0.5F;
            float var16 = (float)var14.getY() + 0.5F;
            float var17 = (float)var14.getZ() + 0.5F;
            float var18 = (float)((double)var15 - endCrystalEntity.getX());
            float var19 = (float)((double)var16 - endCrystalEntity.getY());
            float var20 = (float)((double)var17 - endCrystalEntity.getZ());
            matrixStack.translate(var18, var19, var20);
            EnderDragonEntityRenderer.renderCrystalBeam(
               -var18, -var19 + var10, -var20, g, endCrystalEntity.endCrystalAge, matrixStack, vertexConsumerProvider, i
            );
         }

         super.render(endCrystalEntity, f, g, matrixStack, vertexConsumerProvider, i);
      }
   }
}
