package net.minecraft.resources;

import org.apache.logging.log4j.LogManager;
import com.google.gson.JsonElement;
import java.io.Reader;
import net.minecraft.server.packs.resources.Resource;
import com.google.gson.JsonSyntaxException;
import com.google.gson.JsonIOException;
import java.io.IOException;
import com.mojang.serialization.JsonOps;
import com.google.gson.JsonParser;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Collection;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.MappedRegistry;
import java.util.Optional;
import net.minecraft.util.Codecs;
import net.minecraft.core.WritableRegistry;
import java.util.function.Supplier;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.MapCodec;
import com.google.common.collect.Maps;
import com.mojang.serialization.DynamicOps;
import net.minecraft.core.Registry;
import java.util.Map;
import net.minecraft.core.RegistryAccess;
import net.minecraft.server.packs.resources.ResourceManager;
import org.apache.logging.log4j.Logger;

public class RegistryReadOps<T> extends DelegatingOps<T> {
    private static final Logger LOGGER;
    private final ResourceManager resourceManager;
    private final RegistryAccess registryHolder;
    private final Map<ResourceKey<? extends Registry<?>>, ReadCache<?>> readCache;
    
    public static <T> RegistryReadOps<T> create(final DynamicOps<T> dynamicOps, final ResourceManager abc, final RegistryAccess gm) {
        return new RegistryReadOps<T>(dynamicOps, abc, gm);
    }
    
    private RegistryReadOps(final DynamicOps<T> dynamicOps, final ResourceManager abc, final RegistryAccess gm) {
        super(dynamicOps);
        this.readCache = Maps.newIdentityHashMap();
        this.resourceManager = abc;
        this.registryHolder = gm;
    }
    
    protected <E> DataResult<Pair<Supplier<E>, T>> decodeElement(final T object, final ResourceKey<Registry<E>> ug, final MapCodec<E> mapCodec) {
        final Optional<WritableRegistry<E>> optional5 = this.registryHolder.<E>registry(ug);
        if (!optional5.isPresent()) {
            return (DataResult<Pair<Supplier<E>, T>>)DataResult.error("Unknown registry: " + ug);
        }
        final WritableRegistry<E> gs6 = optional5.get();
        final DataResult<Pair<ResourceLocation, T>> dataResult7 = (DataResult<Pair<ResourceLocation, T>>)ResourceLocation.CODEC.decode((DynamicOps)this.delegate, object);
        if (!dataResult7.result().isPresent()) {
            final WritableRegistry<Object> writableRegistry;
            return (DataResult<Pair<Supplier<E>, T>>)Codecs.<E>withName(ug, mapCodec).codec().decode((DynamicOps)this.delegate, object).map(pair -> pair.mapFirst(pair -> {
                writableRegistry.register((ResourceKey<Object>)pair.getFirst(), pair.getSecond());
                writableRegistry.setPersistent((ResourceKey<Object>)pair.getFirst());
                return pair::getSecond;
            }));
        }
        final Pair<ResourceLocation, T> pair2 = (Pair<ResourceLocation, T>)dataResult7.result().get();
        final ResourceLocation uh9 = (ResourceLocation)pair2.getFirst();
        return (DataResult<Pair<Supplier<E>, T>>)this.<E>readAndRegisterElement(ug, gs6, mapCodec, uh9).map(supplier -> Pair.of(supplier, pair2.getSecond()));
    }
    
    public <E> DataResult<MappedRegistry<E>> decodeElements(final MappedRegistry<E> gh, final ResourceKey<Registry<E>> ug, final MapCodec<E> mapCodec) {
        final ResourceLocation uh5 = ug.location();
        final Collection<ResourceLocation> collection6 = this.resourceManager.listResources(uh5, string -> string.endsWith(".json"));
        DataResult<MappedRegistry<E>> dataResult7 = (DataResult<MappedRegistry<E>>)DataResult.success(gh, Lifecycle.stable());
        for (final ResourceLocation uh6 : collection6) {
            final String string2 = uh6.getPath();
            if (!string2.endsWith(".json")) {
                RegistryReadOps.LOGGER.warn("Skipping resource {} since it is not a json file", uh6);
            }
            else if (!string2.startsWith(uh5.getPath() + "/")) {
                RegistryReadOps.LOGGER.warn("Skipping resource {} since it does not have a registry name prefix", uh6);
            }
            else {
                final String string3 = string2.substring(0, string2.length() - ".json".length()).substring(uh5.getPath().length() + 1);
                final int integer12 = string3.indexOf(47);
                if (integer12 < 0) {
                    RegistryReadOps.LOGGER.warn("Skipping resource {} since it does not have a namespace", uh6);
                }
                else {
                    final String string4 = string3.substring(0, integer12);
                    final String string5 = string3.substring(integer12 + 1);
                    final ResourceLocation uh7 = new ResourceLocation(string4, string5);
                    dataResult7 = (DataResult<MappedRegistry<E>>)dataResult7.flatMap(gh -> this.<E>readAndRegisterElement(ug, gh, mapCodec, uh7).map(supplier -> gh));
                }
            }
        }
        return (DataResult<MappedRegistry<E>>)dataResult7.setPartial(gh);
    }
    
