package net.minecraft.util.datafix.fixes;

import com.mojang.serialization.DynamicLike;
import java.util.Optional;
import com.mojang.datafixers.OpticFinder;
import com.mojang.datafixers.util.Pair;
import com.mojang.datafixers.Typed;
import com.mojang.datafixers.DataFixUtils;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
import java.util.stream.IntStream;
import it.unimi.dsi.fastutil.shorts.ShortList;
import java.util.List;
import java.util.Arrays;
import java.nio.ByteBuffer;
import com.mojang.serialization.Dynamic;
import com.mojang.datafixers.types.Type;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.TypeRewriteRule;
import com.mojang.datafixers.schemas.Schema;
import com.mojang.datafixers.DataFix;

public class ChunkToProtochunkFix extends DataFix {
    public ChunkToProtochunkFix(final Schema schema, final boolean boolean2) {
        super(schema, boolean2);
    }
    
    public TypeRewriteRule makeRule() {
        final Type<?> type2 = this.getInputSchema().getType(References.CHUNK);
        final Type<?> type3 = this.getOutputSchema().getType(References.CHUNK);
        final Type<?> type4 = type2.findFieldType("Level");
        final Type<?> type5 = type3.findFieldType("Level");
        final Type<?> type6 = type4.findFieldType("TileTicks");
        final OpticFinder<?> opticFinder7 = DSL.fieldFinder("Level", (Type)type4);
        final OpticFinder<?> opticFinder8 = DSL.fieldFinder("TileTicks", (Type)type6);
        final OpticFinder opticFinder9;
        final Type type7;
        final OpticFinder opticFinder10;
        final Optional<? extends Stream<? extends Dynamic<?>>> optional4;
        final Dynamic<?> dynamic2;
        final boolean boolean6;
        final Dynamic<?> dynamic3;
        Dynamic<?> dynamic4;
        Optional<ByteBuffer> optional5;
        ByteBuffer byteBuffer9;
        int[] arr10;
        int integer11;
        Dynamic<?> dynamic5;
        List<ShortList> list10;
        int integer12;
        int integer13;
        int integer14;
        short short6;
        final List<ShortList> list11;
        final DynamicLike dynamicLike;
        Dynamic<?> dynamic6;
        final Type type8;
        return TypeRewriteRule.seq(this.fixTypeEverywhereTyped("ChunkToProtoChunkFix", (Type)type2, this.getOutputSchema().getType(References.CHUNK), typed -> typed.updateTyped(opticFinder9, type7, typed -> {
            optional4 = typed.getOptionalTyped(opticFinder10).flatMap(typed -> typed.write().result()).flatMap(dynamic -> dynamic.asStreamOpt().result());
            dynamic2 = typed.get(DSL.remainderFinder());
            boolean6 = (dynamic2.get("TerrainPopulated").asBoolean((boolean)(0 != 0)) && (!dynamic2.get("LightPopulated").asNumber().result().isPresent() || dynamic2.get("LightPopulated").asBoolean((boolean)(0 != 0))));
            dynamic3 = dynamic2.set("Status", dynamic2.createString(boolean6 ? "mobs_spawned" : "empty"));
            dynamic4 = dynamic3.set("hasLegacyStructureData", dynamic3.createBoolean((boolean)(1 != 0)));
            if (boolean6) {
                optional5 = (Optional<ByteBuffer>)dynamic4.get("Biomes").asByteBufferOpt().result();
                if (optional5.isPresent()) {
                    byteBuffer9 = optional5.get();
                    for (arr10 = new int[256], integer11 = 0; integer11 < arr10.length; ++integer11) {
                        if (integer11 < byteBuffer9.capacity()) {
                            arr10[integer11] = (byteBuffer9.get(integer11) & 0xFF);
                        }
                    }
                    dynamic4 = dynamic4.set("Biomes", dynamic4.createIntList(Arrays.stream(arr10)));
                }
                dynamic5 = dynamic4;
                list10 = IntStream.range(0, 16).mapToObj(integer -> new ShortArrayList()).collect(Collectors.toList());
                if (optional4.isPresent()) {
                    ((Stream)optional4.get()).forEach(dynamic -> {
                        integer12 = dynamic.get("x").asInt(0);
                        integer13 = dynamic.get("y").asInt(0);
                        integer14 = dynamic.get("z").asInt(0);
                        short6 = packOffsetCoordinates(integer12, integer13, integer14);
                        list11.get(integer13 >> 4).add(short6);
                        return;
                    });
                    dynamic4 = dynamic4.set("ToBeTicked", dynamic4.createList((Stream)list10.stream().map(shortList -> ((Dynamic)dynamicLike).createList((Stream)shortList.stream().map(dynamicLike::createShort)))));
                }
                dynamic6 = DataFixUtils.orElse(typed.set(DSL.remainderFinder(), dynamic4).write().result(), dynamic4);
            }
            else {
                dynamic6 = dynamic4;
            }
            return (Typed)((Pair)type8.readTyped((Dynamic)dynamic6).result().orElseThrow(() -> new IllegalStateException("Could not read the new chunk"))).getFirst();
        })), this.writeAndRead("Structure biome inject", this.getInputSchema().getType(References.STRUCTURE_FEATURE), this.getOutputSchema().getType(References.STRUCTURE_FEATURE)));
    }
    
    private static short packOffsetCoordinates(final int integer1, final int integer2, final int integer3) {
        return (short)((integer1 & 0xF) | (integer2 & 0xF) << 4 | (integer3 & 0xF) << 8);
    }
}
