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

import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonArray;
import net.minecraft.core.Registry;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonObject;
import com.google.common.collect.Sets;
import java.util.function.Predicate;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import com.google.common.collect.ImmutableSet;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParam;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.minecraft.world.level.block.state.properties.Property;
import java.util.Set;
import net.minecraft.world.level.block.Block;

public class CopyBlockState extends LootItemConditionalFunction {
    private final Block block;
    private final Set<Property<?>> properties;
    
    private CopyBlockState(final LootItemCondition[] arr, final Block bvr, final Set<Property<?>> set) {
        super(arr);
        this.block = bvr;
        this.properties = set;
    }
    
    @Override
    public LootItemFunctionType getType() {
        return LootItemFunctions.COPY_STATE;
    }
    
    @Override
    public Set<LootContextParam<?>> getReferencedContextParams() {
        return ImmutableSet.of(LootContextParams.BLOCK_STATE);
    }
    
    @Override
    protected ItemStack run(final ItemStack bki, final LootContext dat) {
        final BlockState cfj4 = dat.<BlockState>getParamOrNull(LootContextParams.BLOCK_STATE);
        if (cfj4 != null) {
            final CompoundTag le5 = bki.getOrCreateTag();
            CompoundTag le6;
            if (le5.contains("BlockStateTag", 10)) {
                le6 = le5.getCompound("BlockStateTag");
            }
            else {
                le6 = new CompoundTag();
                le5.put("BlockStateTag", le6);
            }
            this.properties.stream().filter(cfj4::hasProperty).forEach(cgl -> le6.putString(cgl.getName(), CopyBlockState.<Comparable>serialize(cfj4, cgl)));
        }
        return bki;
    }
    
    public static Builder copyState(final Block bvr) {
        return new Builder(bvr);
    }
    
    private static <T extends Comparable<T>> String serialize(final BlockState cfj, final Property<T> cgl) {
        final T comparable3 = cfj.<T>getValue(cgl);
        return cgl.getName(comparable3);
    }
    
    public static class Builder extends LootItemConditionalFunction.Builder<Builder> {
        private final Block block;
        private final Set<Property<?>> properties;
        
        private Builder(final Block bvr) {
            this.properties = Sets.newHashSet();
            this.block = bvr;
        }
        
        public Builder copy(final Property<?> cgl) {
            if (!this.block.getStateDefinition().getProperties().contains(cgl)) {
                throw new IllegalStateException("Property " + cgl + " is not present on block " + this.block);
            }
            this.properties.add(cgl);
            return this;
        }
        
        @Override
        protected Builder getThis() {
            return this;
        }
        
        @Override
        public LootItemFunction build() {
            return new CopyBlockState(this.getConditions(), this.block, this.properties, null);
        }
    }
    
    public static class Serializer extends LootItemConditionalFunction.Serializer<CopyBlockState> {
        @Override
        public void serialize(final JsonObject jsonObject, final CopyBlockState dbx, final JsonSerializationContext jsonSerializationContext) {
            super.serialize(jsonObject, dbx, jsonSerializationContext);
            jsonObject.addProperty("block", Registry.BLOCK.getKey(dbx.block).toString());
            final JsonArray jsonArray5 = new JsonArray();
            dbx.properties.forEach(cgl -> jsonArray5.add(cgl.getName()));
            jsonObject.add("properties", jsonArray5);
        }
        
        @Override
        public CopyBlockState deserialize(final JsonObject jsonObject, final JsonDeserializationContext jsonDeserializationContext, final LootItemCondition[] arr) {
            final ResourceLocation uh5 = new ResourceLocation(GsonHelper.getAsString(jsonObject, "block"));
            final Object o;
            final Object obj;
            final Block bvr6 = Registry.BLOCK.getOptional(uh5).<Throwable>orElseThrow(() -> {
                new IllegalArgumentException("Can't find block " + obj);
                return o;
            });
            final StateDefinition<Block, BlockState> cfk7 = bvr6.getStateDefinition();
            final Set<Property<?>> set8 = Sets.newHashSet();
            final JsonArray jsonArray9 = GsonHelper.getAsJsonArray(jsonObject, "properties", null);
            if (jsonArray9 != null) {
                jsonArray9.forEach(jsonElement -> set8.add(cfk7.getProperty(GsonHelper.convertToString(jsonElement, "property"))));
            }
            return new CopyBlockState(arr, bvr6, set8, null);
        }
    }
}
