package com.thebrokenrail.gestus.mixin;

import com.thebrokenrail.gestus.entity.FakePlayerEntity;
import com.thebrokenrail.gestus.util.Util;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.Packet;
import net.minecraft.network.packet.s2c.play.EntityEquipmentUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ServerPlayNetworkHandler.class)
public class MixinServerPlayNetworkHandler {
    @Shadow
    public ServerPlayerEntity player;

    @Inject(at = @At("HEAD"), method = "sendPacket(Lnet/minecraft/network/Packet;Lio/netty/util/concurrent/GenericFutureListener;)V", cancellable = true)
    public void sendPacket(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> listener, CallbackInfo info) {
        if (packet instanceof MobSpawnS2CPacket) {
            MobSpawnS2CPacketAccessor packetData = (MobSpawnS2CPacketAccessor) packet;
            Entity entity = player.getEntityWorld().getEntityById(packetData.getId());
            if (entity instanceof FakePlayerEntity && ((FakePlayerEntity) entity).player.getUuid().equals(player.getUuid())) {
                info.cancel();
            }
        }
    }

    @Unique
    private boolean shouldModify(int id) {
        return player.getEntityWorld().getEntityById(id) instanceof PlayerEntity && id != player.getEntityId();
    }

    @ModifyVariable(at = @At("HEAD"), method = "sendPacket(Lnet/minecraft/network/Packet;Lio/netty/util/concurrent/GenericFutureListener;)V", argsOnly = true)
    public Packet<?> modifyPacket(Packet<?> packet) {
        if (packet instanceof EntityTrackerUpdateS2CPacket && shouldModify(((EntityTrackerUpdateS2CPacketAccessor) packet).getId())) {
            return Util.modifyTracker(player, (EntityTrackerUpdateS2CPacket) packet);
        } else if (packet instanceof EntityEquipmentUpdateS2CPacket && shouldModify(((EntityEquipmentUpdateS2CPacketAccessor) packet).getId())) {
            return Util.modifyEquipment((EntityEquipmentUpdateS2CPacket) packet);
        } else {
            return packet;
        }
    }
}
