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

import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.utils.math.Easing;
import dev.crucifixbeta.api.utils.player.InventoryUtil;
import dev.crucifixbeta.api.utils.render.ColorUtil;
import dev.crucifixbeta.api.utils.render.Render3DUtil;
import dev.crucifixbeta.core.impl.BreakManager;
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.text.DecimalFormat;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.BlockState;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.AirBlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;

@Environment(EnvType.CLIENT)
public class BreakESP extends Module {
   public static BreakESP INSTANCE;
   private final BooleanSetting progress = this.add(new BooleanSetting("Progress", true));
   private final SliderSetting damage = this.add(new SliderSetting("Damage", 1.0, 0.0, 2.0, 0.01));
   private final ColorSetting box = this.add(new ColorSetting("Box", new Color(198, 176, 12, 255)).injectBoolean(true));
   private final ColorSetting fill = this.add(new ColorSetting("Fill", new Color(198, 176, 12, 78)).injectBoolean(true));
   private final ColorSetting boxFriend = this.add(new ColorSetting("FriendBox", new Color(30, 45, 169, 255)).injectBoolean(true));
   private final ColorSetting fillFriend = this.add(new ColorSetting("FriendFill", new Color(30, 45, 169, 78)).injectBoolean(true));
   private final EnumSetting<Easing> ease = this.add(new EnumSetting<>("Ease", Easing.CubicInOut));
   private final BooleanSetting second = this.add(new BooleanSetting("Second", true));
   private final ColorSetting secondBox = this.add(new ColorSetting("SecondBox", new Color(255, 255, 255, 255)).injectBoolean(true));
   private final ColorSetting secondFill = this.add(new ColorSetting("SecondFill", new Color(255, 255, 255, 100)).injectBoolean(true));
   final DecimalFormat df = new DecimalFormat("0.0");
   final Color startColor = new Color(255, 6, 6);
   final Color endColor = new Color(0, 255, 12);
   final Color doubleColor = new Color(255, 179, 96);

   public BreakESP() {
      super("BreakESP", Module.Category.Render);
      this.setChinese("\u6316\u6398\u663e\u793a");
      INSTANCE = this;
   }

   private Color getFillColor(PlayerEntity player) {
      return CrucifixBeta.FRIEND.isFriend(player) ? this.fillFriend.getValue() : this.fill.getValue();
   }

   private Color getBoxColor(PlayerEntity player) {
      return CrucifixBeta.FRIEND.isFriend(player) ? this.boxFriend.getValue() : this.box.getValue();
   }

   @Override
   public void onRender3D(MatrixStack matrixStack) {
      for (BreakManager.BreakData var3 : CrucifixBeta.BREAK.breakMap.values()) {
         if (var3 != null && var3.getEntity() != null) {
            PlayerEntity var4 = (PlayerEntity)var3.getEntity();
            double var5 = 0.5 * (1.0 - var3.fade.ease(this.ease.getValue()));
            Box var7 = new Box(var3.pos).shrink(var5, var5, var5).shrink(-var5, -var5, -var5);
            if (this.fill.booleanValue) {
               Render3DUtil.drawFill(matrixStack, var7, this.getFillColor(var4));
            }

            if (this.box.booleanValue) {
               Render3DUtil.drawBox(matrixStack, var7, this.getBoxColor(var4));
            }

            Render3DUtil.drawText3D(var4.getName().getString(), var3.pos.toCenterPos().add(0.0, this.progress.getValue() ? 0.15 : 0.0, 0.0), -1);
            if (this.progress.getValue()) {
               Render3DUtil.drawText3D(
                  Text.of(
                     var3.failed
                        ? "\u00a74Failed"
                        : (var3.complete ? "Broke" : this.df.format(Math.min(1.0, (double)var3.timer.getMs() / var3.breakTime) * 100.0))
                  ),
                  var3.pos.toCenterPos().add(0.0, -0.15, 0.0),
                  0.0,
                  0.0,
                  1.0,
                  var3.complete
                     ? (mc.world.isAir(var3.pos) ? this.endColor : this.startColor)
                     : ColorUtil.fadeColor(this.startColor, this.endColor, (double)var3.timer.getMs() / var3.breakTime)
               );
            }
         }
      }

      if (this.second.getValue()) {
         for (int var13 : CrucifixBeta.BREAK.doubleMap.keySet()) {
            BreakManager.BreakData var14 = CrucifixBeta.BREAK.doubleMap.get(var13);
            if (var14 != null && var14.getEntity() != null && !mc.world.isAir(var14.pos)) {
               BreakManager.BreakData var8 = CrucifixBeta.BREAK.breakMap.get(var13);
               if (var8 == null || !var8.pos.equals(var14.pos)) {
                  double var9 = 0.5 * (1.0 - var14.fade.ease(this.ease.getValue()));
                  Box var11 = new Box(var14.pos).shrink(var9, var9, var9).shrink(-var9, -var9, -var9);
                  if (this.secondFill.booleanValue) {
                     Render3DUtil.drawFill(matrixStack, var11, this.secondFill.getValue());
                  }

                  if (this.secondBox.booleanValue) {
                     Render3DUtil.drawBox(matrixStack, var11, this.secondBox.getValue());
                  }

                  Render3DUtil.drawText3D(var14.getEntity().getName().getString(), var14.pos.toCenterPos().add(0.0, 0.15, 0.0), -1);
                  Render3DUtil.drawText3D("Double", var14.pos.toCenterPos().add(0.0, -0.15, 0.0), this.doubleColor.getRGB());
               }
            } else {
               CrucifixBeta.BREAK.doubleMap.remove(var13);
            }
         }
      }
   }

