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

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.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.SliderSetting;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Blocks;
import net.minecraft.entity.Entity;
import net.minecraft.entity.ExperienceOrbEntity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.decoration.EndCrystalEntity;
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;

@Environment(EnvType.CLIENT)
public class Flatten extends Module {
   public static Flatten INSTANCE;
   private final BooleanSetting rotate = this.add(new BooleanSetting("Rotate", true));
   private final BooleanSetting checkMine = this.add(new BooleanSetting("DetectMining", true));
   private final BooleanSetting inventory = this.add(new BooleanSetting("InventorySwap", true));
   private final BooleanSetting usingPause = this.add(new BooleanSetting("UsingPause", true));
   private final BooleanSetting cover = this.add(new BooleanSetting("Cover", false));
   private final SliderSetting blocksPer = this.add(new SliderSetting("BlocksPer", 2, 1, 8));
   private final SliderSetting delay = this.add(new SliderSetting("Delay", 100, 0, 1000));
   private final Timer timer = new Timer();
   int progress = 0;

   public Flatten() {
      super("Flatten", Module.Category.Movement);
      this.setChinese("\u586b\u5e73\u811a\u4e0b");
      INSTANCE = this;
   }

   @EventListener
   public void onUpdate(UpdateEvent event) {
      this.progress = 0;
      if (!this.inventory.getValue() || EntityUtil.inInventory()) {
         if (!Blink.INSTANCE.isOn() || !Blink.INSTANCE.pauseModule.getValue()) {
            if (!this.usingPause.getValue() || !mc.player.isUsingItem()) {
               if (mc.player.isOnGround()) {
                  if (this.timer.passed((long)this.delay.getValueInt())) {
                     int var2 = mc.player.getInventory().selectedSlot;
                     int var3 = this.getBlock();
                     if (var3 != -1) {
                        if (EntityUtil.isInsideBlock()) {
                           BlockPos var4 = new BlockPosX(mc.player.getX() + 0.5, mc.player.getY() + 0.5, mc.player.getZ() + 0.5).down();
                           BlockPos var5 = new BlockPosX(mc.player.getX() - 0.5, mc.player.getY() + 0.5, mc.player.getZ() + 0.5).down();
                           BlockPos var6 = new BlockPosX(mc.player.getX() + 0.5, mc.player.getY() + 0.5, mc.player.getZ() - 0.5).down();
                           BlockPos var7 = new BlockPosX(mc.player.getX() - 0.5, mc.player.getY() + 0.5, mc.player.getZ() - 0.5).down();
                           if (this.canPlace(var4) || this.canPlace(var5) || this.canPlace(var6) || this.canPlace(var7)) {
                              CombatUtil.attackCrystal(var4, this.rotate.getValue(), this.usingPause.getValue());
                              CombatUtil.attackCrystal(var5, this.rotate.getValue(), this.usingPause.getValue());
                              CombatUtil.attackCrystal(var6, this.rotate.getValue(), this.usingPause.getValue());
                              CombatUtil.attackCrystal(var7, this.rotate.getValue(), this.usingPause.getValue());
                              this.doSwap(var3);
                              this.tryPlaceObsidian(var4, this.rotate.getValue());
                              this.tryPlaceObsidian(var5, this.rotate.getValue());
                              this.tryPlaceObsidian(var6, this.rotate.getValue());
                              this.tryPlaceObsidian(var7, this.rotate.getValue());
                              if (this.inventory.getValue()) {
                                 this.doSwap(var3);
                                 EntityUtil.syncInventory();
                              } else {
                                 this.doSwap(var2);
                              }
                           }
                        }
                     }
                  }
               }
            }
         }
      }
   }

   private void tryPlaceObsidian(BlockPos pos, boolean rotate) {
      if (this.canPlace(pos)) {
         if (!((double)this.progress < this.blocksPer.getValue())) {
            return;
         }

         if (BlockUtil.allowAirPlace()) {
            BlockUtil.placedPos.add(pos);
            BlockUtil.airPlace(pos, rotate);
            this.timer.reset();
            this.progress++;
            return;
         }

         Direction var3 = BlockUtil.getPlaceSide(pos);
         if (var3 == null) {
            return;
         }

         this.progress++;
         BlockUtil.placedPos.add(pos);
         BlockUtil.clickBlock(pos.offset(var3), var3.getOpposite(), rotate);
         this.timer.reset();
      }
   }

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

   private boolean canPlace(BlockPos pos) {
      if (this.checkMine.getValue() && CrucifixBeta.BREAK.isMining(pos)) {
         return false;
      } else if (this.cover.getValue() && mc.world.isAir(pos.up())) {
         return false;
      } else if (BlockUtil.getPlaceSide(pos) == null) {
         return false;
      } else {
         return !BlockUtil.canReplace(pos) ? false : !this.hasEntity(pos);
      }
   }

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

      return false;
   }

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