package top.r3944realms.lib39.core.network.toClient;

import net.fabricmc.fabric.api.networking.v1.FabricPacket;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.PacketType;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.core.event.FabricCommonEventHandler;
import top.r3944realms.lib39.core.sync.ISyncData;
import top.r3944realms.lib39.core.sync.NBTEntitySyncData;
import top.r3944realms.lib39.core.sync.SyncData2Manager;

import java.util.Optional;

/**
 * The type Sync nbt lookup data entity s 2 c packet.
 */
public record SyncNBTLookupDataEntityS2CPacket(int entityId, ResourceLocation id, CompoundTag data) implements FabricPacket {
    /**
     * The constant SYNC_NBT_LOOKUP_PACKET_ID.
     */
    public static final ResourceLocation SYNC_NBT_LOOKUP_PACKET_ID =
            Lib39.rl("sync_nbt_lookup_data_entity");
    /**
     * The constant TYPE.
     */
    public static final PacketType<SyncNBTLookupDataEntityS2CPacket> TYPE = PacketType.create(
            SYNC_NBT_LOOKUP_PACKET_ID,
            buf -> new SyncNBTLookupDataEntityS2CPacket(buf.readInt(), buf.readResourceLocation(), buf.readNbt())
    );

    /**
     * Instantiates a new Sync nbt data s 2 c pack.
     *
     * @param entityId the entity id
     * @param data     the data
     */
    public SyncNBTLookupDataEntityS2CPacket(int entityId, @NotNull NBTEntitySyncData data) {
        this(entityId, data.id(), data.serializeNBT());
    }

    @Override
    public void write(@NotNull FriendlyByteBuf friendlyByteBuf) {
        friendlyByteBuf.writeInt(entityId);
        friendlyByteBuf.writeResourceLocation(id);
        friendlyByteBuf.writeNbt(data);
    }

    @Contract(value = " -> new", pure = true)
    @Override
    public @NotNull PacketType<?> getType() {
        return TYPE;
    }


    /**
     * Receive.
     *
     * @param packet       the packet
     * @param localPlayer  the local player
     * @param packetSender the packet sender
     */
    public static void receive(@NotNull SyncNBTLookupDataEntityS2CPacket packet, @NotNull LocalPlayer localPlayer, PacketSender packetSender) {
        Level level = localPlayer.level();
        Entity entity = level.getEntity(packet.entityId);
        if (entity != null) {
            Optional<SyncData2Manager.DataProvider<Entity, ISyncData<?>>> lookupOpt =
                    FabricCommonEventHandler
                            .getSyncData2Manager()
                            .getDataProvider(packet.id);
            lookupOpt.flatMap(dataProvider -> dataProvider.getData(entity))
                    .ifPresent(lookup -> {
                                if (lookup instanceof NBTEntitySyncData nbtLookup) {
                                    CompoundTag current = nbtLookup.serializeNBT();
                                    if (!current.equals(packet.data)) {
                                        nbtLookup.deserializeNBT(packet.data);
                                    }
                                } else Lib39.LOGGER.debug("Unhandled sync data: {}", packet.data);
                            }
                    );

        }
    }
}
