package net.minecraft.advancements;

import com.google.gson.JsonParseException;
import net.minecraft.util.GsonHelper;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializationContext;
import java.lang.reflect.Type;
import com.google.gson.JsonSerializer;
import com.google.gson.JsonDeserializer;
import java.util.Date;
import java.util.List;
import com.google.common.collect.Lists;
import javax.annotation.Nullable;
import net.minecraft.network.FriendlyByteBuf;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Set;
import com.google.common.collect.Maps;
import java.util.Map;

public class AdvancementProgress implements Comparable<AdvancementProgress> {
    private final Map<String, CriterionProgress> criteria;
    private String[][] requirements;
    
    public AdvancementProgress() {
        this.criteria = Maps.newHashMap();
        this.requirements = new String[0][];
    }
    
    public void update(final Map<String, Criterion> map, final String[][] arr) {
        final Set<String> set4 = map.keySet();
        this.criteria.entrySet().removeIf(entry -> !set4.contains(entry.getKey()));
        for (final String string6 : set4) {
            if (!this.criteria.containsKey(string6)) {
                this.criteria.put(string6, new CriterionProgress());
            }
        }
        this.requirements = arr;
    }
    
    public boolean isDone() {
        if (this.requirements.length == 0) {
            return false;
        }
        for (final String[] arr5 : this.requirements) {
            boolean boolean6 = false;
            for (final String string10 : arr5) {
                final CriterionProgress ac11 = this.getCriterion(string10);
                if (ac11 != null && ac11.isDone()) {
                    boolean6 = true;
                    break;
                }
            }
            if (!boolean6) {
                return false;
            }
        }
        return true;
    }
    
    public boolean hasProgress() {
        for (final CriterionProgress ac3 : this.criteria.values()) {
            if (ac3.isDone()) {
                return true;
            }
        }
        return false;
    }
    
    public boolean grantProgress(final String string) {
        final CriterionProgress ac3 = this.criteria.get(string);
        if (ac3 != null && !ac3.isDone()) {
            ac3.grant();
            return true;
        }
        return false;
    }
    
    public boolean revokeProgress(final String string) {
        final CriterionProgress ac3 = this.criteria.get(string);
        if (ac3 != null && ac3.isDone()) {
            ac3.revoke();
            return true;
        }
        return false;
    }
    
    @Override
    public String toString() {
        return "AdvancementProgress{criteria=" + this.criteria + ", requirements=" + Arrays.deepToString(this.requirements) + '}';
    }
    
    public void serializeToNetwork(final FriendlyByteBuf mg) {
        mg.writeVarInt(this.criteria.size());
        for (final Map.Entry<String, CriterionProgress> entry4 : this.criteria.entrySet()) {
            mg.writeUtf(entry4.getKey());
            entry4.getValue().serializeToNetwork(mg);
        }
    }
    
    public static AdvancementProgress fromNetwork(final FriendlyByteBuf mg) {
        final AdvancementProgress y2 = new AdvancementProgress();
        for (int integer3 = mg.readVarInt(), integer4 = 0; integer4 < integer3; ++integer4) {
            y2.criteria.put(mg.readUtf(32767), CriterionProgress.fromNetwork(mg));
        }
        return y2;
    }
    
    @Nullable
    public CriterionProgress getCriterion(final String string) {
        return this.criteria.get(string);
    }
    
    public float getPercent() {
        if (this.criteria.isEmpty()) {
            return 0.0f;
        }
        final float float2 = (float)this.requirements.length;
        final float float3 = (float)this.countCompletedRequirements();
        return float3 / float2;
    }
    
    @Nullable
    public String getProgressText() {
        if (this.criteria.isEmpty()) {
            return null;
        }
        final int integer2 = this.requirements.length;
        if (integer2 <= 1) {
            return null;
        }
        final int integer3 = this.countCompletedRequirements();
        return integer3 + "/" + integer2;
    }
    
    private int countCompletedRequirements() {
        int integer2 = 0;
        for (final String[] arr6 : this.requirements) {
            boolean boolean7 = false;
            for (final String string11 : arr6) {
                final CriterionProgress ac12 = this.getCriterion(string11);
                if (ac12 != null && ac12.isDone()) {
                    boolean7 = true;
                    break;
                }
            }
            if (boolean7) {
                ++integer2;
            }
        }
        return integer2;
    }
    
    public Iterable<String> getRemainingCriteria() {
        final List<String> list2 = Lists.newArrayList();
        for (final Map.Entry<String, CriterionProgress> entry4 : this.criteria.entrySet()) {
            if (!entry4.getValue().isDone()) {
                list2.add(entry4.getKey());
            }
        }
        return list2;
    }
    
    public Iterable<String> getCompletedCriteria() {
        final List<String> list2 = Lists.newArrayList();
        for (final Map.Entry<String, CriterionProgress> entry4 : this.criteria.entrySet()) {
            if (entry4.getValue().isDone()) {
                list2.add(entry4.getKey());
            }
        }
        return list2;
    }
    
    @Nullable
    public Date getFirstProgressDate() {
        Date date2 = null;
        for (final CriterionProgress ac4 : this.criteria.values()) {
            if (ac4.isDone() && (date2 == null || ac4.getObtained().before(date2))) {
                date2 = ac4.getObtained();
            }
        }
        return date2;
    }
    
    @Override
    public int compareTo(final AdvancementProgress y) {
        final Date date3 = this.getFirstProgressDate();
        final Date date4 = y.getFirstProgressDate();
        if (date3 == null && date4 != null) {
            return 1;
        }
        if (date3 != null && date4 == null) {
            return -1;
        }
        if (date3 == null && date4 == null) {
            return 0;
        }
        return date3.compareTo(date4);
    }
    
    public static class Serializer implements JsonDeserializer<AdvancementProgress>, JsonSerializer<AdvancementProgress> {
        @Override
        public JsonElement serialize(final AdvancementProgress y, final Type type, final JsonSerializationContext jsonSerializationContext) {
            final JsonObject jsonObject5 = new JsonObject();
            final JsonObject jsonObject6 = new JsonObject();
            for (final Map.Entry<String, CriterionProgress> entry8 : y.criteria.entrySet()) {
                final CriterionProgress ac9 = entry8.getValue();
                if (ac9.isDone()) {
                    jsonObject6.add(entry8.getKey(), ac9.serializeToJson());
                }
            }
            if (!jsonObject6.entrySet().isEmpty()) {
                jsonObject5.add("criteria", jsonObject6);
            }
            jsonObject5.addProperty("done", y.isDone());
            return jsonObject5;
        }
        
        @Override
        public AdvancementProgress deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
            final JsonObject jsonObject5 = GsonHelper.convertToJsonObject(jsonElement, "advancement");
            final JsonObject jsonObject6 = GsonHelper.getAsJsonObject(jsonObject5, "criteria", new JsonObject());
            final AdvancementProgress y7 = new AdvancementProgress();
            for (final Map.Entry<String, JsonElement> entry9 : jsonObject6.entrySet()) {
                final String string10 = entry9.getKey();
                y7.criteria.put(string10, CriterionProgress.fromJson(GsonHelper.convertToString(entry9.getValue(), string10)));
            }
            return y7;
        }
    }
}
