package net.minecraft.advancements.critereon;

import java.util.function.Predicate;
import net.minecraft.advancements.CriterionProgress;
import java.util.function.BiConsumer;
import net.minecraft.advancements.AdvancementProgress;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonNull;
import com.google.gson.JsonParseException;
import net.minecraft.core.Registry;
import net.minecraft.stats.StatType;
import com.google.gson.JsonArray;
import com.google.common.collect.Maps;
import javax.annotation.Nullable;
import net.minecraft.advancements.Advancement;
import net.minecraft.server.ServerAdvancementManager;
import net.minecraft.server.PlayerAdvancements;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import net.minecraft.stats.RecipeBook;
import java.util.Iterator;
import net.minecraft.stats.StatsCounter;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import com.google.gson.JsonObject;
import net.minecraft.util.GsonHelper;
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
import com.google.gson.JsonElement;
import net.minecraft.resources.ResourceLocation;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
import net.minecraft.stats.Stat;
import java.util.Map;
import net.minecraft.world.level.GameType;

public class PlayerPredicate {
    public static final PlayerPredicate ANY;
    private final MinMaxBounds.Ints level;
    private final GameType gameType;
    private final Map<Stat<?>, MinMaxBounds.Ints> stats;
    private final Object2BooleanMap<ResourceLocation> recipes;
    private final Map<ResourceLocation, AdvancementPredicate> advancements;
    
    private static AdvancementPredicate advancementPredicateFromJson(final JsonElement jsonElement) {
        if (jsonElement.isJsonPrimitive()) {
            final boolean boolean2 = jsonElement.getAsBoolean();
            return new AdvancementDonePredicate(boolean2);
        }
        final Object2BooleanMap<String> object2BooleanMap2 = (Object2BooleanMap<String>)new Object2BooleanOpenHashMap();
        final JsonObject jsonObject3 = GsonHelper.convertToJsonObject(jsonElement, "criterion data");
        final boolean boolean3;
        final Object2BooleanMap object2BooleanMap3;
        jsonObject3.entrySet().forEach(entry -> {
            boolean3 = GsonHelper.convertToBoolean(entry.getValue(), "criterion test");
            object2BooleanMap3.put(entry.getKey(), boolean3);
            return;
        });
        return new AdvancementCriterionsPredicate(object2BooleanMap2);
    }
    
    private PlayerPredicate(final MinMaxBounds.Ints d, final GameType bjt, final Map<Stat<?>, MinMaxBounds.Ints> map3, final Object2BooleanMap<ResourceLocation> object2BooleanMap, final Map<ResourceLocation, AdvancementPredicate> map5) {
        this.level = d;
        this.gameType = bjt;
        this.stats = map3;
        this.recipes = object2BooleanMap;
        this.advancements = map5;
    }
    
    public boolean matches(final Entity akq) {
        if (this == PlayerPredicate.ANY) {
            return true;
        }
        if (!(akq instanceof ServerPlayer)) {
            return false;
        }
        final ServerPlayer xe3 = (ServerPlayer)akq;
        if (!this.level.matches(xe3.experienceLevel)) {
            return false;
        }
        if (this.gameType != GameType.NOT_SET && this.gameType != xe3.gameMode.getGameModeForPlayer()) {
            return false;
        }
        final StatsCounter aas4 = xe3.getStats();
        for (final Map.Entry<Stat<?>, MinMaxBounds.Ints> entry6 : this.stats.entrySet()) {
            final int integer7 = aas4.getValue(entry6.getKey());
            if (!entry6.getValue().matches(integer7)) {
                return false;
            }
        }
        final RecipeBook aal5 = xe3.getRecipeBook();
        for (final Object2BooleanMap.Entry<ResourceLocation> entry7 : this.recipes.object2BooleanEntrySet()) {
            if (aal5.contains((ResourceLocation)entry7.getKey()) != entry7.getBooleanValue()) {
                return false;
            }
        }
        if (!this.advancements.isEmpty()) {
            final PlayerAdvancements sv6 = xe3.getAdvancements();
            final ServerAdvancementManager sx7 = xe3.getServer().getAdvancements();
            for (final Map.Entry<ResourceLocation, AdvancementPredicate> entry8 : this.advancements.entrySet()) {
                final Advancement u10 = sx7.getAdvancement(entry8.getKey());
                if (u10 == null || !entry8.getValue().test(sv6.getOrStartProgress(u10))) {
                    return false;
                }
            }
        }
        return true;
    }
    
