package net.minecraft.world.level.storage.loot;

import org.apache.commons.lang3.ArrayUtils;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonParseException;
import com.google.gson.JsonObject;
import net.minecraft.util.GsonHelper;
import com.google.gson.JsonDeserializationContext;
import java.lang.reflect.Type;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializer;
import com.google.gson.JsonDeserializer;
import net.minecraft.world.level.storage.loot.predicates.ConditionUserBuilder;
import net.minecraft.world.level.storage.loot.functions.FunctionUserBuilder;
import net.minecraft.util.Mth;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import net.minecraft.world.level.storage.loot.entries.LootPoolEntry;
import org.apache.commons.lang3.mutable.MutableInt;
import com.google.common.collect.Lists;
import java.util.function.Consumer;
import net.minecraft.world.level.storage.loot.functions.LootItemFunctions;
import net.minecraft.world.level.storage.loot.predicates.LootItemConditions;
import net.minecraft.world.item.ItemStack;
import java.util.function.BiFunction;
import net.minecraft.world.level.storage.loot.functions.LootItemFunction;
import java.util.function.Predicate;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer;

public class LootPool {
    private final LootPoolEntryContainer[] entries;
    private final LootItemCondition[] conditions;
    private final Predicate<LootContext> compositeCondition;
    private final LootItemFunction[] functions;
    private final BiFunction<ItemStack, LootContext, ItemStack> compositeFunction;
    private final RandomIntGenerator rolls;
    private final RandomValueBounds bonusRolls;
    
    private LootPool(final LootPoolEntryContainer[] arr, final LootItemCondition[] arr, final LootItemFunction[] arr, final RandomIntGenerator daz, final RandomValueBounds dbb) {
        this.entries = arr;
        this.conditions = arr;
        this.compositeCondition = LootItemConditions.<LootContext>andConditions(arr);
        this.functions = arr;
        this.compositeFunction = LootItemFunctions.compose(arr);
        this.rolls = daz;
        this.bonusRolls = dbb;
    }
    
    private void addRandomItem(final Consumer<ItemStack> consumer, final LootContext dat) {
        final Random random4 = dat.getRandom();
        final List<LootPoolEntry> list5 = Lists.newArrayList();
        final MutableInt mutableInt6 = new MutableInt();
        for (final LootPoolEntryContainer dbo10 : this.entries) {
            final int integer5;
            final List<LootPoolEntry> list6;
            final MutableInt mutableInt7;
            dbo10.expand(dat, dbn -> {
                integer5 = dbn.getWeight(dat.getLuck());
                if (integer5 > 0) {
                    list6.add(dbn);
                    mutableInt7.add(integer5);
                }
                return;
            });
        }
        final int integer6 = list5.size();
        if (mutableInt6.intValue() == 0 || integer6 == 0) {
            return;
        }
        if (integer6 == 1) {
            list5.get(0).createItemStack(consumer, dat);
            return;
        }
        int integer7 = random4.nextInt(mutableInt6.intValue());
        for (final LootPoolEntry dbn2 : list5) {
            integer7 -= dbn2.getWeight(dat.getLuck());
            if (integer7 < 0) {
                dbn2.createItemStack(consumer, dat);
            }
        }
    }
    
    public void addRandomItems(final Consumer<ItemStack> consumer, final LootContext dat) {
        if (!this.compositeCondition.test(dat)) {
            return;
        }
        final Consumer<ItemStack> consumer2 = LootItemFunction.decorate(this.compositeFunction, consumer, dat);
        final Random random5 = dat.getRandom();
        for (int integer6 = this.rolls.getInt(random5) + Mth.floor(this.bonusRolls.getFloat(random5) * dat.getLuck()), integer7 = 0; integer7 < integer6; ++integer7) {
            this.addRandomItem(consumer2, dat);
        }
    }
    
    public void validate(final ValidationContext dbe) {
        for (int integer3 = 0; integer3 < this.conditions.length; ++integer3) {
            this.conditions[integer3].validate(dbe.forChild(".condition[" + integer3 + "]"));
        }
        for (int integer3 = 0; integer3 < this.functions.length; ++integer3) {
            this.functions[integer3].validate(dbe.forChild(".functions[" + integer3 + "]"));
        }
        for (int integer3 = 0; integer3 < this.entries.length; ++integer3) {
            this.entries[integer3].validate(dbe.forChild(".entries[" + integer3 + "]"));
        }
    }
    
