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

import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.UpdateEvent;
import dev.crucifixbeta.api.utils.combat.CombatUtil;
import dev.crucifixbeta.api.utils.player.EntityUtil;
import dev.crucifixbeta.api.utils.world.BlockPosX;
import dev.crucifixbeta.api.utils.world.BlockUtil;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.impl.exploit.Blink;
import dev.crucifixbeta.mod.modules.impl.player.PacketMine;
import dev.crucifixbeta.mod.modules.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;

@Environment(EnvType.CLIENT)
public class Breaker extends Module {
   public static Breaker INSTANCE;
   public final SliderSetting targetRange = this.add(
      new SliderSetting("TargetRange", 6.0, 0.0, 8.0, 0.1).setSuffix("m")
   );
   public final SliderSetting range = this.add(new SliderSetting("Range", 6.0, 0.0, 8.0, 0.1).setSuffix("m"));
   private final BooleanSetting burrow = this.add(new BooleanSetting("Burrow", true));
   private final BooleanSetting head = this.add(new BooleanSetting("Head", true));
   private final BooleanSetting face = this.add(new BooleanSetting("Face", true));
   private final BooleanSetting down = this.add(new BooleanSetting("Down", false));
   private final BooleanSetting surround = this.add(new BooleanSetting("Surround", true));
   private final BooleanSetting cevPause = this.add(new BooleanSetting("CevPause", true));
   public static final List<Block> hard;

   public Breaker() {
      super("Breaker", Module.Category.Combat);
      this.setChinese("\u81ea\u52a8\u6316\u6398");
      INSTANCE = this;
   }

   @EventListener
   public void onUpdate(UpdateEvent event) {
      if (PacketMine.INSTANCE != null) {
         if (CevBreaker.INSTANCE == null || !CevBreaker.INSTANCE.isOn() || !this.cevPause.getValue()) {
            if (!AntiCrawl.INSTANCE.work) {
               if (!Blink.INSTANCE.isOn() || !Blink.INSTANCE.pauseModule.getValue()) {
                  PlayerEntity var2 = CombatUtil.getClosestEnemy(this.targetRange.getValue());
                  if (var2 != null) {
                     this.doBreak(var2);
                  }
               }
            }
         }
      }
   }