    private <E> DataResult<Supplier<E>> readAndRegisterElement(final ResourceKey<Registry<E>> ug, final WritableRegistry<E> gs, final MapCodec<E> mapCodec, final ResourceLocation uh) {
        // 
        // This method could not be decompiled.
        // 
        // Original Bytecode:
        // 
        //     1: aload           uh
        //     3: invokestatic    net/minecraft/resources/ResourceKey.create:(Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/resources/ResourceKey;
        //     6: astore          ug6
        //     8: aload_2         /* gs */
        //     9: aload           ug6
        //    11: invokevirtual   net/minecraft/core/WritableRegistry.get:(Lnet/minecraft/resources/ResourceKey;)Ljava/lang/Object;
        //    14: astore          object7
        //    16: aload           object7
        //    18: ifnull          35
        //    21: aload           object7
        //    23: invokedynamic   BootstrapMethod #4, get:(Ljava/lang/Object;)Ljava/util/function/Supplier;
        //    28: invokestatic    com/mojang/serialization/Lifecycle.stable:()Lcom/mojang/serialization/Lifecycle;
        //    31: invokestatic    com/mojang/serialization/DataResult.success:(Ljava/lang/Object;Lcom/mojang/serialization/Lifecycle;)Lcom/mojang/serialization/DataResult;
        //    34: areturn        
        //    35: aload_0         /* this */
        //    36: aload_1         /* ug */
        //    37: invokespecial   net/minecraft/resources/RegistryReadOps.readCache:(Lnet/minecraft/resources/ResourceKey;)Lnet/minecraft/resources/RegistryReadOps$ReadCache;
        //    40: astore          a8
        //    42: aload           a8
        //    44: invokestatic    net/minecraft/resources/RegistryReadOps$ReadCache.access$000:(Lnet/minecraft/resources/RegistryReadOps$ReadCache;)Ljava/util/Map;
        //    47: aload           ug6
        //    49: invokeinterface java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
        //    54: checkcast       Lcom/mojang/serialization/DataResult;
        //    57: astore          dataResult9
        //    59: aload           dataResult9
        //    61: ifnull          67
        //    64: aload           dataResult9
        //    66: areturn        
        //    67: aload_2         /* gs */
        //    68: aload           ug6
        //    70: invokedynamic   BootstrapMethod #5, get:(Lnet/minecraft/core/WritableRegistry;Lnet/minecraft/resources/ResourceKey;)Lcom/google/common/base/Supplier;
        //    75: invokestatic    com/google/common/base/Suppliers.memoize:(Lcom/google/common/base/Supplier;)Lcom/google/common/base/Supplier;
        //    78: astore          supplier10
        //    80: aload           a8
        //    82: invokestatic    net/minecraft/resources/RegistryReadOps$ReadCache.access$000:(Lnet/minecraft/resources/RegistryReadOps$ReadCache;)Ljava/util/Map;
        //    85: aload           ug6
        //    87: aload           supplier10
        //    89: invokestatic    com/mojang/serialization/DataResult.success:(Ljava/lang/Object;)Lcom/mojang/serialization/DataResult;
        //    92: invokeinterface java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
        //    97: pop            
        //    98: aload_0         /* this */
        //    99: aload_1         /* ug */
        //   100: aload           ug6
        //   102: aload_3         /* mapCodec */
        //   103: invokespecial   net/minecraft/resources/RegistryReadOps.readElementFromFile:(Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/resources/ResourceKey;Lcom/mojang/serialization/MapCodec;)Lcom/mojang/serialization/DataResult;
        //   106: astore          dataResult11
        //   108: aload           dataResult11
        //   110: invokevirtual   com/mojang/serialization/DataResult.result:()Ljava/util/Optional;
        //   113: aload_2         /* gs */
        //   114: aload           ug6
        //   116: invokedynamic   BootstrapMethod #6, accept:(Lnet/minecraft/core/WritableRegistry;Lnet/minecraft/resources/ResourceKey;)Ljava/util/function/Consumer;
        //   121: invokevirtual   java/util/Optional.ifPresent:(Ljava/util/function/Consumer;)V
        //   124: aload           dataResult11
        //   126: invokedynamic   BootstrapMethod #7, apply:()Ljava/util/function/Function;
        //   131: invokevirtual   com/mojang/serialization/DataResult.map:(Ljava/util/function/Function;)Lcom/mojang/serialization/DataResult;
        //   134: astore          dataResult12
        //   136: aload           a8
        //   138: invokestatic    net/minecraft/resources/RegistryReadOps$ReadCache.access$000:(Lnet/minecraft/resources/RegistryReadOps$ReadCache;)Ljava/util/Map;
        //   141: aload           ug6
        //   143: aload           dataResult12
        //   145: invokeinterface java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
        //   150: pop            
        //   151: aload           dataResult12
        //   153: areturn        
        //    Signature:
        //  <E:Ljava/lang/Object;>(Lnet/minecraft/resources/ResourceKey<Lnet/minecraft/core/Registry<TE;>;>;Lnet/minecraft/core/WritableRegistry<TE;>;Lcom/mojang/serialization/MapCodec<TE;>;Lnet/minecraft/resources/ResourceLocation;)Lcom/mojang/serialization/DataResult<Ljava/util/function/Supplier<TE;>;>;
        //    MethodParameters:
        //  Name      Flags  
        //  --------  -----
        //  ug        
        //  gs        
        //  mapCodec  
        //  uh        
        //    StackMapTable: 00 02 FF 00 23 00 06 07 00 02 07 00 A1 07 00 68 07 00 83 00 07 00 A1 00 00 FD 00 1F 00 07 00 0A
        // 
        // The error that occurred was:
        // 
        // java.lang.IllegalStateException: Could not infer any expression.
        //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:374)
        //     at com.strobel.decompiler.ast.TypeAnalysis.run(TypeAnalysis.java:96)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:344)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:42)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:214)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:99)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethodBody(AstBuilder.java:782)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethod(AstBuilder.java:675)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:552)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:519)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:161)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createType(AstBuilder.java:150)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addType(AstBuilder.java:125)
        //     at cuchaz.enigma.SourceProvider.getSources(SourceProvider.java:85)
        //     at cuchaz.enigma.EnigmaProject$JarExport.decompileClass(EnigmaProject.java:241)
        //     at cuchaz.enigma.EnigmaProject$JarExport.lambda$decompile$1(EnigmaProject.java:230)
        //     at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
        //     at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
        //     at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
        //     at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
        //     at java.base/java.util.stream.ReduceOps$ReduceTask.doLeaf(ReduceOps.java:952)
        //     at java.base/java.util.stream.ReduceOps$ReduceTask.doLeaf(ReduceOps.java:926)
        //     at java.base/java.util.stream.AbstractTask.compute(AbstractTask.java:327)
        //     at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
        //     at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
        //     at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
        //     at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
        //     at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
        //     at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
        // 
        throw new IllegalStateException("An error occurred while decompiling this method.");
    }
    
