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.math.Timer;
import dev.crucifixbeta.api.utils.move.MoveUtils;
import dev.crucifixbeta.api.utils.player.EntityUtil;
import dev.crucifixbeta.api.utils.player.InventoryUtil;
import dev.crucifixbeta.api.utils.rotation.Rotation;
import dev.crucifixbeta.api.utils.rotation.RotationUtils;
import dev.crucifixbeta.api.utils.world.BlockUtil;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.ButtonBlock;
import net.minecraft.entity.Entity;
import net.minecraft.entity.ExperienceOrbEntity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ArrowEntity;
import net.minecraft.entity.projectile.thrown.ExperienceBottleEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public class AutoButton extends Module {
   public static AutoButton INSTANCE;
   private final SliderSetting delay = this.add(new SliderSetting("Delay", 100, 0, 500).setSuffix("ms"));
   private final SliderSetting range = this.add(new SliderSetting("Range", 5.0, 0.0, 8.0).setSuffix("m"));
   private final SliderSetting placeRange = this.add(new SliderSetting("PlaceRange", 4.5, 0.0, 6.0).setSuffix("m"));
   private final BooleanSetting inventorySwap = this.add(new BooleanSetting("InventorySwap", true));
   private final BooleanSetting ghostHand = this.add(new BooleanSetting("GhostHand", true));
   private final BooleanSetting movementFix = this.add(new BooleanSetting("MovementFix", true));
   private final Timer timer = new Timer();

   public AutoButton() {
      super("AutoButton", Module.Category.Combat);
      this.setChinese("\u81ea\u52a8\u6309\u94ae");
      INSTANCE = this;
   }

   @EventListener
   public void onUpdate(UpdateEvent event) {
      if (this.timer.passed((long)this.delay.getValue())) {
         if (!this.inventorySwap.getValue() || EntityUtil.inInventory()) {
            PlayerEntity var2 = CombatUtil.getClosestEnemy(this.range.getValue());
            if (var2 != null) {
               BlockPos var3 = EntityUtil.getEntityPos(var2, true);
               if (var3.getY() < 320) {
                  if (!this.shouldSkipPlace(var3)) {
                     int var4 = this.getButtonSlot();
                     if (var4 != -1) {
                        int var5 = mc.player.getInventory().selectedSlot;
                        this.doSwap(var4);
                        if (this.movementFix.getValue()) {
                           Direction var6 = BlockUtil.allowAirPlace() ? BlockUtil.getClickSide(var3) : BlockUtil.getPlaceSide(var3, this.placeRange.getValue());
                           if (var6 != null) {
                              Vec3d var7 = var3.toCenterPos()
                                 .add((double)var6.getVector().getX() * 0.5, (double)var6.getVector().getY() * 0.5, (double)var6.getVector().getZ() * 0.5);
                              Rotation var8 = RotationUtils.calculate(var7);
                              MoveUtils.fixMovement(var8.getYaw());
                           }
                        }

                        BlockUtil.placeBlock(var3, true);
                        if (this.inventorySwap.getValue()) {
                           this.doSwap(var4);
                           EntityUtil.syncInventory();
                        } else {
                           this.doSwap(var5);
                        }

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

   private boolean shouldSkipPlace(BlockPos pos) {
      if (!BlockUtil.canReplace(pos)) {
         return true;
      } else {
         if (this.ghostHand.getValue()) {
            if (this.hasEntityIgnoringPlayers(pos)) {
               return true;
            }
         } else if (BlockUtil.hasEntity(pos, false)) {
            return true;
         }

         return this.placeRange.getValue() > 0.0 && mc.player.getEyePos().distanceTo(pos.toCenterPos()) > this.placeRange.getValue()
            ? true
            : BlockUtil.getPlaceSide(pos, this.placeRange.getValue()) == null && !BlockUtil.allowAirPlace();
      }
   }

   private boolean hasEntityIgnoringPlayers(BlockPos pos) {
      for (Entity var3 : BlockUtil.getEntities(new Box(pos))) {
         if (var3 != null
            && var3.isAlive()
            && !(var3 instanceof ItemEntity)
            && !(var3 instanceof ExperienceOrbEntity)
            && !(var3 instanceof ExperienceBottleEntity)
            && !(var3 instanceof ArrowEntity)
            && !(var3 instanceof PlayerEntity)) {
            return true;
         }
      }

      return false;
   }

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

   private int getButtonSlot() {
      return this.inventorySwap.getValue() ? InventoryUtil.findClassInventorySlot(ButtonBlock.class) : InventoryUtil.findClass(ButtonBlock.class);
   }
}
