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

import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.PacketEvent;
import dev.crucifixbeta.api.events.impl.TickEvent;
import dev.crucifixbeta.api.events.impl.UpdateEvent;
import dev.crucifixbeta.api.events.impl.UpdateRotateEvent;
import dev.crucifixbeta.api.utils.combat.CombatUtil;
import dev.crucifixbeta.api.utils.math.PredictUtil;
import dev.crucifixbeta.api.utils.math.Timer;
import dev.crucifixbeta.core.impl.RotationManager;
import dev.crucifixbeta.mod.modules.Module;
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.Random;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BowItem;
import net.minecraft.item.Items;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket;
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket.Mode;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket.Action;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.Full;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.PositionAndOnGround;
import net.minecraft.util.Hand;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public class BowBomb extends Module {
   public static boolean send;
   private final EnumSetting<BowBomb.exploitEn> exploit = this.add(new EnumSetting<>("Exploit", BowBomb.exploitEn.Strong));
   private final Random random = new Random();
   private final Timer delayTimer = new Timer();
   private final BooleanSetting aim = this.add(new BooleanSetting("Aimbot", true));
   private final SliderSetting predictTicks = this.add(new SliderSetting("PredictTicks", 3.0, 0.0, 10.0, 0.1));
   private final BooleanSetting rotation = this.add(new BooleanSetting("Rotation", false));
   private final SliderSetting spoofs = this.add(new SliderSetting("Spoofs", 50.0, 0.0, 200.0, 1.0));
   private final BooleanSetting minimize = this.add(new BooleanSetting("Minimize", false));
   private final SliderSetting delay = this.add(new SliderSetting("Delay", 5.0, 0.0, 10.0).setSuffix("s"));
   private final SliderSetting activeTime = this.add(
      new SliderSetting("ActiveTime", 0.4F, 0.0, 3.0, 0.01).setSuffix("s")
   );
   private final BooleanSetting message = this.add(new BooleanSetting("Message", true));
   private final BooleanSetting fastBow = this.add(new BooleanSetting("FastBow", false).setParent());
   private final SliderSetting fastBowSpeed = this.add(
      new SliderSetting("FastBowSpeed", 5.0, 1.0, 20.0, 0.1, () -> this.fastBow.isOpen()).setSuffix("x")
   );
   private final SliderSetting fastBowChargeTime = this.add(
      new SliderSetting("FastBowCharge", 3.0, 1.0, 20.0, 1.0, () -> this.fastBow.isOpen()).setSuffix("ticks")
   );
   private final SliderSetting fastBowDelay = this.add(
      new SliderSetting("FastBowDelay", 0.0, 0.0, 5.0, 0.1, () -> this.fastBow.isOpen()).setSuffix("ticks")
   );
   private final Timer activeTimer = new Timer();
   boolean active = false;
   private int fastBowTicks = 0;
   private int fastBowDelayTicks = 0;
   private boolean fastBowCharging = false;

   public BowBomb() {
      super("BowBomb", "exploit", Module.Category.Exploit);
      this.setChinese("\u5f13\u6f0f\u6d1e");
   }

   @EventListener
   public void onMotion(UpdateRotateEvent event) {
      if (mc.player.isUsingItem() && mc.player.getActiveItem().getItem() == Items.BOW && this.aim.getValue()) {
         PlayerEntity var2 = this.getTarget();
         if (var2 != null) {
            Vec3d var3 = PredictUtil.getPos(var2, this.predictTicks.getValueInt()).add(0.0, (double)var2.getEyeHeight(var2.getPose()), 0.0);
            float[] var4 = RotationManager.getRotation(var3);
            event.setRotation(var4[0], var4[1]);
         }
      }
   }

   private PlayerEntity getTarget() {
      AbstractClientPlayerEntity var1 = null;
      double var2 = 100000.0;

      for (AbstractClientPlayerEntity var5 : CrucifixBeta.THREAD.getPlayers()) {
         if (!(Math.abs(var5.getY() - mc.player.getY()) > 4.0) && CombatUtil.isValid(var5, var2)) {
            var1 = var5;
            var2 = (double)mc.player.distanceTo(var5);
         }
      }

      return var1;
   }

   @EventListener
   public void onUpdate(UpdateEvent event) {
      if (mc.player.isUsingItem() && mc.player.getActiveItem().getItem() == Items.BOW) {
         this.active = true;
      } else {
         this.activeTimer.reset();
         this.active = false;
      }
   }

   @Override
   public void onDisable() {
      send = false;
      this.fastBowTicks = 0;
      this.fastBowDelayTicks = 0;
      this.fastBowCharging = false;
   }

   @EventListener
   public void onTick(TickEvent event) {
      if (nullCheck() || !this.fastBow.getValue()) {
         this.resetFastBowState();
      } else if (!this.isHoldingBow()) {
         this.resetFastBowState();
      } else if (this.fastBowDelayTicks > 0) {
         this.fastBowDelayTicks--;
      } else {
         boolean var2 = mc.player.isUsingItem()
            && (mc.player.getActiveHand() == Hand.MAIN_HAND ? mc.player.getMainHandStack() : mc.player.getOffHandStack()).getItem() instanceof BowItem;
         if (!var2) {
            this.fastBowTicks = 0;
            this.fastBowCharging = false;
         } else {
            if (!this.fastBowCharging) {
               this.fastBowCharging = true;
               this.fastBowTicks = 0;
            }

            this.fastBowTicks++;
            float var3 = (float)(this.fastBowChargeTime.getValue() * 20.0 / Math.max(0.1, this.fastBowSpeed.getValue()));
            if (!((float)this.fastBowTicks < var3)) {
               Hand var4 = mc.player.getActiveHand();
               mc.player
                  .networkHandler
                  .sendPacket(new PlayerActionC2SPacket(Action.RELEASE_USE_ITEM, mc.player.getBlockPos(), mc.player.getHorizontalFacing()));
               this.fastBowTicks = 0;
               this.fastBowCharging = false;
               this.fastBowDelayTicks = Math.max(0, this.fastBowDelay.getValueInt());
               sendSequencedPacket(id -> new PlayerInteractItemC2SPacket(var4, id, CrucifixBeta.ROTATION.getLastYaw(), CrucifixBeta.ROTATION.getLastPitch()));
            }
         }
      }
   }

   @EventListener
   protected void onPacketSend(PacketEvent.Send event) {
      if (!nullCheck()
         && this.delayTimer.passed((long)(this.delay.getValue() * 1000.0))
         && this.activeTimer.passed((long)(this.activeTime.getValue() * 1000.0))
         && this.active) {
         Packet var2 = event.getPacket();
         PlayerActionC2SPacket var3;
         if (var2 instanceof PlayerActionC2SPacket && (var3 = (PlayerActionC2SPacket)var2).getAction() == Action.RELEASE_USE_ITEM) {
            send = true;
            if (this.message.getValue()) {
               this.sendMessage("\u00a7eBowBomb trigger.");
            }

            mc.getNetworkHandler().sendPacket(new ClientCommandC2SPacket(mc.player, Mode.START_SPRINTING));
            if (this.exploit.getValue() == BowBomb.exploitEn.Fast) {
               for (int var4 = 0; var4 < this.getRuns(); var4++) {
                  this.spoof(mc.player.getX(), this.minimize.getValue() ? mc.player.getY() : mc.player.getY() - 1.0E-10, mc.player.getZ(), true);
                  this.spoof(mc.player.getX(), mc.player.getY() + 1.0E-10, mc.player.getZ(), false);
               }
            }

            if (this.exploit.getValue() == BowBomb.exploitEn.Strong) {
               for (int var6 = 0; var6 < this.getRuns(); var6++) {
                  this.spoof(mc.player.getX(), mc.player.getY() + 1.0E-10, mc.player.getZ(), false);
                  this.spoof(mc.player.getX(), this.minimize.getValue() ? mc.player.getY() : mc.player.getY() - 1.0E-10, mc.player.getZ(), true);
               }
            }

            if (this.exploit.getValue() == BowBomb.exploitEn.Phobos) {
               for (int var7 = 0; var7 < this.getRuns(); var7++) {
                  this.spoof(mc.player.getX(), mc.player.getY() + 1.3E-13, mc.player.getZ(), true);
                  this.spoof(mc.player.getX(), mc.player.getY() + 2.7E-13, mc.player.getZ(), false);
               }
            }

            if (this.exploit.getValue() == BowBomb.exploitEn.Strict) {
               double[] var8 = new double[]{
                  100.0 * -Math.sin(Math.toRadians((double)mc.player.getYaw())), 100.0 * Math.cos(Math.toRadians((double)mc.player.getYaw()))
               };

               for (int var5 = 0; var5 < this.getRuns(); var5++) {
                  if (this.random.nextBoolean()) {
                     this.spoof(mc.player.getX() - var8[0], mc.player.getY(), mc.player.getZ() - var8[1], false);
                  } else {
                     this.spoof(mc.player.getX() + var8[0], mc.player.getY(), mc.player.getZ() + var8[1], true);
                  }
               }
            }

            send = false;
            this.delayTimer.reset();
         }
      }
   }

   private void spoof(double x, double y, double z, boolean ground) {
      if (this.rotation.getValue()) {
         mc.getNetworkHandler().sendPacket(new Full(x, y, z, mc.player.getYaw(), mc.player.getPitch(), ground));
      } else {
         mc.getNetworkHandler().sendPacket(new PositionAndOnGround(x, y, z, ground));
      }
   }

   private int getRuns() {
      return this.spoofs.getValueInt();
   }

   private void resetFastBowState() {
      this.fastBowTicks = 0;
      this.fastBowDelayTicks = 0;
      this.fastBowCharging = false;
   }

   private boolean isHoldingBow() {
      return mc.player != null && (mc.player.getMainHandStack().getItem() == Items.BOW || mc.player.getOffHandStack().getItem() == Items.BOW);
   }

   static {

      send = false;
   }
@Environment(EnvType.CLIENT)
   private static enum exploitEn {
      Strong,
      Fast,
      Strict,
      Phobos;

}
}
