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

import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.Entity;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.core.event.CommonEventHandler;
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;
import java.util.function.Supplier;

/**
 * The type Sync nbt data s 2 c payload.
 */
@SuppressWarnings("unused")
public record SyncNBTCapDataEntityS2CPayload(int entityId, Identifier id, CompoundTag data) implements CustomPacketPayload {
    /**
     * The constant SYNC_NBT_CAP_PACKET_ID.
     */
    public static final Identifier SYNC_NBT_CAP_PACKET_ID =
            Lib39.rl("sync_nbt_cap_data_entity");
    /**
     * The constant TYPE.
     */
    public static final Type<SyncNBTCapDataEntityS2CPayload> TYPE = new Type<>(SYNC_NBT_CAP_PACKET_ID);

    /**
     * The constant STREAM_CODEC.
     */
    public static final StreamCodec<RegistryFriendlyByteBuf, SyncNBTCapDataEntityS2CPayload> STREAM_CODEC =
            StreamCodec.ofMember(SyncNBTCapDataEntityS2CPayload::encode, SyncNBTCapDataEntityS2CPayload::decode);

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

    /**
     * Encode.
     *
     * @param msg    the msg
     * @param buffer the buffer
     */
    public static void encode(@NotNull SyncNBTCapDataEntityS2CPayload msg, @NotNull FriendlyByteBuf buffer) {
        buffer.writeInt(msg.entityId);
        buffer.writeIdentifier(msg.id);
        buffer.writeNbt(msg.data);
    }

    /**
     * Decode sync nbt data s 2 c pack.
     *
     * @param buffer the buffer
     * @return the sync nbt data s 2 c pack
     */
    @Contract("_ -> new")
    public static @NotNull SyncNBTCapDataEntityS2CPayload decode(@NotNull FriendlyByteBuf buffer) {
        return new SyncNBTCapDataEntityS2CPayload(buffer.readInt(), buffer.readIdentifier(), buffer.readNbt());
    }

    /**
     * Handle.
     *
     * @param payload the msg
     * @param context the context
     */
    public static void handle(SyncNBTCapDataEntityS2CPayload payload, @NotNull IPayloadContext context) {
        context.enqueueWork(() -> {
            ClientLevel level = Minecraft.getInstance().level;
            if (level != null) {
                Entity entity = level.getEntity(payload.entityId);
                if (entity != null) {
                    Optional<SyncData2Manager.DataProvider<Entity, ISyncData<?>>> capOpt =
                            CommonEventHandler.Game
                                    .getSyncData2Manager()
                                    .getDataProvider(payload.id);
                    capOpt.flatMap(dataProvider -> dataProvider.getData(entity))
                            .ifPresent(cap -> {
                                if (cap instanceof NBTEntitySyncData nbtCap) {
                                    CompoundTag current = nbtCap.serializeNBT();
                                    if (!current.equals(payload.data)) {
                                        nbtCap.deserializeNBT(payload.data);
                                    }
                                } else Lib39.LOGGER.debug("Unhandled sync data: {}", payload.data);
                            }
                    );
                }
            }
        });
    }

    @Override
    public Type<? extends CustomPacketPayload> type() {
        return TYPE;
    }
}
