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

import com.mojang.blaze3d.systems.RenderSystem;
import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.utils.render.Render3DUtil;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.impl.player.AutoPearl;
import dev.crucifixbeta.mod.modules.settings.impl.ColorSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import java.awt.Color;
import java.util.Optional;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.Entity;
import net.minecraft.entity.projectile.ArrowEntity;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.entity.projectile.TridentEntity;
import net.minecraft.entity.projectile.thrown.EggEntity;
import net.minecraft.entity.projectile.thrown.EnderPearlEntity;
import net.minecraft.entity.projectile.thrown.ExperienceBottleEntity;
import net.minecraft.entity.projectile.thrown.PotionEntity;
import net.minecraft.entity.projectile.thrown.SnowballEntity;
import net.minecraft.item.BowItem;
import net.minecraft.item.CrossbowItem;
import net.minecraft.item.EggItem;
import net.minecraft.item.EnderPearlItem;
import net.minecraft.item.ExperienceBottleItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.LingeringPotionItem;
import net.minecraft.item.SnowballItem;
import net.minecraft.item.SplashPotionItem;
import net.minecraft.item.TridentItem;
import net.minecraft.registry.entry.RegistryEntry.Reference;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult.Type;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RaycastContext;
import net.minecraft.world.RaycastContext.FluidHandling;
import net.minecraft.world.RaycastContext.ShapeType;

@Environment(EnvType.CLIENT)
public class Trajectories extends Module {
   private static MatrixStack matrixStack;
   private final ColorSetting hand = this.add(new ColorSetting("Hand", new Color(255, 255, 255, 255)).injectBoolean(true));
   private final SliderSetting startDistance = this.add(new SliderSetting("Start Distance", 1.0, 0.0, 2.0, 0.05));
   private final ColorSetting pearl = this.add(new ColorSetting("Pearl", new Color(255, 255, 255, 255)).injectBoolean(true));
   private final ColorSetting arrow = this.add(new ColorSetting("Arrow", new Color(255, 255, 255, 255)).injectBoolean(true));
   private final ColorSetting xp = this.add(new ColorSetting("XP Bottle", new Color(255, 255, 255, 255)).injectBoolean(true));
   private final ColorSetting snowball = this.add(new ColorSetting("Snowball", new Color(255, 255, 255, 255)).injectBoolean(false));
   private final ColorSetting egg = this.add(new ColorSetting("Egg", new Color(255, 255, 255, 255)).injectBoolean(false));
   private final ColorSetting potion = this.add(new ColorSetting("Potion", new Color(255, 255, 255, 255)).injectBoolean(false));
   private final ColorSetting trident = this.add(new ColorSetting("Trident", new Color(255, 255, 255, 255)).injectBoolean(false));
   private final SliderSetting boxSize = this.add(new SliderSetting("Box Size", 0.3, 0.1, 1.0, 0.05));

   public Trajectories() {
      super("Trajectories", Module.Category.Render);
      this.setChinese("\u6295\u63b7\u7269\u8f68\u8ff9\u9884\u6d4b");
   }

   @Override
   public void onRender3D(MatrixStack stack) {
      if (!nullCheck()) {
         matrixStack = stack;
         RenderSystem.disableDepthTest();

         for (Entity var3 : CrucifixBeta.THREAD.getEntities()) {
            Color var4 = this.getEntityColor(var3);
            if (var4 != null) {
               this.calcTrajectory(var3, var4);
            }
         }

         if (this.hand.booleanValue && mc.options.getPerspective().isFirstPerson()) {
            ItemStack var14 = mc.player.getMainHandStack();
            ItemStack var15 = mc.player.getOffHandStack();
            Item var16 = null;
            Hand var5 = null;
            if (this.isThrowable(var14.getItem()) || var14.getItem() instanceof BowItem || var14.getItem() instanceof CrossbowItem || AutoPearl.INSTANCE.isOn()
               )
             {
               var16 = var14.getItem();
               var5 = Hand.MAIN_HAND;
            } else if (this.isThrowable(var15.getItem()) || var15.getItem() instanceof BowItem || var15.getItem() instanceof CrossbowItem) {
               var16 = var15.getItem();
               var5 = Hand.OFF_HAND;
            }

            if (var16 != null) {
               boolean var6 = mc.options.getBobView().getValue();
               mc.options.getBobView().setValue(false);
               double var7 = mc.player.getX();
               double var9 = mc.player.getEyeY();
               double var11 = mc.player.getZ();
               boolean var13 = var5 == Hand.MAIN_HAND && this.hasMultishot(var14) || var5 == Hand.OFF_HAND && this.hasMultishot(var15);
               if (var13 && var16 instanceof CrossbowItem) {
                  this.calcPreview(var16, mc.player.getYaw() - 10.0F, var7, var9, var11, this.hand.getValue());
                  this.calcPreview(var16, mc.player.getYaw(), var7, var9, var11, this.hand.getValue());
                  this.calcPreview(var16, mc.player.getYaw() + 10.0F, var7, var9, var11, this.hand.getValue());
               } else {
                  this.calcPreview(var16, mc.player.getYaw(), var7, var9, var11, this.hand.getValue());
               }

               mc.options.getBobView().setValue(var6);
            }
         }

         RenderSystem.enableDepthTest();
      }
   }

