package net.minecraft.tags;

import net.minecraft.world.level.block.Blocks;
import com.google.common.collect.Multimap;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import com.google.common.collect.HashMultimap;
import net.minecraft.resources.ResourceLocation;
import java.util.Map;
import java.util.concurrent.CompletionStage;
import java.util.function.Function;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.core.Registry;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.server.packs.resources.PreparableReloadListener;

public class TagManager implements PreparableReloadListener {
    private final SynchronizableTagCollection<Block> blocks;
    private final SynchronizableTagCollection<Item> items;
    private final SynchronizableTagCollection<Fluid> fluids;
    private final SynchronizableTagCollection<EntityType<?>> entityTypes;
    
    public TagManager() {
        this.blocks = new SynchronizableTagCollection<Block>(Registry.BLOCK, "tags/blocks", "block");
        this.items = new SynchronizableTagCollection<Item>(Registry.ITEM, "tags/items", "item");
        this.fluids = new SynchronizableTagCollection<Fluid>(Registry.FLUID, "tags/fluids", "fluid");
        this.entityTypes = new SynchronizableTagCollection<EntityType<?>>(Registry.ENTITY_TYPE, "tags/entity_types", "entity_type");
    }
    
    public SynchronizableTagCollection<Block> getBlocks() {
        return this.blocks;
    }
    
    public SynchronizableTagCollection<Item> getItems() {
        return this.items;
    }
    
    public SynchronizableTagCollection<Fluid> getFluids() {
        return this.fluids;
    }
    
    public SynchronizableTagCollection<EntityType<?>> getEntityTypes() {
        return this.entityTypes;
    }
    
    public void serializeToNetwork(final FriendlyByteBuf mg) {
        this.blocks.serializeToNetwork(mg);
        this.items.serializeToNetwork(mg);
        this.fluids.serializeToNetwork(mg);
        this.entityTypes.serializeToNetwork(mg);
    }
    
    public static TagManager deserializeFromNetwork(final FriendlyByteBuf mg) {
        final TagManager adh2 = new TagManager();
        adh2.getBlocks().loadFromNetwork(mg);
        adh2.getItems().loadFromNetwork(mg);
        adh2.getFluids().loadFromNetwork(mg);
        adh2.getEntityTypes().loadFromNetwork(mg);
        return adh2;
    }
    
    @Override
    public CompletableFuture<Void> reload(final PreparationBarrier a, final ResourceManager abc, final ProfilerFiller ami3, final ProfilerFiller ami4, final Executor executor5, final Executor executor6) {
        final CompletableFuture<Map<ResourceLocation, Tag.Builder>> completableFuture8 = this.blocks.prepare(abc, executor5);
        final CompletableFuture<Map<ResourceLocation, Tag.Builder>> completableFuture9 = this.items.prepare(abc, executor5);
        final CompletableFuture<Map<ResourceLocation, Tag.Builder>> completableFuture10 = this.fluids.prepare(abc, executor5);
        final CompletableFuture<Map<ResourceLocation, Tag.Builder>> completableFuture11 = this.entityTypes.prepare(abc, executor5);
        final CompletableFuture<Map<ResourceLocation, Tag.Builder>> completableFuture12;
        final CompletableFuture<Map<ResourceLocation, Tag.Builder>> completableFuture13;
        final CompletableFuture<Map<ResourceLocation, Tag.Builder>> completableFuture14;
        final CompletableFuture<Map<ResourceLocation, Tag.Builder>> completableFuture15;
        final Multimap<String, ResourceLocation> multimap7;
        final IllegalStateException ex;
        return CompletableFuture.allOf(completableFuture8, completableFuture9, completableFuture10, completableFuture11).thenCompose(a::wait).thenAcceptAsync(void5 -> {
            this.blocks.load(completableFuture12.join());
            this.items.load(completableFuture13.join());
            this.fluids.load(completableFuture14.join());
            this.entityTypes.load(completableFuture15.join());
            SerializationTags.bind(this.blocks, this.items, this.fluids, this.entityTypes);
            multimap7 = HashMultimap.create();
            multimap7.putAll("blocks", BlockTags.getMissingTags(this.blocks));
            multimap7.putAll("items", ItemTags.getMissingTags(this.items));
            multimap7.putAll("fluids", FluidTags.getMissingTags(this.fluids));
            multimap7.putAll("entity_types", EntityTypeTags.getMissingTags(this.entityTypes));
            if (!multimap7.isEmpty()) {
                new IllegalStateException("Missing required tags: " + multimap7.entries().stream().map(entry -> entry.getKey() + ":" + entry.getValue()).sorted().collect(Collectors.joining(",")));
                throw ex;
            }
        }, executor6);
    }
    
    public void bindToGlobal() {
        BlockTags.reset(this.blocks);
        ItemTags.reset(this.items);
        FluidTags.reset(this.fluids);
        EntityTypeTags.reset(this.entityTypes);
        Blocks.rebuildCache();
    }
}
