package net.minecraft.advancements.critereon;

import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import net.minecraft.tags.SerializationTags;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import com.google.gson.JsonElement;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import javax.annotation.Nullable;
import net.minecraft.world.level.block.Block;
import net.minecraft.tags.Tag;

public class BlockPredicate {
    public static final BlockPredicate ANY;
    @Nullable
    private final Tag<Block> tag;
    @Nullable
    private final Block block;
    private final StatePropertiesPredicate properties;
    private final NbtPredicate nbt;
    
    public BlockPredicate(@Nullable final Tag<Block> adf, @Nullable final Block bvr, final StatePropertiesPredicate ck, final NbtPredicate bz) {
        this.tag = adf;
        this.block = bvr;
        this.properties = ck;
        this.nbt = bz;
    }
    
    public boolean matches(final ServerLevel zd, final BlockPos fu) {
        if (this == BlockPredicate.ANY) {
            return true;
        }
        if (!zd.isLoaded(fu)) {
            return false;
        }
        final BlockState cfj4 = zd.getBlockState(fu);
        final Block bvr5 = cfj4.getBlock();
        if (this.tag != null && !this.tag.contains(bvr5)) {
            return false;
        }
        if (this.block != null && bvr5 != this.block) {
            return false;
        }
        if (!this.properties.matches(cfj4)) {
            return false;
        }
        if (this.nbt != NbtPredicate.ANY) {
            final BlockEntity cdl6 = zd.getBlockEntity(fu);
            if (cdl6 == null || !this.nbt.matches(cdl6.save(new CompoundTag()))) {
                return false;
            }
        }
        return true;
    }
    
    public static BlockPredicate fromJson(@Nullable final JsonElement jsonElement) {
        if (jsonElement == null || jsonElement.isJsonNull()) {
            return BlockPredicate.ANY;
        }
        final JsonObject jsonObject2 = GsonHelper.convertToJsonObject(jsonElement, "block");
        final NbtPredicate bz3 = NbtPredicate.fromJson(jsonObject2.get("nbt"));
        Block bvr4 = null;
        if (jsonObject2.has("block")) {
            final ResourceLocation uh5 = new ResourceLocation(GsonHelper.getAsString(jsonObject2, "block"));
            bvr4 = Registry.BLOCK.get(uh5);
        }
        Tag<Block> adf5 = null;
        if (jsonObject2.has("tag")) {
            final ResourceLocation uh6 = new ResourceLocation(GsonHelper.getAsString(jsonObject2, "tag"));
            adf5 = SerializationTags.getInstance().getBlocks().getTag(uh6);
            if (adf5 == null) {
                throw new JsonSyntaxException("Unknown block tag '" + uh6 + "'");
            }
        }
        final StatePropertiesPredicate ck6 = StatePropertiesPredicate.fromJson(jsonObject2.get("state"));
        return new BlockPredicate(adf5, bvr4, ck6, bz3);
    }
    
    public JsonElement serializeToJson() {
        if (this == BlockPredicate.ANY) {
            return JsonNull.INSTANCE;
        }
        final JsonObject jsonObject2 = new JsonObject();
        if (this.block != null) {
            jsonObject2.addProperty("block", Registry.BLOCK.getKey(this.block).toString());
        }
        if (this.tag != null) {
            jsonObject2.addProperty("tag", SerializationTags.getInstance().getBlocks().getIdOrThrow(this.tag).toString());
        }
        jsonObject2.add("nbt", this.nbt.serializeToJson());
        jsonObject2.add("state", this.properties.serializeToJson());
        return jsonObject2;
    }
    
    static {
        ANY = new BlockPredicate(null, null, StatePropertiesPredicate.ANY, NbtPredicate.ANY);
    }
    
    public static class Builder {
        @Nullable
        private Block block;
        @Nullable
        private Tag<Block> blocks;
        private StatePropertiesPredicate properties;
        private NbtPredicate nbt;
        
        private Builder() {
            this.properties = StatePropertiesPredicate.ANY;
            this.nbt = NbtPredicate.ANY;
        }
        
        public static Builder block() {
            return new Builder();
        }
        
        public Builder of(final Block bvr) {
            this.block = bvr;
            return this;
        }
        
        public Builder of(final Tag<Block> adf) {
            this.blocks = adf;
            return this;
        }
        
        public Builder setProperties(final StatePropertiesPredicate ck) {
            this.properties = ck;
            return this;
        }
        
        public BlockPredicate build() {
            return new BlockPredicate(this.blocks, this.block, this.properties, this.nbt);
        }
    }
}