   private Color getEntityColor(Entity e) {
      if (e instanceof EnderPearlEntity && this.pearl.booleanValue) {
         return this.pearl.getValue();
      } else if (e instanceof ArrowEntity && this.arrow.booleanValue) {
         return this.arrow.getValue();
      } else if (e instanceof ExperienceBottleEntity && this.xp.booleanValue) {
         return this.xp.getValue();
      } else if (e instanceof SnowballEntity && this.snowball.booleanValue) {
         return this.snowball.getValue();
      } else if (e instanceof EggEntity && this.egg.booleanValue) {
         return this.egg.getValue();
      } else if (e instanceof PotionEntity && this.potion.booleanValue) {
         return this.potion.getValue();
      } else {
         return e instanceof TridentEntity && this.trident.booleanValue ? this.trident.getValue() : null;
      }
   }

   private void drawHitBox(Vec3d pos, Color color) {
      double var3 = this.boxSize.getValue();
      Box var5 = new Box(pos.x - var3 / 2.0, pos.y - var3 / 2.0, pos.z - var3 / 2.0, pos.x + var3 / 2.0, pos.y + var3 / 2.0, pos.z + var3 / 2.0);
      Render3DUtil.drawBox(matrixStack, var5, color);
   }

   private void calcTrajectory(Entity e, Color color) {
      Vec3d var3 = e.getVelocity();
      double var4 = var3.x;
      double var6 = var3.y;
      double var8 = var3.z;
      if (var4 != 0.0 || var6 != 0.0 || var8 != 0.0) {
         double var10 = e.getX();
         double var12 = e.getY();
         double var14 = e.getZ();
         double var16 = !(e instanceof ArrowEntity) && !(e instanceof TridentEntity) ? 0.03 : 0.05;
         short var18 = 300;

         for (int var19 = 0; var19 < var18; var19++) {
            Vec3d var20 = new Vec3d(var10, var12, var14);
            var10 += var4;
            var12 += var6;
            var14 += var8;
            if (mc.world.getBlockState(new BlockPos((int)var10, (int)var12, (int)var14)).getBlock() == Blocks.WATER) {
               var4 *= 0.8;
               var6 *= 0.8;
               var8 *= 0.8;
            } else {
               var4 *= 0.99;
               var6 *= 0.99;
               var8 *= 0.99;
            }

            var6 -= var16;
            Vec3d var21 = new Vec3d(var10, var12, var14);
            Vec3d var22 = null;

            for (Entity var24 : mc.world.getEntities()) {
               if (var24 != e && !(var24 instanceof ProjectileEntity)) {
                  Optional var25 = var24.getBoundingBox().raycast(var20, var21);
                  if (var25.isPresent()) {
                     var22 = (Vec3d)var25.get();
                     break;
                  }
               }
            }

            if (var22 != null) {
               Render3DUtil.drawLine(var20, var22, color);
               this.drawHitBox(var22, color);
               break;
            }

            BlockHitResult var27 = mc.world.raycast(new RaycastContext(var20, var21, ShapeType.OUTLINE, FluidHandling.NONE, mc.player));
            if (var27 != null && var27.getType() == Type.BLOCK) {
               Render3DUtil.drawLine(var20, var27.getPos(), color);
               this.drawHitBox(var27.getPos(), color);
               break;
            }

            if (var12 <= -65.0) {
               break;
            }

            Render3DUtil.drawLine(var20, var21, color);
         }
      }
   }

