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

import asm.accessors.IExplosionS2CPacket;
import com.mojang.authlib.GameProfile;
import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.PacketEvent;
import dev.crucifixbeta.api.events.impl.UpdateEvent;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.settings.impl.BindSetting;
import dev.crucifixbeta.mod.modules.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.ColorSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import java.awt.Color;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.network.OtherClientPlayerEntity;
import net.minecraft.entity.Entity.RemovalReason;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.common.KeepAliveC2SPacket;
import net.minecraft.network.packet.c2s.play.AdvancementTabC2SPacket;
import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket;
import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket;
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket;
import net.minecraft.network.packet.c2s.play.ClientStatusC2SPacket;
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket;
import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
import net.minecraft.network.packet.c2s.play.TeleportConfirmC2SPacket;
import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.ExplosionS2CPacket;
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public class Blink extends Module {
   public static Blink INSTANCE;
   public static OtherClientPlayerEntity fakePlayer;
   final CopyOnWriteArrayList<Packet<?>> packetsList = new CopyOnWriteArrayList<>();
   public final BooleanSetting render = this.add(new BooleanSetting("Render", true));
   public final BooleanSetting pauseModule = this.add(new BooleanSetting("PauseModule", true));
   public final BooleanSetting lagbackCheck = this.add(new BooleanSetting("LagbackCheck", true));
   private final BooleanSetting onlyMove = this.add(new BooleanSetting("OnlyMove", true));
   private final BooleanSetting velocity = this.add(new BooleanSetting("Velocity", false));
   private final BooleanSetting limitPackets = this.add(new BooleanSetting("LimitPackets", false));
   private final SliderSetting maxPackets = this.add(new SliderSetting("MaxPackets", 60.0, 0.0, 200.0, this.limitPackets::getValue));
   private final BooleanSetting pulse = this.add(new BooleanSetting("Pulse", false));
   private final SliderSetting factor = this.add(new SliderSetting("Factor", 1.0, 0.0, 10.0, this.pulse::getValue));
   public final BooleanSetting indicator = this.add(new BooleanSetting("Indicator", true).setParent());
   private final ColorSetting color = this.add(new ColorSetting("Color", new Color(255, 255, 255, 255), this.indicator::isOpen));
   private final SliderSetting yOffset = this.add(new SliderSetting("YOffset", 0, -200, 200, this.indicator::isOpen));
   final BindSetting cancel = this.add(new BindSetting("Cancel", -1));
   private boolean blinking;
   private Vec3d start;
   private float startYaw;
   private float startPitch;

   public Blink() {
      super("Blink", Module.Category.Exploit);
      this.setChinese("\u77ac\u79fb");
      INSTANCE = this;
   }

   @Override
   public void onRender2D(DrawContext drawContext, float tickDelta) {
      if (this.indicator.getValue()) {
         String var3 = "Blinking.. (" + this.packetsList.size() + ")";
         TextRenderer var4 = mc.textRenderer;
         int var5 = mc.getWindow().getScaledWidth() / 2 - mc.textRenderer.getWidth(var3) / 2;
         int var6 = mc.getWindow().getScaledHeight() / 2;
         Objects.requireNonNull(mc.textRenderer);
         drawContext.drawText(var4, var3, var5, var6 + 9 - this.yOffset.getValueInt(), this.color.getValue().getRGB(), false);
      }
   }

   @EventListener
   public void onReceivePacket(PacketEvent.Receive event) {
      if (!nullCheck() && this.velocity.getValue()) {
         if (event.getPacket() instanceof ExplosionS2CPacket var3) {
            IExplosionS2CPacket var4 = (IExplosionS2CPacket)var3;
            var4.setVelocityX(0.0F);
            var4.setVelocityY(0.0F);
            var4.setVelocityZ(0.0F);
         } else {
            Packet var6 = event.getPacket();
            EntityVelocityUpdateS2CPacket var5;
            if (var6 instanceof EntityVelocityUpdateS2CPacket && (var5 = (EntityVelocityUpdateS2CPacket)var6).getEntityId() == mc.player.getId()) {
               event.cancel();
            }
         }
      }
   }

   @Override
   public void onEnable() {
      this.packetsList.clear();
      if (nullCheck()) {
         this.disable();
      } else {
         this.start = mc.player.getPos();
         this.startYaw = mc.player.getYaw();
         this.startPitch = mc.player.getPitch();
         if (this.render.getValue()) {
            fakePlayer = new OtherClientPlayerEntity(mc.world, new GameProfile(UUID.fromString("11451466-6666-6666-6666-666666666601"), mc.player.getName().getString()));
            fakePlayer.copyPositionAndRotation(mc.player);
            fakePlayer.bodyYaw = mc.player.bodyYaw;
            fakePlayer.headYaw = mc.player.headYaw;
            fakePlayer.getInventory().clone(mc.player.getInventory());
            mc.world.addEntity(fakePlayer);
         }
      }
   }

   @EventListener
   public void onUpdate(UpdateEvent event) {
      if (mc.player.isDead()) {
         this.packetsList.clear();
         this.disable();
      } else if (this.cancel.isPressed()) {
         this.cancel();
      } else if (this.limitPackets.getValue() && (double)this.packetsList.size() > this.maxPackets.getValue()) {
         this.cancel();
      } else {
         if (this.pulse.getValue() && (double)this.packetsList.size() > this.factor.getValue() * 10.0) {
            this.blinking = true;

            for (Packet var3 : this.packetsList) {
               mc.getNetworkHandler().sendPacket(var3);
            }

            this.packetsList.clear();
            if (fakePlayer != null) {
               fakePlayer.copyPositionAndRotation(mc.player);
               fakePlayer.setHeadYaw(mc.player.headYaw);
               fakePlayer.setBodyYaw(mc.player.bodyYaw);
            }

            this.blinking = false;
         }
      }
   }

   @Override
   public void onLogin() {
      if (this.isOn()) {
         this.packetsList.clear();
         this.disable();
      }
   }

   @EventListener
   public void onSendPacket(PacketEvent.Send event) {
      if (!this.blinking) {
         Packet var2 = event.getPacket();
         if (!(var2 instanceof ChatMessageC2SPacket)) {
            if (!(var2 instanceof RequestCommandCompletionsC2SPacket)) {
               if (!(var2 instanceof CommandExecutionC2SPacket)) {
                  if (!(var2 instanceof TeleportConfirmC2SPacket)) {
                     if (!(var2 instanceof KeepAliveC2SPacket)) {
                        if (!(var2 instanceof AdvancementTabC2SPacket)) {
                           if (!(var2 instanceof ClientStatusC2SPacket)) {
                              if (!(var2 instanceof ClickSlotC2SPacket)) {
                                 if (!this.onlyMove.getValue()
                                       && (
                                          event.getPacket() instanceof PlayerActionC2SPacket
                                             || event.getPacket() instanceof ClientCommandC2SPacket
                                             || event.getPacket() instanceof HandSwingC2SPacket
                                             || event.getPacket() instanceof PlayerInteractEntityC2SPacket
                                             || event.getPacket() instanceof PlayerInteractBlockC2SPacket
                                             || event.getPacket() instanceof PlayerInteractItemC2SPacket
                                       )
                                    || event.getPacket() instanceof PlayerMoveC2SPacket) {
                                    event.cancel();
                                    this.packetsList.add(event.getPacket());
                                 }
                              }
                           }
                        }
                     }
                  }
               }
            }
         }
      }
   }

   @EventListener
   public void onPacketEvent(PacketEvent.Receive event) {
      if (this.lagbackCheck.getValue() && event.getPacket() instanceof PlayerPositionLookS2CPacket) {
         this.cancel();
      }
   }

   private void cancel() {
      mc.player.setPosition(this.start);
      mc.player.setYaw(this.startYaw);
      mc.player.setPitch(this.startPitch);
      this.packetsList.clear();
      this.disable();
   }

   @Override
   public void onDisable() {
      if (nullCheck()) {
         this.packetsList.clear();
         this.disable();
      } else {
         if (fakePlayer != null) {
            fakePlayer.kill();
            fakePlayer.setRemoved(RemovalReason.KILLED);
            fakePlayer.onRemoved();
            fakePlayer = null;
         }

         for (Packet var2 : this.packetsList) {
            mc.getNetworkHandler().sendPacket(var2);
         }
      }
   }

   @Override
   public String getInfo() {
      return String.valueOf(this.packetsList.size());
   }
}
