package net.minecraft.world.level.levelgen.feature;

import java.util.Arrays;
import java.util.function.Function;
import java.util.Map;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.Util;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.block.state.BlockState;
import java.util.Iterator;
import net.minecraft.world.level.levelgen.Heightmap;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import net.minecraft.world.level.BlockGetter;
import java.util.List;
import com.google.common.collect.ImmutableList;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.RuinedPortalPiece;
import net.minecraft.world.level.chunk.ChunkGenerator;
import java.util.Random;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.core.BlockPos;
import com.mojang.serialization.Codec;
import net.minecraft.world.level.levelgen.feature.configurations.RuinedPortalConfiguration;

public class RuinedPortalFeature extends StructureFeature<RuinedPortalConfiguration> {
    private static final String[] STRUCTURE_LOCATION_PORTALS;
    private static final String[] STRUCTURE_LOCATION_GIANT_PORTALS;
    
    public RuinedPortalFeature(final Codec<RuinedPortalConfiguration> codec) {
        super(codec);
    }
    
    @Override
    public StructureStartFactory<RuinedPortalConfiguration> getStartFactory() {
        return FeatureStart::new;
    }
    
    private static boolean isCold(final BlockPos fu, final Biome bre) {
        return bre.getTemperature(fu) < 0.15f;
    }
    
    private static int findSuitableY(final Random random, final ChunkGenerator cha, final RuinedPortalPiece.VerticalPlacement b, final boolean boolean4, final int integer5, final int integer6, final BoundingBox ctd) {
        int integer7;
        if (b == RuinedPortalPiece.VerticalPlacement.IN_NETHER) {
            if (boolean4) {
                integer7 = randomIntInclusive(random, 32, 100);
            }
            else if (random.nextFloat() < 0.5f) {
                integer7 = randomIntInclusive(random, 27, 29);
            }
            else {
                integer7 = randomIntInclusive(random, 29, 100);
            }
        }
        else if (b == RuinedPortalPiece.VerticalPlacement.IN_MOUNTAIN) {
            final int integer8 = integer5 - integer6;
            integer7 = getRandomWithinInterval(random, 70, integer8);
        }
        else if (b == RuinedPortalPiece.VerticalPlacement.UNDERGROUND) {
            final int integer8 = integer5 - integer6;
            integer7 = getRandomWithinInterval(random, 15, integer8);
        }
        else if (b == RuinedPortalPiece.VerticalPlacement.PARTLY_BURIED) {
            integer7 = integer5 - integer6 + randomIntInclusive(random, 2, 8);
        }
        else {
            integer7 = integer5;
        }
        final List<BlockPos> list9 = ImmutableList.<BlockPos>of(new BlockPos(ctd.x0, 0, ctd.z0), new BlockPos(ctd.x1, 0, ctd.z0), new BlockPos(ctd.x0, 0, ctd.z1), new BlockPos(ctd.x1, 0, ctd.z1));
        final List<BlockGetter> list10 = list9.stream().map(fu -> cha.getBaseColumn(fu.getX(), fu.getZ())).collect(Collectors.toList());
        final Heightmap.Types a11 = (b == RuinedPortalPiece.VerticalPlacement.ON_OCEAN_FLOOR) ? Heightmap.Types.OCEAN_FLOOR_WG : Heightmap.Types.WORLD_SURFACE_WG;
        final BlockPos.MutableBlockPos a12 = new BlockPos.MutableBlockPos();
        int integer9 = 0;
    Label_0385:
        for (integer9 = integer7; integer9 > 15; --integer9) {
            int integer10 = 0;
            a12.set(0, integer9, 0);
            for (final BlockGetter bpg16 : list10) {
                final BlockState cfj17 = bpg16.getBlockState(a12);
                if (cfj17 != null && a11.isOpaque().test(cfj17) && ++integer10 == 3) {
                    break Label_0385;
                }
            }
        }
        return integer9;
    }
    
    private static int randomIntInclusive(final Random random, final int integer2, final int integer3) {
        return random.nextInt(integer3 - integer2 + 1) + integer2;
    }
    
    private static int getRandomWithinInterval(final Random random, final int integer2, final int integer3) {
        if (integer2 < integer3) {
            return randomIntInclusive(random, integer2, integer3);
        }
        return integer3;
    }
    
    static {
        STRUCTURE_LOCATION_PORTALS = new String[] { "ruined_portal/portal_1", "ruined_portal/portal_2", "ruined_portal/portal_3", "ruined_portal/portal_4", "ruined_portal/portal_5", "ruined_portal/portal_6", "ruined_portal/portal_7", "ruined_portal/portal_8", "ruined_portal/portal_9", "ruined_portal/portal_10" };
        STRUCTURE_LOCATION_GIANT_PORTALS = new String[] { "ruined_portal/giant_portal_1", "ruined_portal/giant_portal_2", "ruined_portal/giant_portal_3" };
    }
    
    public static class FeatureStart extends StructureStart<RuinedPortalConfiguration> {
        protected FeatureStart(final StructureFeature<RuinedPortalConfiguration> cml, final int integer2, final int integer3, final BoundingBox ctd, final int integer5, final long long6) {
            super(cml, integer2, integer3, ctd, integer5, long6);
        }
        