    public static PlayerPredicate fromJson(@Nullable final JsonElement jsonElement) {
        if (jsonElement == null || jsonElement.isJsonNull()) {
            return PlayerPredicate.ANY;
        }
        final JsonObject jsonObject2 = GsonHelper.convertToJsonObject(jsonElement, "player");
        final MinMaxBounds.Ints d3 = MinMaxBounds.Ints.fromJson(jsonObject2.get("level"));
        final String string4 = GsonHelper.getAsString(jsonObject2, "gamemode", "");
        final GameType bjt5 = GameType.byName(string4, GameType.NOT_SET);
        final Map<Stat<?>, MinMaxBounds.Ints> map6 = Maps.newHashMap();
        final JsonArray jsonArray7 = GsonHelper.getAsJsonArray(jsonObject2, "stats", null);
        if (jsonArray7 != null) {
            for (final JsonElement jsonElement2 : jsonArray7) {
                final JsonObject jsonObject3 = GsonHelper.convertToJsonObject(jsonElement2, "stats entry");
                final ResourceLocation sm11 = new ResourceLocation(GsonHelper.getAsString(jsonObject3, "type"));
                final StatType<?> aaq12 = Registry.STAT_TYPE.get(sm11);
                if (aaq12 == null) {
                    throw new JsonParseException("Invalid stat type: " + sm11);
                }
                final ResourceLocation sm12 = new ResourceLocation(GsonHelper.getAsString(jsonObject3, "stat"));
                final Stat<?> aao14 = PlayerPredicate.getStat(aaq12, sm12);
                final MinMaxBounds.Ints d4 = MinMaxBounds.Ints.fromJson(jsonObject3.get("value"));
                map6.put(aao14, d4);
            }
        }
        final Object2BooleanMap<ResourceLocation> object2BooleanMap8 = (Object2BooleanMap<ResourceLocation>)new Object2BooleanOpenHashMap();
        final JsonObject jsonObject4 = GsonHelper.getAsJsonObject(jsonObject2, "recipes", new JsonObject());
        for (final Map.Entry<String, JsonElement> entry11 : jsonObject4.entrySet()) {
            final ResourceLocation sm13 = new ResourceLocation(entry11.getKey());
            final boolean boolean13 = GsonHelper.convertToBoolean(entry11.getValue(), "recipe present");
            object2BooleanMap8.put(sm13, boolean13);
        }
        final Map<ResourceLocation, AdvancementPredicate> map7 = Maps.newHashMap();
        final JsonObject jsonObject5 = GsonHelper.getAsJsonObject(jsonObject2, "advancements", new JsonObject());
        for (final Map.Entry<String, JsonElement> entry12 : jsonObject5.entrySet()) {
            final ResourceLocation sm14 = new ResourceLocation(entry12.getKey());
            final AdvancementPredicate c15 = advancementPredicateFromJson(entry12.getValue());
            map7.put(sm14, c15);
        }
        return new PlayerPredicate(d3, bjt5, map6, object2BooleanMap8, map7);
    }
    
    private static <T> Stat<T> getStat(final StatType<T> aaq, final ResourceLocation sm) {
        final Registry<T> gb3 = aaq.getRegistry();
        final T object4 = gb3.get(sm);
        if (object4 == null) {
            throw new JsonParseException("Unknown object " + sm + " for stat type " + Registry.STAT_TYPE.getKey(aaq));
        }
        return aaq.get(object4);
    }
    
    private static <T> ResourceLocation getStatValueId(final Stat<T> aao) {
        return aao.getType().getRegistry().getKey(aao.getValue());
    }
    