   private void calcPreview(Item item, float yaw, double x, double y, double z, Color color) {
      float var10 = this.getDistance(item);
      float var11 = mc.player.getPitch();
      double var12 = (double)(
         -MathHelper.sin(yaw / 180.0F * (float) Math.PI) * MathHelper.cos((var11 - (float)this.getThrowPitch(item)) / 180.0F * (float) Math.PI) * var10
      );
      double var14 = (double)(-MathHelper.sin((var11 - (float)this.getThrowPitch(item)) / 180.0F * (float) Math.PI) * var10);
      double var16 = (double)(
         MathHelper.cos(yaw / 180.0F * (float) Math.PI) * MathHelper.cos((var11 - (float)this.getThrowPitch(item)) / 180.0F * (float) Math.PI) * var10
      );
      float var18 = (float)mc.player.getItemUseTime() / 20.0F;
      var18 = (var18 * var18 + var18 * 2.0F) / 3.0F;
      if (var18 > 1.0F) {
         var18 = 1.0F;
      }

      float var19 = MathHelper.sqrt((float)(var12 * var12 + var14 * var14 + var16 * var16));
      var12 /= (double)var19;
      var14 /= (double)var19;
      var16 /= (double)var19;
      float var20 = (item instanceof BowItem ? var18 * 2.0F : (item instanceof CrossbowItem ? 2.2F : 1.0F)) * this.getThrowVelocity(item);
      var12 *= (double)var20;
      var14 *= (double)var20;
      var16 *= (double)var20;
      var12 += mc.player.getVelocity().x;
      var14 += mc.player.getVelocity().y;
      var16 += mc.player.getVelocity().z;
      double var21;
      if (!(item instanceof BowItem) && !(item instanceof CrossbowItem)) {
         var21 = 0.03;
      } else {
         var21 = 0.05;
      }

      short var23 = 300;
      Vec3d var24 = new Vec3d(x, y, z);
      double var25 = this.startDistance.getValue();
      double var27 = 0.0;
      Vec3d var29 = var24;
      boolean var30 = false;
      Vec3d var31 = null;

      for (int var32 = 0; var32 < var23; var32++) {
         double var33 = x + var12;
         double var35 = y + var14;
         double var37 = z + var16;
         Vec3d var39 = new Vec3d(var33, var35, var37);
         if (mc.world.getBlockState(new BlockPos((int)var33, (int)var35, (int)var37)).getBlock() == Blocks.WATER) {
            var12 *= 0.8;
            var14 *= 0.8;
            var16 *= 0.8;
         } else {
            var12 *= 0.99;
            var14 *= 0.99;
            var16 *= 0.99;
         }

         var14 -= var21;
         double var40 = var29.distanceTo(var39);
         var27 += var40;
         Vec3d var42 = null;

         for (Entity var44 : mc.world.getEntities()) {
            if (var44 != mc.player && !(var44 instanceof ProjectileEntity)) {
               Optional var45 = var44.getBoundingBox().raycast(var29, var39);
               if (var45.isPresent()) {
                  var42 = (Vec3d)var45.get();
                  break;
               }
            }
         }

         BlockHitResult var60 = null;
         if (var42 == null) {
            var60 = mc.world.raycast(new RaycastContext(var29, var39, ShapeType.OUTLINE, FluidHandling.NONE, mc.player));
            if (var60 != null && var60.getType() == Type.BLOCK) {
               var42 = var60.getPos();
            }
         }

         if (var42 != null) {
            double var46 = var27 - var40 + var29.distanceTo(var42);
            if (var46 >= var25) {
               if (!var30) {
                  Vec3d var48 = this.getPointAtDistance(var24, var29, var39, var27 - var40, var25);
                  if (var48 != null) {
                     Render3DUtil.drawLine(var48, var42, color);
                     this.drawHitBox(var42, color);
                  }
               } else {
                  Render3DUtil.drawLine(var31 != null ? var31 : var29, var42, color);
                  this.drawHitBox(var42, color);
               }
            } else {
               this.drawHitBox(var42, color);
            }
            break;
         }

         if (var27 >= var25) {
            if (!var30) {
               Vec3d var62 = this.getPointAtDistance(var24, var29, var39, var27 - var40, var25);
               if (var62 != null) {
                  Render3DUtil.drawLine(var62, var39, color);
                  var31 = var39;
               }

               var30 = true;
            } else {
               Render3DUtil.drawLine(var29, var39, color);
               var31 = var39;
            }
         }

         x = var33;
         y = var35;
         z = var37;
         var29 = var39;
         if (var35 <= -65.0) {
            break;
         }
      }
   }

   private Vec3d getPointAtDistance(Vec3d origin, Vec3d p1, Vec3d p2, double distToP1, double targetDist) {
      double var8 = targetDist - distToP1;
      if (!(var8 < 0.0) && !(var8 > p1.distanceTo(p2))) {
         Vec3d var10 = p2.subtract(p1).normalize();
         return p1.add(var10.multiply(var8));
      } else {
         return null;
      }
   }

   private boolean isThrowable(Item item) {
      return item instanceof EnderPearlItem
         || item instanceof TridentItem
         || item instanceof ExperienceBottleItem
         || item instanceof SnowballItem
         || item instanceof EggItem
         || item instanceof SplashPotionItem
         || item instanceof LingeringPotionItem;
   }

   private float getDistance(Item item) {
      return item instanceof BowItem ? 1.0F : 0.4F;
   }

   private float getThrowVelocity(Item item) {
      if (item instanceof SplashPotionItem || item instanceof LingeringPotionItem) {
         return 0.5F;
      } else if (item instanceof ExperienceBottleItem) {
         return 0.59F;
      } else {
         return item instanceof TridentItem ? 2.0F : 1.5F;
      }
   }

   private int getThrowPitch(Item item) {
      return !(item instanceof SplashPotionItem) && !(item instanceof LingeringPotionItem) && !(item instanceof ExperienceBottleItem) ? 0 : 20;
   }

   private boolean hasMultishot(ItemStack stack) {
      if (!(stack.getItem() instanceof CrossbowItem)) {
         return false;
      } else {
         Reference var2 = mc.world.getRegistryManager().get(Enchantments.MULTISHOT.getRegistryRef()).getEntry(Enchantments.MULTISHOT).get();
         return EnchantmentHelper.getLevel(var2, stack) != 0;
      }
   }
}