        @Override
        public void generatePieces(final ChunkGenerator cha, final StructureManager cva, final int integer3, final int integer4, final Biome bre, final RuinedPortalConfiguration cok) {
            final RuinedPortalPiece.Properties a9 = new RuinedPortalPiece.Properties();
            RuinedPortalPiece.VerticalPlacement b8;
            if (cok.portalType == Type.DESERT) {
                b8 = RuinedPortalPiece.VerticalPlacement.PARTLY_BURIED;
                a9.airPocket = false;
                a9.mossiness = 0.0f;
            }
            else if (cok.portalType == Type.JUNGLE) {
                b8 = RuinedPortalPiece.VerticalPlacement.ON_LAND_SURFACE;
                a9.airPocket = (this.random.nextFloat() < 0.5f);
                a9.mossiness = 0.8f;
                a9.overgrown = true;
                a9.vines = true;
            }
            else if (cok.portalType == Type.SWAMP) {
                b8 = RuinedPortalPiece.VerticalPlacement.ON_OCEAN_FLOOR;
                a9.airPocket = false;
                a9.mossiness = 0.5f;
                a9.vines = true;
            }
            else if (cok.portalType == Type.MOUNTAIN) {
                final boolean boolean10 = this.random.nextFloat() < 0.5f;
                b8 = (boolean10 ? RuinedPortalPiece.VerticalPlacement.IN_MOUNTAIN : RuinedPortalPiece.VerticalPlacement.ON_LAND_SURFACE);
                a9.airPocket = (boolean10 || this.random.nextFloat() < 0.5f);
            }
            else if (cok.portalType == Type.OCEAN) {
                b8 = RuinedPortalPiece.VerticalPlacement.ON_OCEAN_FLOOR;
                a9.airPocket = false;
                a9.mossiness = 0.8f;
            }
            else if (cok.portalType == Type.NETHER) {
                b8 = RuinedPortalPiece.VerticalPlacement.IN_NETHER;
                a9.airPocket = (this.random.nextFloat() < 0.5f);
                a9.mossiness = 0.0f;
                a9.replaceWithBlackstone = true;
            }
            else {
                final boolean boolean10 = this.random.nextFloat() < 0.5f;
                b8 = (boolean10 ? RuinedPortalPiece.VerticalPlacement.UNDERGROUND : RuinedPortalPiece.VerticalPlacement.ON_LAND_SURFACE);
                a9.airPocket = (boolean10 || this.random.nextFloat() < 0.5f);
            }
            ResourceLocation uh10;
            if (this.random.nextFloat() < 0.05f) {
                uh10 = new ResourceLocation(RuinedPortalFeature.STRUCTURE_LOCATION_GIANT_PORTALS[this.random.nextInt(RuinedPortalFeature.STRUCTURE_LOCATION_GIANT_PORTALS.length)]);
            }
            else {
                uh10 = new ResourceLocation(RuinedPortalFeature.STRUCTURE_LOCATION_PORTALS[this.random.nextInt(RuinedPortalFeature.STRUCTURE_LOCATION_PORTALS.length)]);
            }
            final StructureTemplate cve11 = cva.getOrCreate(uh10);
            final Rotation cap12 = Util.<Rotation>getRandom(Rotation.values(), this.random);
            final Mirror bzj13 = (this.random.nextFloat() < 0.5f) ? Mirror.NONE : Mirror.FRONT_BACK;
            final BlockPos fu14 = new BlockPos(cve11.getSize().getX() / 2, 0, cve11.getSize().getZ() / 2);
            final BlockPos fu15 = new ChunkPos(integer3, integer4).getWorldPosition();
            final BoundingBox ctd16 = cve11.getBoundingBox(fu15, cap12, fu14, bzj13);
            final Vec3i gr17 = ctd16.getCenter();
            final int integer5 = gr17.getX();
            final int integer6 = gr17.getZ();
            final int integer7 = cha.getBaseHeight(integer5, integer6, RuinedPortalPiece.getHeightMapType(b8)) - 1;
            final int integer8 = findSuitableY(this.random, cha, b8, a9.airPocket, integer7, ctd16.getYSpan(), ctd16);
            final BlockPos fu16 = new BlockPos(fu15.getX(), integer8, fu15.getZ());
            if (cok.portalType == Type.MOUNTAIN || cok.portalType == Type.OCEAN || cok.portalType == Type.STANDARD) {
                a9.cold = isCold(fu16, bre);
            }
            this.pieces.add(new RuinedPortalPiece(fu16, b8, a9, uh10, cve11, cap12, bzj13, fu14));
            this.calculateBoundingBox();
        }
    }
    
    public enum Type implements StringRepresentable {
        STANDARD("standard"), 
        DESERT("desert"), 
        JUNGLE("jungle"), 
        SWAMP("swamp"), 
        MOUNTAIN("mountain"), 
        OCEAN("ocean"), 
        NETHER("nether");
        
        public static final Codec<Type> CODEC;
        private static final Map<String, Type> BY_NAME;
        private final String name;
        
        private Type(final String string3) {
            this.name = string3;
        }
        
        public String getName() {
            return this.name;
        }
        
        public static Type byName(final String string) {
            return Type.BY_NAME.get(string);
        }
        
        @Override
        public String getSerializedName() {
            return this.name;
        }
        
        static {
            CODEC = StringRepresentable.<Type>fromEnum(Type::values, Type::byName);
            BY_NAME = Arrays.<Type>stream(values()).collect(Collectors.toMap(Type::getName, b -> b));
        }
    }
}