    public static Builder lootPool() {
        return new Builder();
    }
    
    public static class Builder implements FunctionUserBuilder<Builder>, ConditionUserBuilder<Builder> {
        private final List<LootPoolEntryContainer> entries;
        private final List<LootItemCondition> conditions;
        private final List<LootItemFunction> functions;
        private RandomIntGenerator rolls;
        private RandomValueBounds bonusRolls;
        
        public Builder() {
            this.entries = Lists.newArrayList();
            this.conditions = Lists.newArrayList();
            this.functions = Lists.newArrayList();
            this.rolls = new RandomValueBounds(1.0f);
            this.bonusRolls = new RandomValueBounds(0.0f, 0.0f);
        }
        
        public Builder setRolls(final RandomIntGenerator daz) {
            this.rolls = daz;
            return this;
        }
        
        @Override
        public Builder unwrap() {
            return this;
        }
        
        public Builder add(final LootPoolEntryContainer.Builder<?> a) {
            this.entries.add(a.build());
            return this;
        }
        
        @Override
        public Builder when(final LootItemCondition.Builder a) {
            this.conditions.add(a.build());
            return this;
        }
        
        @Override
        public Builder apply(final LootItemFunction.Builder a) {
            this.functions.add(a.build());
            return this;
        }
        
        public LootPool build() {
            if (this.rolls == null) {
                throw new IllegalArgumentException("Rolls not set");
            }
            return new LootPool(this.entries.<LootPoolEntryContainer>toArray(new LootPoolEntryContainer[0]), this.conditions.<LootItemCondition>toArray(new LootItemCondition[0]), this.functions.<LootItemFunction>toArray(new LootItemFunction[0]), this.rolls, this.bonusRolls, null);
        }
    }
    
    public static class Serializer implements JsonDeserializer<LootPool>, JsonSerializer<LootPool> {
        @Override
        public LootPool deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
            final JsonObject jsonObject5 = GsonHelper.convertToJsonObject(jsonElement, "loot pool");
            final LootPoolEntryContainer[] arr6 = GsonHelper.<LootPoolEntryContainer[]>getAsObject(jsonObject5, "entries", jsonDeserializationContext, LootPoolEntryContainer[].class);
            final LootItemCondition[] arr7 = GsonHelper.<LootItemCondition[]>getAsObject(jsonObject5, "conditions", new LootItemCondition[0], jsonDeserializationContext, LootItemCondition[].class);
            final LootItemFunction[] arr8 = GsonHelper.<LootItemFunction[]>getAsObject(jsonObject5, "functions", new LootItemFunction[0], jsonDeserializationContext, LootItemFunction[].class);
            final RandomIntGenerator daz9 = RandomIntGenerators.deserialize(jsonObject5.get("rolls"), jsonDeserializationContext);
            final RandomValueBounds dbb10 = GsonHelper.<RandomValueBounds>getAsObject(jsonObject5, "bonus_rolls", new RandomValueBounds(0.0f, 0.0f), jsonDeserializationContext, RandomValueBounds.class);
            return new LootPool(arr6, arr7, arr8, daz9, dbb10, null);
        }
        
        @Override
        public JsonElement serialize(final LootPool dav, final Type type, final JsonSerializationContext jsonSerializationContext) {
            final JsonObject jsonObject5 = new JsonObject();
            jsonObject5.add("rolls", RandomIntGenerators.serialize(dav.rolls, jsonSerializationContext));
            jsonObject5.add("entries", jsonSerializationContext.serialize(dav.entries));
            if (dav.bonusRolls.getMin() != 0.0f && dav.bonusRolls.getMax() != 0.0f) {
                jsonObject5.add("bonus_rolls", jsonSerializationContext.serialize(dav.bonusRolls));
            }
            if (!ArrayUtils.isEmpty((Object[])dav.conditions)) {
                jsonObject5.add("conditions", jsonSerializationContext.serialize(dav.conditions));
            }
            if (!ArrayUtils.isEmpty((Object[])dav.functions)) {
                jsonObject5.add("functions", jsonSerializationContext.serialize(dav.functions));
            }
            return jsonObject5;
        }
    }
}