    public JsonElement serializeToJson() {
        if (this == PlayerPredicate.ANY) {
            return JsonNull.INSTANCE;
        }
        final JsonObject jsonObject2 = new JsonObject();
        jsonObject2.add("level", this.level.serializeToJson());
        if (this.gameType != GameType.NOT_SET) {
            jsonObject2.addProperty("gamemode", this.gameType.getName());
        }
        if (!this.stats.isEmpty()) {
            final JsonArray jsonArray3 = new JsonArray();
            final JsonObject jsonObject3;
            final JsonArray jsonArray4;
            this.stats.forEach((aao, d) -> {
                jsonObject3 = new JsonObject();
                jsonObject3.addProperty("type", Registry.STAT_TYPE.getKey(aao.getType()).toString());
                jsonObject3.addProperty("stat", PlayerPredicate.getStatValueId(aao).toString());
                jsonObject3.add("value", d.serializeToJson());
                jsonArray4.add(jsonObject3);
                return;
            });
            jsonObject2.add("stats", jsonArray3);
        }
        if (!this.recipes.isEmpty()) {
            final JsonObject jsonObject4 = new JsonObject();
            this.recipes.forEach((sm, boolean3) -> jsonObject4.addProperty(sm.toString(), boolean3));
            jsonObject2.add("recipes", jsonObject4);
        }
        if (!this.advancements.isEmpty()) {
            final JsonObject jsonObject4 = new JsonObject();
            final JsonObject jsonObject5;
            this.advancements.forEach((sm, c) -> jsonObject5.add(sm.toString(), c.toJson()));
            jsonObject2.add("advancements", jsonObject4);
        }
        return jsonObject2;
    }
    
    static {
        ANY = new Builder().build();
    }
    
    static class AdvancementDonePredicate implements AdvancementPredicate {
        private final boolean state;
        
        public AdvancementDonePredicate(final boolean boolean1) {
            this.state = boolean1;
        }
        
        @Override
        public JsonElement toJson() {
            return new JsonPrimitive(this.state);
        }
        
        @Override
        public boolean test(final AdvancementProgress w) {
            return w.isDone() == this.state;
        }
    }
    
    static class AdvancementCriterionsPredicate implements AdvancementPredicate {
        private final Object2BooleanMap<String> criterions;
        
        public AdvancementCriterionsPredicate(final Object2BooleanMap<String> object2BooleanMap) {
            this.criterions = object2BooleanMap;
        }
        
        @Override
        public JsonElement toJson() {
            final JsonObject jsonObject2 = new JsonObject();
            this.criterions.forEach((BiConsumer)jsonObject2::addProperty);
            return jsonObject2;
        }
        
        @Override
        public boolean test(final AdvancementProgress w) {
            for (final Object2BooleanMap.Entry<String> entry4 : this.criterions.object2BooleanEntrySet()) {
                final CriterionProgress aa5 = w.getCriterion((String)entry4.getKey());
                if (aa5 == null || aa5.isDone() != entry4.getBooleanValue()) {
                    return false;
                }
            }
            return true;
        }
    }
    
    public static class Builder {
        private MinMaxBounds.Ints level;
        private GameType gameType;
        private final Map<Stat<?>, MinMaxBounds.Ints> stats;
        private final Object2BooleanMap<ResourceLocation> recipes;
        private final Map<ResourceLocation, AdvancementPredicate> advancements;
        
        public Builder() {
            this.level = MinMaxBounds.Ints.ANY;
            this.gameType = GameType.NOT_SET;
            this.stats = Maps.newHashMap();
            this.recipes = (Object2BooleanMap<ResourceLocation>)new Object2BooleanOpenHashMap();
            this.advancements = Maps.newHashMap();
        }
        
        public PlayerPredicate build() {
            return new PlayerPredicate(this.level, this.gameType, this.stats, this.recipes, this.advancements, null);
        }
    }
    
    interface AdvancementPredicate extends Predicate<AdvancementProgress> {
        JsonElement toJson();
    }
}
