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

import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.ClientTickEvent;
import dev.crucifixbeta.api.events.impl.RotationEvent;
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.client.AntiCheat;
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.Blocks;
import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public class AntiPiston extends Module {
   public static AntiPiston INSTANCE;
   public final EnumSetting<AntiPiston.Mode> mode = this.add(new EnumSetting<>("Mode", AntiPiston.Mode.Both));
   public final BooleanSetting onlyBlock = this.add(new BooleanSetting("OnlyBurrow", true));
   public final SliderSetting placeDelay = this.add(new SliderSetting("PlaceDelay", 50, 0, 500));
   public final SliderSetting blocksPer = this.add(new SliderSetting("BlocksPer", 2, 1, 10));
   public final BooleanSetting feet = this.add(new BooleanSetting("Feet", true));
   public final BooleanSetting face = this.add(new BooleanSetting("Face", true));
   public final BooleanSetting inventorySwap = this.add(new BooleanSetting("InventorySwap", true));
   public final BooleanSetting rotate = this.add(new BooleanSetting("Rotate", true));
   public final BooleanSetting swing = this.add(new BooleanSetting("Swing", true));
   public final BooleanSetting autoburrow = this.add(new BooleanSetting("AutoBurrow", false));
   private final Timer timer = new Timer();
   private boolean webPlaced = false;
   public Vec3d directionVec = null;
   int progress = 0;
   final ArrayList<BlockPos> pos = new ArrayList<>();

   public AntiPiston() {
      super("AntiPiston", Module.Category.Combat);
      this.setChinese("\u9632\u6d3b\u585e");
      INSTANCE = this;
   }

   @Override
   public String getInfo() {
      return this.pos.isEmpty() ? null : "Working";
   }

   @EventListener
   public void onRotate(RotationEvent event) {
      if (this.rotate.getValue() && this.directionVec != null) {
         CrucifixBeta.ROTATION.lookAt(this.directionVec);
      }
   }

   @EventListener
   public void onTick(ClientTickEvent event) {
      if (!nullCheck()) {
         this.update();
      }
   }

   private void update() {
      if (this.timer.passed((long)this.placeDelay.getValueInt())) {
         if (!this.inventorySwap.getValue() || EntityUtil.inInventory()) {
            if (!this.onlyBlock.getValue() || EntityUtil.isInsideBlock()) {
               this.pos.clear();
               this.progress = 0;
               this.directionVec = null;
               if (this.getWebSlot() != -1) {
                  if (!Blink.INSTANCE.isOn() || !Blink.INSTANCE.pauseModule.getValue()) {
                     Vec3d var1 = mc.player.getPos();
                     if (this.feet.getValue()) {
                        this.placeWeb(new BlockPosX(var1.getX(), var1.getY(), var1.getZ()));
                     }

                     if (this.face.getValue()) {
                        this.placeWeb(new BlockPosX(var1.getX(), var1.getY() + 1.1, var1.getZ()));
                     }

                     if (this.webPlaced && !this.isBurrowed() && this.autoburrow.getValue() && !AutoWeb.INSTANCE.isOn()) {
                        AutoWeb.INSTANCE.enable();
                        this.webPlaced = false;
                     }
                  }
               }
            }
         }
      }
   }

   private boolean placeWeb(BlockPos pos) {
      if (this.pos.contains(pos)) {
         return false;
      } else {
         this.pos.add(pos);
         if (this.progress >= this.blocksPer.getValueInt()) {
            return false;
         } else if (this.getWebSlot() == -1) {
            return false;
         } else if (BlockUtil.getPlaceSide(pos) != null && (mc.world.isAir(pos) || BlockUtil.getBlock(pos) == Blocks.COBWEB)) {
            int var2 = mc.player.getInventory().selectedSlot;
            int var3 = this.getWebSlot();
            if (!this.placeBlock(pos, this.rotate.getValue(), var3)) {
               return false;
            } else {
               BlockUtil.placedPos.add(pos);
               this.progress++;
               this.webPlaced = true;
               if (this.inventorySwap.getValue()) {
                  this.doSwap(var3);
                  EntityUtil.syncInventory();
               } else {
                  this.doSwap(var2);
               }

               this.timer.reset();
               return true;
            }
         } else {
            return false;
         }
      }
   }

   public boolean placeBlock(BlockPos pos, boolean rotate, int slot) {
      Direction var4 = BlockUtil.getPlaceSide(pos);
      if (var4 == null) {
         return BlockUtil.allowAirPlace() ? this.clickBlock(pos, Direction.DOWN, rotate, slot) : false;
      } else {
         return this.clickBlock(pos.offset(var4), var4.getOpposite(), rotate, slot);
      }
   }

   public boolean clickBlock(BlockPos pos, Direction side, boolean rotate, int slot) {
      Vec3d var5 = new Vec3d(
         (double)pos.getX() + 0.5 + (double)side.getVector().getX() * 0.5,
         (double)pos.getY() + 0.5 + (double)side.getVector().getY() * 0.5,
         (double)pos.getZ() + 0.5 + (double)side.getVector().getZ() * 0.5
      );
      if (rotate) {
         this.directionVec = var5;
         CrucifixBeta.ROTATION.lookAt(var5);
      }

      this.doSwap(slot);
      BlockHitResult var6 = new BlockHitResult(var5, side, pos, false);
      Module.sendSequencedPacket(id -> new PlayerInteractBlockC2SPacket(Hand.MAIN_HAND, var6, id));
      if (this.swing.getValue()) {
         EntityUtil.swingHand(Hand.MAIN_HAND, AntiCheat.INSTANCE.interactSwing.getValue());
      }

      if (rotate) {
         CrucifixBeta.ROTATION.snapBack();
      }

      return true;
   }

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

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

   private boolean isBurrowed() {
      BlockPos var1 = mc.player.getBlockPos();
      return !mc.world.isAir(var1);
   }
@Environment(EnvType.CLIENT)
   public static enum Mode {
      AntiPiston,
      AntiPush,
      Both;

}
}
