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

import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.MoveEvent;
import dev.crucifixbeta.api.events.impl.PacketEvent;
import dev.crucifixbeta.api.events.impl.UpdateEvent;
import dev.crucifixbeta.api.utils.render.Render3DUtil;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.settings.impl.BindSetting;
import dev.crucifixbeta.mod.modules.settings.impl.ColorSetting;
import java.awt.Color;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.Items;
import net.minecraft.network.listener.ClientPlayPacketListener;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.Full;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.LookAndOnGround;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.OnGroundOnly;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.PositionAndOnGround;
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public class ChorusControl extends Module {
   final BindSetting confirm = this.add(new BindSetting("Confirm", -1));
   private final ColorSetting color = this.add(new ColorSetting("Color", new Color(255, 255, 255, 100)));
   Vec3d chorusPos = null;
   PlayerPositionLookS2CPacket chorusPacket = null;
   boolean isEatingChorus = false;
   int chorusTicks = 0;

   public ChorusControl() {
      super("ChorusControl", Module.Category.Exploit);
      this.setChinese("\u7d2b\u9882\u679c\u63a7\u5236");
   }

   @Override
   public void onDisable() {
      if (this.chorusPacket != null) {
         this.chorusPacket.apply((ClientPlayPacketListener)mc.getNetworkHandler());
         this.reset();
      }
   }

   private void reset() {
      this.chorusPacket = null;
      this.chorusPos = null;
   }

   @EventListener(
      priority = -200
   )
   public void onMove(MoveEvent event) {
      if (this.chorusPacket != null) {
         event.setX(0.0);
         event.setY(0.0);
         event.setZ(0.0);
      }
   }

   @Override
   public void onRender3D(MatrixStack matrixStack) {
      if (this.chorusPos != null) {
         Render3DUtil.drawFill(
            matrixStack,
            new Box(
               this.chorusPos.getX() - 0.3,
               this.chorusPos.getY(),
               this.chorusPacket.getZ() - 0.3,
               this.chorusPos.getX() + 0.3,
               this.chorusPos.getY() + 1.85,
               this.chorusPos.getZ() + 0.3
            ),
            this.color.getValue()
         );
      }
   }

   @EventListener
   public void onUpdate(UpdateEvent event) {
      if (mc.player.getActiveItem() != null) {
         if (mc.player.getActiveItem().getItem() == Items.CHORUS_FRUIT) {
            this.isEatingChorus = true;
         } else if (this.isEatingChorus) {
            this.chorusTicks++;
            if (this.chorusTicks > 5) {
               this.isEatingChorus = false;
               this.chorusTicks = 0;
            }
         }

         if (this.confirm.isPressed() && this.chorusPacket != null) {
            this.chorusPacket.apply((ClientPlayPacketListener)mc.getNetworkHandler());
            this.reset();
         }
      }
   }

   @EventListener
   public void onPacketReceive(PacketEvent.Receive e) {
      if (e.getPacket() instanceof PlayerPositionLookS2CPacket var3 && (this.isEatingChorus || this.chorusPos != null)) {
         this.chorusPacket = var3;
         this.chorusPos = new Vec3d(this.chorusPacket.getX(), this.chorusPacket.getY(), this.chorusPacket.getZ());
         e.cancel();
      }
   }

   @EventListener
   public void onPacketSend(PacketEvent.Send e) {
      if (this.chorusPacket != null
         && (
            e.getPacket() instanceof PlayerMoveC2SPacket
               || e.getPacket() instanceof Full
               || e.getPacket() instanceof LookAndOnGround
               || e.getPacket() instanceof OnGroundOnly
               || e.getPacket() instanceof PositionAndOnGround
         )) {
         e.cancel();
      }
   }
}
