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

import dev.crucifixbeta.CrucifixBeta;
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.math.PredictUtil;
import dev.crucifixbeta.api.utils.math.Timer;
import dev.crucifixbeta.api.utils.player.EntityUtil;
import dev.crucifixbeta.api.utils.player.InventoryUtil;
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.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.EnumSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import java.util.ArrayList;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.ConcretePowderBlock;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ElytraItem;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public class AutoTrap extends Module {
   public static AutoTrap INSTANCE;
   public final SliderSetting delay = this.add(new SliderSetting("Delay", 100, 0, 500).setSuffix("ms"));
   private final EnumSetting<AutoTrap.TargetMode> targetMod = this.add(new EnumSetting<>("TargetMode", AutoTrap.TargetMode.Single));
   private final EnumSetting<AutoTrap.TrapBlock> trapBlock = this.add(new EnumSetting<>("TrapMode", AutoTrap.TrapBlock.Obsidian));
   private final EnumSetting<AutoTrap.Mode> headMode = this.add(new EnumSetting<>("BlockForHead", AutoTrap.Mode.Anchor));
   final ArrayList<BlockPos> trapList = new ArrayList<>();
   final ArrayList<BlockPos> placeList = new ArrayList<>();
   private final Timer timer = new Timer();
   private final SliderSetting placeRange = this.add(new SliderSetting("PlaceRange", 4.0, 1.0, 6.0).setSuffix("m"));
   private final SliderSetting blocksPer = this.add(new SliderSetting("BlocksPer", 1, 1, 8));
   public final SliderSetting predictTicks = this.add(new SliderSetting("PredictTicks", 2.0, 0.0, 50.0, 1.0));
   private final BooleanSetting rotate = this.add(new BooleanSetting("Rotate", true));
   private final BooleanSetting autoDisable = this.add(new BooleanSetting("AutoDisable", true));
   private final SliderSetting range = this.add(new SliderSetting("Range", 5.0, 1.0, 8.0).setSuffix("m"));
   private final BooleanSetting checkMine = this.add(new BooleanSetting("DetectMining", false));
   private final BooleanSetting helper = this.add(new BooleanSetting("Helper", true));
   private final BooleanSetting inventory = this.add(new BooleanSetting("InventorySwap", true));
   private final BooleanSetting onlyCrawling = this.add(new BooleanSetting("OnlyCrawling", false));
   private final BooleanSetting checkElytra = this.add(new BooleanSetting("CheckElytra", false));
   private final BooleanSetting extend = this.add(new BooleanSetting("Extend", true));
   private final BooleanSetting antiStep = this.add(new BooleanSetting("AntiStep", false));
   private final BooleanSetting onlyBreak = this.add(new BooleanSetting("OnlyBreak", false, this.antiStep::getValue));
   private final BooleanSetting head = this.add(new BooleanSetting("Head", true));
   private final BooleanSetting headExtend = this.add(new BooleanSetting("HeadExtend", true));
   private final BooleanSetting chestUp = this.add(new BooleanSetting("ChestUp", true));
   private final BooleanSetting onlyBreaking = this.add(new BooleanSetting("OnlyBreaking", false, this.chestUp::getValue));
   private final BooleanSetting chest = this.add(new BooleanSetting("Chest", true));
   private final BooleanSetting onlyGround = this.add(new BooleanSetting("OnlyGround", false, this.chest::getValue));
   private final BooleanSetting ignoreCrawling = this.add(new BooleanSetting("IgnoreCrawling", false, this.chest::getValue));
   private final BooleanSetting legs = this.add(new BooleanSetting("Legs", false));
   private final BooleanSetting legAnchor = this.add(new BooleanSetting("LegAnchor", true));
   private final BooleanSetting down = this.add(new BooleanSetting("Down", false));
   private final BooleanSetting onlyHole = this.add(new BooleanSetting("OnlyHole", false));
   private final BooleanSetting breakCrystal = this.add(new BooleanSetting("Break", true));
   private final BooleanSetting usingPause = this.add(new BooleanSetting("UsingPause", true));
   private final BooleanSetting selfGround = this.add(new BooleanSetting("SelfGround", true));
   public PlayerEntity target;
   int progress = 0;

   public AutoTrap() {
      super("AutoTrap", Module.Category.Combat);
      this.setChinese("\u81ea\u52a8\u56f0\u4f4f");
      INSTANCE = this;
   }

   @EventListener
   public void onUpdate(UpdateEvent event) {
      this.trapList.clear();
      this.placeList.clear();
      this.progress = 0;
      this.target = null;
      if (!this.selfGround.getValue() || mc.player.isOnGround()) {
         if (!this.inventory.getValue() || EntityUtil.inInventory()) {
            if (!Blink.INSTANCE.isOn() || !Blink.INSTANCE.pauseModule.getValue()) {
               if (!this.usingPause.getValue() || !this.shouldPauseForUsingItem()) {
                  if (this.timer.passed((long)this.delay.getValue())) {
                     if (this.targetMod.getValue() == AutoTrap.TargetMode.Single) {
                        this.target = CombatUtil.getClosestEnemy(this.range.getValue());
                        if (this.target == null) {
                           if (this.autoDisable.getValue()) {
                              this.disable();
                           }

                           return;
                        }

                        this.trapTarget(this.target);
                     } else if (this.targetMod.getValue() == AutoTrap.TargetMode.Multi) {
                        boolean var2 = false;

                        for (PlayerEntity var4 : CombatUtil.getEnemies(this.range.getValue())) {
                           var2 = true;
                           this.target = var4;
                           this.trapTarget(this.target);
                        }

                        if (!var2) {
                           if (this.autoDisable.getValue()) {
                              this.disable();
                           }

                           this.target = null;
                        }
                     }
                  }
               }
            }
         }
      }
   }

   private void trapTarget(PlayerEntity target) {
      if (!this.onlyHole.getValue() || CrucifixBeta.HOLE.isHole(EntityUtil.getEntityPos(target))) {
         if (!this.onlyCrawling.getValue()
            || target.isCrawling()
            || this.checkElytra.getValue()
               && target.getInventory().armor.get(2).getItem() instanceof ElytraItem
               && (!(mc.player.getY() < target.getY() + 1.0) || target.isFallFlying())) {
            Vec3d var2 = this.predictTicks.getValue() > 0.0 ? PredictUtil.getPos(target, this.predictTicks.getValueInt()) : target.getPos();
            this.doTrap(target, new BlockPosX(var2.getX(), var2.getY(), var2.getZ()));
         }
      }
   }

   private void doTrap(PlayerEntity player, BlockPos pos) {
      if (pos != null) {
         if (!this.trapList.contains(pos)) {
            this.trapList.add(pos);
            int var3 = player.isCrawling() ? 1 : 2;
            int var4 = player.isCrawling() ? 0 : 1;
            if (this.legs.getValue()) {
               for (Direction var8 : Direction.values()) {
                  if (var8 != Direction.DOWN && var8 != Direction.UP) {
                     BlockPos var9 = pos.offset(var8);
                     this.tryPlaceBlock(var9, this.legAnchor.getValue(), false, false);
                     if (BlockUtil.getPlaceSide(var9) == null && BlockUtil.clientCanPlace(var9, this.breakCrystal.getValue()) && this.getHelper(var9) != null) {
                        this.tryPlaceObsidian(this.getHelper(var9));
                     }
                  }
               }
            }

            if (this.headExtend.getValue()) {
               int[] var15 = new int[]{1, 0, -1};

               for (int var42 : var15) {
                  for (int var13 : var15) {
                     BlockPos var14 = pos.add(var13, 0, var42);
                     if (this.checkEntity(new BlockPos(var14))) {
                        this.tryPlaceBlock(
                           var14.up(var3),
                           this.headMode.getValue() == AutoTrap.Mode.Anchor,
                           this.headMode.getValue() == AutoTrap.Mode.Concrete,
                           this.headMode.getValue() == AutoTrap.Mode.Web
                        );
                     }
                  }
               }
            }

            if (this.head.getValue() && BlockUtil.clientCanPlace(pos.up(var3), this.breakCrystal.getValue())) {
               if (BlockUtil.getPlaceSide(pos.up(var3)) == null) {
                  boolean var16 = this.helper.getValue();
                  if (this.getHelper(pos.up(var3)) != null) {
                     this.tryPlaceObsidian(this.getHelper(pos.up(var3)));
                     var16 = false;
                  }

                  if (var16) {
                     for (Direction var22 : Direction.values()) {
                        if (var22 != Direction.DOWN && var22 != Direction.UP) {
                           BlockPos var49 = pos.offset(var22).up(var4);
                           if (BlockUtil.isStrictDirection(pos.offset(var22).up(), var22.getOpposite())
                              && BlockUtil.clientCanPlace(var49.up(var4), this.breakCrystal.getValue())
                              && BlockUtil.canPlace(var49, this.placeRange.getValue(), this.breakCrystal.getValue())) {
                              this.tryPlaceObsidian(var49);
                              var16 = false;
                              break;
                           }
                        }
                     }

                     if (var16) {
                        for (Direction var23 : Direction.values()) {
                           if (var23 != Direction.DOWN && var23 != Direction.UP) {
                              BlockPos var50 = pos.offset(var23).up(var4);
                              if (BlockUtil.isStrictDirection(pos.offset(var23).up(), var23.getOpposite())
                                 && BlockUtil.clientCanPlace(var50.up(var4), this.breakCrystal.getValue())
                                 && BlockUtil.getPlaceSide(var50) == null
                                 && BlockUtil.clientCanPlace(var50, this.breakCrystal.getValue())
                                 && this.getHelper(var50) != null) {
                                 this.tryPlaceObsidian(this.getHelper(var50));
                                 var16 = false;
                                 break;
                              }
                           }
                        }

                        if (var16) {
                           for (Direction var24 : Direction.values()) {
                              if (var24 != Direction.DOWN && var24 != Direction.UP) {
                                 BlockPos var51 = pos.offset(var24).up(var4);
                                 if (BlockUtil.isStrictDirection(pos.offset(var24).up(), var24.getOpposite())
                                    && BlockUtil.clientCanPlace(var51.up(var4), this.breakCrystal.getValue())
                                    && BlockUtil.getPlaceSide(var51) == null
                                    && BlockUtil.clientCanPlace(var51, this.breakCrystal.getValue())
                                    && this.getHelper(var51) != null
                                    && BlockUtil.getPlaceSide(var51.down()) == null
                                    && BlockUtil.clientCanPlace(var51.down(), this.breakCrystal.getValue())
                                    && this.getHelper(var51.down()) != null) {
                                    this.tryPlaceObsidian(this.getHelper(var51.down()));
                                    break;
                                 }
                              }
                           }
                        }
                     }
                  }
               }

               this.tryPlaceBlock(
                  pos.up(var3),
                  this.headMode.getValue() == AutoTrap.Mode.Anchor,
                  this.headMode.getValue() == AutoTrap.Mode.Concrete,
                  this.headMode.getValue() == AutoTrap.Mode.Web
               );
            }

            if (this.antiStep.getValue() && (CrucifixBeta.BREAK.isMining(pos.up(var3)) || !this.onlyBreak.getValue())) {
               if (BlockUtil.getPlaceSide(pos.up(3)) == null
                  && BlockUtil.clientCanPlace(pos.up(3), this.breakCrystal.getValue())
                  && this.getHelper(pos.up(3), Direction.DOWN) != null) {
                  this.tryPlaceObsidian(this.getHelper(pos.up(3)));
               }

               this.tryPlaceObsidian(pos.up(3));
            }

            if (this.down.getValue()) {
               BlockPos var17 = pos.down();
               this.tryPlaceObsidian(var17);
               if (BlockUtil.getPlaceSide(var17) == null && BlockUtil.clientCanPlace(var17, this.breakCrystal.getValue()) && this.getHelper(var17) != null) {
                  this.tryPlaceObsidian(this.getHelper(var17));
               }
            }

            if (this.chestUp.getValue()) {
               for (Direction var39 : Direction.values()) {
                  if (var39 != Direction.DOWN && var39 != Direction.UP) {
                     BlockPos var46 = pos.offset(var39).up(var3);
                     if (!this.onlyBreaking.getValue() || CrucifixBeta.BREAK.isMining(pos.up(var3))) {
                        this.tryPlaceObsidian(var46);
                        if (BlockUtil.getPlaceSide(var46) == null && BlockUtil.clientCanPlace(var46, this.breakCrystal.getValue())) {
                           if (this.getHelper(var46) != null) {
                              this.tryPlaceObsidian(this.getHelper(var46));
                           } else if (BlockUtil.getPlaceSide(var46.down()) == null
                              && BlockUtil.clientCanPlace(var46.down(), this.breakCrystal.getValue())
                              && this.getHelper(var46.down()) != null) {
                              this.tryPlaceObsidian(this.getHelper(var46.down()));
                           }
                        }
                     }
                  }
               }
            }

            if (this.chest.getValue()
               && (!this.onlyGround.getValue() || this.target.isOnGround())
               && (!this.ignoreCrawling.getValue() || !this.target.isCrawling())) {
               for (Direction var40 : Direction.values()) {
                  if (var40 != Direction.DOWN && var40 != Direction.UP) {
                     BlockPos var47 = pos.offset(var40).up(var4);
                     this.tryPlaceObsidian(var47);
                     if (BlockUtil.getPlaceSide(var47) == null && BlockUtil.clientCanPlace(var47, this.breakCrystal.getValue())) {
                        if (this.getHelper(var47) != null) {
                           this.tryPlaceObsidian(this.getHelper(var47));
                        } else if (BlockUtil.getPlaceSide(var47.down()) == null
                           && BlockUtil.clientCanPlace(var47.down(), this.breakCrystal.getValue())
                           && this.getHelper(var47.down()) != null) {
                           this.tryPlaceObsidian(this.getHelper(var47.down()));
                        }
                     }
                  }
               }
            }

            if (this.extend.getValue()) {
               for (int var41 : new int[]{1, 0, -1}) {
                  for (int var54 : new int[]{1, 0, -1}) {
                     BlockPos var55 = pos.add(var41, 0, var54);
                     if (this.checkEntity(new BlockPos(var55))) {
                        this.doTrap(player, var55);
                     }
                  }
               }
            }
         }
      }
   }

   @Override
   public String getInfo() {
      return this.target != null ? this.target.getName().getString() : null;
   }

   public BlockPos getHelper(BlockPos pos) {
      if (!this.helper.getValue()) {
         return null;
      } else {
         for (Direction var5 : Direction.values()) {
            if ((!this.checkMine.getValue() || !CrucifixBeta.BREAK.isMining(pos.offset(var5)))
               && BlockUtil.isStrictDirection(pos.offset(var5), var5.getOpposite())
               && BlockUtil.canPlace(pos.offset(var5), this.placeRange.getValue(), this.breakCrystal.getValue())) {
               return pos.offset(var5);
            }
         }

         return null;
      }
   }

   public BlockPos getHelper(BlockPos pos, Direction ignore) {
      if (!this.helper.getValue()) {
         return null;
      } else {
         for (Direction var6 : Direction.values()) {
            if (var6 != ignore
               && (!this.checkMine.getValue() || !CrucifixBeta.BREAK.isMining(pos.offset(var6)))
               && BlockUtil.isStrictDirection(pos.offset(var6), var6.getOpposite())
               && BlockUtil.canPlace(pos.offset(var6), this.placeRange.getValue(), this.breakCrystal.getValue())) {
               return pos.offset(var6);
            }
         }

         return null;
      }
   }

   private boolean checkEntity(BlockPos pos) {
      if (mc.player.getBoundingBox().intersects(new Box(pos))) {
         return false;
      } else {
         for (Entity var3 : CrucifixBeta.THREAD.getPlayers()) {
            if (var3.getBoundingBox().intersects(new Box(pos)) && var3.isAlive()) {
               return true;
            }
         }

         return false;
      }
   }

   private void tryPlaceBlock(BlockPos pos, boolean anchor, boolean sand, boolean web) {
      if (!this.placeList.contains(pos)) {
         if (!CrucifixBeta.BREAK.isMining(pos)) {
            if (BlockUtil.canPlace(pos, 6.0, this.breakCrystal.getValue())) {
               if ((double)this.progress < this.blocksPer.getValue()) {
                  if (!((double)MathHelper.sqrt((float)mc.player.getEyePos().squaredDistanceTo(pos.toCenterPos())) > this.placeRange.getValue())) {
                     int var5 = mc.player.getInventory().selectedSlot;
                     int var6;
                     if (sand) {
                        var6 = this.getConcrete();
                     } else if (web) {
                        var6 = this.getWeb() != -1 ? this.getWeb() : this.getBlock();
                     } else {
                        var6 = anchor && this.getAnchor() != -1 ? this.getAnchor() : this.getBlock();
                     }

                     if (var6 != -1) {
                        if (this.tryUseCombatTask()) {
                           this.placeList.add(pos);
                           CombatUtil.attackCrystal(pos, this.rotate.getValue(), this.usingPause.getValue());
                           this.doSwap(var6);
                           BlockUtil.placeBlock(pos, this.rotate.getValue());
                           if (this.inventory.getValue()) {
                              this.doSwap(var6);
                              EntityUtil.syncInventory();
                           } else {
                              this.doSwap(var5);
                           }

                           this.timer.reset();
                           this.progress++;
                        }
                     }
                  }
               }
            }
         }
      }
   }

   private void tryPlaceObsidian(BlockPos pos) {
      if (pos != null) {
         if (!this.placeList.contains(pos)) {
            if (!CrucifixBeta.BREAK.isMining(pos)) {
               if (BlockUtil.canPlace(pos, 6.0, this.breakCrystal.getValue())) {
                  if ((double)this.progress < this.blocksPer.getValue()) {
                     if (!((double)MathHelper.sqrt((float)mc.player.getEyePos().squaredDistanceTo(pos.toCenterPos())) > this.placeRange.getValue())) {
                        int var2 = mc.player.getInventory().selectedSlot;
                        int var3 = this.getBlock();
                        if (var3 != -1) {
                           if (this.tryUseCombatTask()) {
                              BlockUtil.placedPos.add(pos);
                              this.placeList.add(pos);
                              CombatUtil.attackCrystal(pos, this.rotate.getValue(), this.usingPause.getValue());
                              this.doSwap(var3);
                              BlockUtil.placeBlock(pos, this.rotate.getValue());
                              if (this.inventory.getValue()) {
                                 this.doSwap(var3);
                                 EntityUtil.syncInventory();
                              } else {
                                 this.doSwap(var2);
                              }

                              this.timer.reset();
                              this.progress++;
                           }
                        }
                     }
                  }
               }
            }
         }
      }
   }

   private void doSwap(int slot) {
      if (this.inventory.getValue()) {
         InventoryUtil.inventorySwap(slot, mc.player.getInventory().selectedSlot);
      } else {
         InventoryUtil.switchToSlot(slot);
      }
   }

   private int getBlock() {
      if (this.trapBlock.is(AutoTrap.TrapBlock.Glass)) {
         return this.getGlass();
      } else {
         return this.inventory.getValue() ? InventoryUtil.findBlockInventorySlot(Blocks.OBSIDIAN) : InventoryUtil.findBlock(Blocks.OBSIDIAN);
      }
   }

   private int getGlass() {
      Block[] var1 = new Block[]{
         Blocks.GLASS,
         Blocks.WHITE_STAINED_GLASS,
         Blocks.LIGHT_GRAY_STAINED_GLASS,
         Blocks.GRAY_STAINED_GLASS,
         Blocks.BLACK_STAINED_GLASS,
         Blocks.BROWN_STAINED_GLASS,
         Blocks.RED_STAINED_GLASS,
         Blocks.ORANGE_STAINED_GLASS,
         Blocks.YELLOW_STAINED_GLASS,
         Blocks.LIME_STAINED_GLASS,
         Blocks.GREEN_STAINED_GLASS,
         Blocks.CYAN_STAINED_GLASS,
         Blocks.LIGHT_BLUE_STAINED_GLASS,
         Blocks.BLUE_STAINED_GLASS,
         Blocks.PURPLE_STAINED_GLASS,
         Blocks.MAGENTA_STAINED_GLASS,
         Blocks.PINK_STAINED_GLASS
      };

      for (Block var5 : var1) {
         int var6 = this.inventory.getValue() ? InventoryUtil.findBlockInventorySlot(var5) : InventoryUtil.findBlock(var5);
         if (var6 != -1) {
            return var6;
         }
      }

      return -1;
   }

   private int getConcrete() {
      return this.inventory.getValue() ? InventoryUtil.findClassInventorySlot(ConcretePowderBlock.class) : InventoryUtil.findClass(ConcretePowderBlock.class);
   }

   private int getWeb() {
      return this.inventory.getValue() ? InventoryUtil.findBlockInventorySlot(Blocks.COBWEB) : InventoryUtil.findBlock(Blocks.COBWEB);
   }

   private int getAnchor() {
      return this.inventory.getValue() ? InventoryUtil.findBlockInventorySlot(Blocks.RESPAWN_ANCHOR) : InventoryUtil.findBlock(Blocks.RESPAWN_ANCHOR);
   }
@Environment(EnvType.CLIENT)
   private static enum Mode {
      Obsidian,
      Anchor,
      Web,
      Concrete;

}

   @Environment(EnvType.CLIENT)
   public static enum TargetMode {
      Single,
      Multi;

}

   @Environment(EnvType.CLIENT)
   private static enum TrapBlock {
      Obsidian,
      Glass;

}
}