    private <E> DataResult<E> readElementFromFile(final ResourceKey<Registry<E>> ug1, final ResourceKey<E> ug2, final MapCodec<E> mapCodec) {
        final ResourceLocation uh5 = new ResourceLocation(ug1.location().getNamespace(), ug1.location().getPath() + "/" + ug2.location().getNamespace() + "/" + ug2.location().getPath() + ".json");
        try (final Resource abb6 = this.resourceManager.getResource(uh5);
             final Reader reader8 = new InputStreamReader(abb6.getInputStream(), StandardCharsets.UTF_8)) {
            final JsonParser jsonParser10 = new JsonParser();
            final JsonElement jsonElement11 = jsonParser10.parse(reader8);
            return (DataResult<E>)mapCodec.codec().parse((DynamicOps)new RegistryReadOps((com.mojang.serialization.DynamicOps<Object>)JsonOps.INSTANCE, this.resourceManager, this.registryHolder), jsonElement11);
        }
        catch (IOException | JsonIOException | JsonSyntaxException ex2) {
            final Exception ex;
            final Exception exception6 = ex;
            return (DataResult<E>)DataResult.error("Failed to parse file: " + exception6.getMessage());
        }
    }
    
    private <E> ReadCache<E> readCache(final ResourceKey<Registry<E>> ug) {
        return (ReadCache<E>)this.readCache.computeIfAbsent(ug, ug -> new ReadCache());
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
    
    static final class ReadCache<E> {
        private final Map<ResourceKey<E>, DataResult<Supplier<E>>> values;
        
        private ReadCache() {
            this.values = Maps.newIdentityHashMap();
        }
    }
}