   private void doBreak(PlayerEntity player) {
      BlockPos var2 = EntityUtil.getEntityPos(player, true);
      double[] var3 = new double[]{-0.8, 0.3, 1.1};
      double[] var4 = new double[]{0.3, -0.3};

      for (PlayerEntity var6 : CombatUtil.getEnemies(this.targetRange.getValue())) {
         for (double var10 : var3) {
            for (double var15 : var4) {
               for (double var20 : var4) {
                  BlockPosX var22 = new BlockPosX(var6.getX() + var15, var6.getY() + var10, var6.getZ() + var20);
                  if (this.canBreak(var22, Math.abs(var10 - 0.3) < 0.01) && var22.equals(PacketMine.getBreakPos())) {
                     return;
                  }
               }
            }
         }
      }

      ArrayList var34 = new ArrayList();
      if (this.down.getValue()) {
         var34.add(-0.8F);
      }

      if (this.head.getValue()) {
         var34.add(2.3F);
      }

      if (this.burrow.getValue()) {
         var34.add(0.3F);
      }

      if (this.face.getValue()) {
         var34.add(1.1F);
      }

      Iterator var35 = var34.iterator();

      while (var35.hasNext()) {
         double var23 = (double)((Float)var35.next()).floatValue();
         boolean var45 = Math.abs(var23 - 0.3) < 0.01;

         for (double var27 : var4) {
            BlockPosX var29 = new BlockPosX(player.getX() + var27, player.getY() + var23, player.getZ() + var27);
            if (this.canBreak(var29, var45)) {
               PacketMine.INSTANCE.mine(var29);
               return;
            }
         }
      }

      var35 = var34.iterator();

      while (var35.hasNext()) {
         double var53 = (double)((Float)var35.next()).floatValue();
         boolean var46 = Math.abs(var53 - 0.3) < 0.01;

         for (double var61 : var4) {
            for (double var31 : var4) {
               BlockPosX var33 = new BlockPosX(player.getX() + var31, player.getY() + var53, player.getZ() + var61);
               if (this.canBreak(var33, var46)) {
                  PacketMine.INSTANCE.mine(var33);
                  return;
               }
            }
         }
      }

      if (this.surround.getValue()) {
         for (Direction var47 : Direction.values()) {
            if (var47 != Direction.UP && var47 != Direction.DOWN) {
               BlockPos var55 = var2.offset(var47);
               if (!(Math.sqrt(mc.player.getEyePos().squaredDistanceTo(var55.toCenterPos())) > this.range.getValue())
                  && (mc.world.isAir(var55) || var55.equals(PacketMine.getBreakPos()))
                  && this.canPlaceCrystal(var55, false)) {
                  return;
               }
            }
         }

         ArrayList<BlockPos> var38 = new ArrayList<>();

         for (Direction var56 : Direction.values()) {
            if (var56 != Direction.UP && var56 != Direction.DOWN) {
               BlockPos var59 = var2.offset(var56);
               if (!(Math.sqrt(mc.player.getEyePos().squaredDistanceTo(var59.toCenterPos())) > this.range.getValue())
                  && this.canBreak(var59, false)
                  && this.canPlaceCrystal(var59, true)
                  && !this.isSurroundPos(var59)) {
                  var38.add(var59);
               }
            }
         }

         if (!var38.isEmpty()) {
            PacketMine.INSTANCE.mine(var38.stream().min(Comparator.comparingDouble(e -> e.getSquaredDistance(mc.player.getEyePos()))).get());
         } else {
            var38.clear();

            for (Direction var57 : Direction.values()) {
               if (var57 != Direction.UP && var57 != Direction.DOWN) {
                  BlockPos var60 = var2.offset(var57);
                  if (!(Math.sqrt(mc.player.getEyePos().squaredDistanceTo(var60.toCenterPos())) > this.range.getValue())
                     && this.canBreak(var60, false)
                     && this.canPlaceCrystal(var60, false)) {
                     var38.add(var60);
                  }
               }
            }

            if (!var38.isEmpty()) {
               PacketMine.INSTANCE.mine(var38.stream().min(Comparator.comparingDouble(e -> e.getSquaredDistance(mc.player.getEyePos()))).get());
            }
         }
      }
   }

   private boolean isSurroundPos(BlockPos pos) {
      for (Direction var5 : Direction.values()) {
         if (var5 != Direction.UP && var5 != Direction.DOWN) {
            BlockPos var6 = EntityUtil.getPlayerPos(true);
            if (var6.offset(var5).equals(pos)) {
               return true;
            }
         }
      }

      return false;
   }

   public boolean canPlaceCrystal(BlockPos pos, boolean block) {
      BlockPos var3 = pos.down();
      BlockPos var4 = var3.up();
      return (BlockUtil.getBlock(var3) == Blocks.BEDROCK || BlockUtil.getBlock(var3) == Blocks.OBSIDIAN || !block)
         && BlockUtil.noEntityBlockCrystal(var4, true, true)
         && BlockUtil.noEntityBlockCrystal(var4.up(), true, true);
   }

   private boolean canBreak(BlockPos pos, boolean isBurrow) {
      if (PacketMine.INSTANCE == null) {
         return false;
      } else if (mc.player.getEyePos().distanceTo(pos.toCenterPos()) <= PacketMine.INSTANCE.range.getValue()
         && (BlockUtil.getClickSideStrict(pos) != null || pos.equals(PacketMine.getBreakPos()))) {
         Block var3 = BlockUtil.getBlock(pos);
         if (var3 == null) {
            return false;
         } else if (var3 == Blocks.BEDROCK || var3 == Blocks.BARRIER || mc.world.isAir(pos) || mc.world.getBlockState(pos).isLiquid()) {
            return false;
         } else {
            return isBurrow ? hard.contains(var3) : true;
         }
      } else {
         return false;
      }
   }

   static {

      hard = Arrays.asList(
         Blocks.OBSIDIAN, Blocks.ENDER_CHEST, Blocks.NETHERITE_BLOCK, Blocks.CRYING_OBSIDIAN, Blocks.RESPAWN_ANCHOR, Blocks.ANCIENT_DEBRIS, Blocks.ANVIL
      );
   }
}