   public static double getBreakTime(BlockPos pos, boolean extraBreak) {
      int var2 = getTool(pos);
      if (var2 == -1) {
         var2 = mc.player.getInventory().selectedSlot;
      }

      return getBreakTime(pos, var2, extraBreak ? 1.0 : INSTANCE.damage.getValue());
   }

   static int getTool(BlockPos pos) {
      AtomicInteger var1 = new AtomicInteger();
      var1.set(-1);
      float var2 = 1.0F;

      for (Entry var4 : InventoryUtil.getInventoryAndHotbarSlots().entrySet()) {
         float var5;
         float var6;
         if (!(((ItemStack)var4.getValue()).getItem() instanceof AirBlockItem)
            && (
                     var5 = (float)EnchantmentHelper.getLevel(
                        mc.world.getRegistryManager().get(Enchantments.EFFICIENCY.getRegistryRef()).getEntry(Enchantments.EFFICIENCY).get(),
                        (ItemStack)var4.getValue()
                     )
                  )
                  + (var6 = ((ItemStack)var4.getValue()).getMiningSpeedMultiplier(mc.world.getBlockState(pos)))
               > var2) {
            var2 = var5 + var6;
            var1.set((Integer)var4.getKey());
         }
      }

      return var1.get();
   }

   static double getBreakTime(BlockPos pos, int slot, double damage) {
      return (double)(1.0F / getBlockStrength(pos, mc.player.getInventory().getStack(slot)) / 20.0F * 1000.0F) * damage;
   }

   static float getBlockStrength(BlockPos position, ItemStack itemStack) {
      BlockState var2 = mc.world.getBlockState(position);
      float var3 = var2.getHardness(mc.world, position);
      if (var3 < 0.0F) {
         return 0.0F;
      } else {
         float var4 = var2.isToolRequired() && !itemStack.isSuitableFor(var2) ? 100.0F : 30.0F;
         return getDigSpeed(var2, itemStack) / var3 / var4;
      }
   }

   static float getDigSpeed(BlockState state, ItemStack itemStack) {
      float var2 = getDestroySpeed(state, itemStack);
      int var3;
      if (var2 > 1.0F
         && (
               var3 = EnchantmentHelper.getLevel(
                  mc.world.getRegistryManager().get(Enchantments.EFFICIENCY.getRegistryRef()).getEntry(Enchantments.EFFICIENCY).get(), itemStack
               )
            )
            > 0
         && !itemStack.isEmpty()) {
         var2 += (float)(StrictMath.pow((double)var3, 2.0) + 1.0);
      }

      return var2 < 0.0F ? 0.0F : var2;
   }

   static float getDestroySpeed(BlockState state, ItemStack itemStack) {
      float var2 = 1.0F;
      if (itemStack != null && !itemStack.isEmpty()) {
         var2 *= itemStack.getMiningSpeedMultiplier(state);
      }

      return var2;
   }
}
