package asm.mixins;

import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.impl.PacketEvent;
import dev.crucifixbeta.core.impl.CommandManager;
import dev.crucifixbeta.mod.modules.impl.client.ClientSetting;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.timeout.TimeoutException;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.handler.PacketEncoderException;
import net.minecraft.network.listener.PacketListener;
import net.minecraft.network.packet.Packet;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Environment(EnvType.CLIENT)
@Mixin({ClientConnection.class})
public class MixinClientConnection {
   @Inject(
      at = {@At("HEAD")},
      method = {"handlePacket"},
      cancellable = true
   )
   private static <T extends PacketListener> void onHandlePacket(Packet<T> packet, PacketListener listener, CallbackInfo ci) {
      PacketEvent.Receive var3 = new PacketEvent.Receive(packet);
      CrucifixBeta.EVENT_BUS.post(var3);
      if (var3.isCancelled()) {
         ci.cancel();
      }
   }

   @Inject(
      method = {"send(Lnet/minecraft/network/packet/Packet;)V"},
      at = {@At("HEAD")},
      cancellable = true
   )
   private void onSendPacketPre(Packet<?> packet, CallbackInfo info) {
      PacketEvent.Send var3 = new PacketEvent.Send(packet);
      CrucifixBeta.EVENT_BUS.post(var3);
      if (var3.isCancelled()) {
         info.cancel();
      }
   }

   @Inject(
      method = {"send(Lnet/minecraft/network/packet/Packet;)V"},
      at = {@At("RETURN")}
   )
   private void onSendPacketPost(Packet<?> packet, CallbackInfo info) {
      PacketEvent.Sent var3 = new PacketEvent.Sent(packet);
      CrucifixBeta.EVENT_BUS.post(var3);
   }

   @Inject(
      method = {"exceptionCaught"},
      at = {@At("HEAD")},
      cancellable = true
   )
   private void exceptionCaught(ChannelHandlerContext context, Throwable throwable, CallbackInfo ci) {
      if (isMalformedPortedSpearChat(throwable)) {
         ci.cancel();
      } else {
         if (!(throwable instanceof TimeoutException) && !(throwable instanceof PacketEncoderException) && ClientSetting.INSTANCE.caughtException.getValue()) {
            if (ClientSetting.INSTANCE.log.getValue()) {
               CommandManager.sendMessage("§4Caught exception §7" + throwable.getMessage());
            }

            ci.cancel();
         }
      }
   }

   private static boolean isMalformedPortedSpearChat(Throwable throwable) {
      if (!(throwable instanceof DecoderException)) {
         return false;
      } else {
         boolean var1 = false;
         boolean var2 = false;

         for (Throwable var3 = throwable; var3 != null; var3 = var3.getCause()) {
            String var4 = var3.getMessage();
            if (var4 != null) {
               var1 |= var4.contains("clientbound/minecraft:system_chat");
               var2 |= var4.contains("minecraft:lunge") || var4.contains("was speared") || var4.contains("spear");
            }
         }

         return var1 && var2;
      }
   }
}
