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

import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.monster.Shulker;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.levelgen.feature.StructurePieceType;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockIgnoreProcessor;
import java.util.Iterator;
import java.util.Collection;
import com.google.common.collect.Lists;
import java.util.Random;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.util.Tuple;
import java.util.List;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;

public class EndCityPieces {
    private static final StructurePlaceSettings OVERWRITE;
    private static final StructurePlaceSettings INSERT;
    private static final SectionGenerator HOUSE_TOWER_GENERATOR;
    private static final List<Tuple<Rotation, BlockPos>> TOWER_BRIDGES;
    private static final SectionGenerator TOWER_GENERATOR;
    private static final SectionGenerator TOWER_BRIDGE_GENERATOR;
    private static final List<Tuple<Rotation, BlockPos>> FAT_TOWER_BRIDGES;
    private static final SectionGenerator FAT_TOWER_GENERATOR;
    
    private static EndCityPiece addPiece(final StructureManager cva, final EndCityPiece a, final BlockPos fu, final String string, final Rotation cap, final boolean boolean6) {
        final EndCityPiece a2 = new EndCityPiece(cva, string, a.templatePosition, cap, boolean6);
        final BlockPos fu2 = a.template.calculateConnectedPosition(a.placeSettings, fu, a2.placeSettings, BlockPos.ZERO);
        a2.move(fu2.getX(), fu2.getY(), fu2.getZ());
        return a2;
    }
    
    public static void startHouseTower(final StructureManager cva, final BlockPos fu, final Rotation cap, final List<StructurePiece> list, final Random random) {
        EndCityPieces.FAT_TOWER_GENERATOR.init();
        EndCityPieces.HOUSE_TOWER_GENERATOR.init();
        EndCityPieces.TOWER_BRIDGE_GENERATOR.init();
        EndCityPieces.TOWER_GENERATOR.init();
        EndCityPiece a6 = addHelper(list, new EndCityPiece(cva, "base_floor", fu, cap, true));
        a6 = addHelper(list, addPiece(cva, a6, new BlockPos(-1, 0, -1), "second_floor_1", cap, false));
        a6 = addHelper(list, addPiece(cva, a6, new BlockPos(-1, 4, -1), "third_floor_1", cap, false));
        a6 = addHelper(list, addPiece(cva, a6, new BlockPos(-1, 8, -1), "third_roof", cap, true));
        recursiveChildren(cva, EndCityPieces.TOWER_GENERATOR, 1, a6, null, list, random);
    }
    
    private static EndCityPiece addHelper(final List<StructurePiece> list, final EndCityPiece a) {
        list.add(a);
        return a;
    }
    
    private static boolean recursiveChildren(final StructureManager cva, final SectionGenerator b, final int integer, final EndCityPiece a, final BlockPos fu, final List<StructurePiece> list, final Random random) {
        if (integer > 8) {
            return false;
        }
        final List<StructurePiece> list2 = Lists.newArrayList();
        if (b.generate(cva, integer, a, fu, list2, random)) {
            boolean boolean9 = false;
            final int integer2 = random.nextInt();
            for (final StructurePiece cty12 : list2) {
                cty12.genDepth = integer2;
                final StructurePiece cty13 = StructurePiece.findCollisionPiece(list, cty12.getBoundingBox());
                if (cty13 != null && cty13.genDepth != a.genDepth) {
                    boolean9 = true;
                    break;
                }
            }
            if (!boolean9) {
                list.addAll(list2);
                return true;
            }
        }
        return false;
    }
    
    static {
        OVERWRITE = new StructurePlaceSettings().setIgnoreEntities(true).addProcessor(BlockIgnoreProcessor.STRUCTURE_BLOCK);
        INSERT = new StructurePlaceSettings().setIgnoreEntities(true).addProcessor(BlockIgnoreProcessor.STRUCTURE_AND_AIR);
        HOUSE_TOWER_GENERATOR = new SectionGenerator() {
            @Override
            public void init() {
            }
            
            @Override
            public boolean generate(final StructureManager cva, final int integer, final EndCityPiece a, final BlockPos fu, final List<StructurePiece> list, final Random random) {
                if (integer > 8) {
                    return false;
                }
                final Rotation cap8 = a.placeSettings.getRotation();
                EndCityPiece a2 = addHelper(list, addPiece(cva, a, fu, "base_floor", cap8, true));
                final int integer2 = random.nextInt(3);
                if (integer2 == 0) {
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(-1, 4, -1), "base_roof", cap8, true));
                }
                else if (integer2 == 1) {
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(-1, 0, -1), "second_floor_2", cap8, false));
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(-1, 8, -1), "second_roof", cap8, false));
                    recursiveChildren(cva, EndCityPieces.TOWER_GENERATOR, integer + 1, a2, null, list, random);
                }
                else if (integer2 == 2) {
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(-1, 0, -1), "second_floor_2", cap8, false));
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(-1, 4, -1), "third_floor_2", cap8, false));
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(-1, 8, -1), "third_roof", cap8, true));
                    recursiveChildren(cva, EndCityPieces.TOWER_GENERATOR, integer + 1, a2, null, list, random);
                }
                return true;
            }
        };
        TOWER_BRIDGES = Lists.<Tuple>newArrayList(new Tuple((A)Rotation.NONE, (B)new BlockPos(1, -1, 0)), new Tuple((A)Rotation.CLOCKWISE_90, (B)new BlockPos(6, -1, 1)), new Tuple((A)Rotation.COUNTERCLOCKWISE_90, (B)new BlockPos(0, -1, 5)), new Tuple((A)Rotation.CLOCKWISE_180, (B)new BlockPos(5, -1, 6)));
        TOWER_GENERATOR = new SectionGenerator() {
            @Override
            public void init() {
            }
            
            @Override
            public boolean generate(final StructureManager cva, final int integer, final EndCityPiece a, final BlockPos fu, final List<StructurePiece> list, final Random random) {
                final Rotation cap8 = a.placeSettings.getRotation();
                EndCityPiece a2 = a;
                a2 = addHelper(list, addPiece(cva, a2, new BlockPos(3 + random.nextInt(2), -3, 3 + random.nextInt(2)), "tower_base", cap8, true));
                a2 = addHelper(list, addPiece(cva, a2, new BlockPos(0, 7, 0), "tower_piece", cap8, true));
                EndCityPiece a3 = (random.nextInt(3) == 0) ? a2 : null;
                for (int integer2 = 1 + random.nextInt(3), integer3 = 0; integer3 < integer2; ++integer3) {
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(0, 4, 0), "tower_piece", cap8, true));
                    if (integer3 < integer2 - 1 && random.nextBoolean()) {
                        a3 = a2;
                    }
                }
                if (a3 != null) {
                    for (final Tuple<Rotation, BlockPos> aek13 : EndCityPieces.TOWER_BRIDGES) {
                        if (random.nextBoolean()) {
                            final EndCityPiece a4 = addHelper(list, addPiece(cva, a3, aek13.getB(), "bridge_end", cap8.getRotated(aek13.getA()), true));
                            recursiveChildren(cva, EndCityPieces.TOWER_BRIDGE_GENERATOR, integer + 1, a4, null, list, random);
                        }
                    }
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(-1, 4, -1), "tower_top", cap8, true));
                }
                else {
                    if (integer != 7) {
                        return recursiveChildren(cva, EndCityPieces.FAT_TOWER_GENERATOR, integer + 1, a2, null, list, random);
                    }
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(-1, 4, -1), "tower_top", cap8, true));
                }
                return true;
            }
        };
        TOWER_BRIDGE_GENERATOR = new SectionGenerator() {
            public boolean shipCreated;
            
            @Override
            public void init() {
                this.shipCreated = false;
            }
            
            @Override
            public boolean generate(final StructureManager cva, final int integer, final EndCityPiece a, final BlockPos fu, final List<StructurePiece> list, final Random random) {
                final Rotation cap8 = a.placeSettings.getRotation();
                final int integer2 = random.nextInt(4) + 1;
                EndCityPiece a2 = addHelper(list, addPiece(cva, a, new BlockPos(0, 0, -4), "bridge_piece", cap8, true));
                a2.genDepth = -1;
                int integer3 = 0;
                for (int integer4 = 0; integer4 < integer2; ++integer4) {
                    if (random.nextBoolean()) {
                        a2 = addHelper(list, addPiece(cva, a2, new BlockPos(0, integer3, -4), "bridge_piece", cap8, true));
                        integer3 = 0;
                    }
                    else {
                        if (random.nextBoolean()) {
                            a2 = addHelper(list, addPiece(cva, a2, new BlockPos(0, integer3, -4), "bridge_steep_stairs", cap8, true));
                        }
                        else {
                            a2 = addHelper(list, addPiece(cva, a2, new BlockPos(0, integer3, -8), "bridge_gentle_stairs", cap8, true));
                        }
                        integer3 = 4;
                    }
                }
                if (this.shipCreated || random.nextInt(10 - integer) != 0) {
                    if (!recursiveChildren(cva, EndCityPieces.HOUSE_TOWER_GENERATOR, integer + 1, a2, new BlockPos(-3, integer3 + 1, -11), list, random)) {
                        return false;
                    }
                }
                else {
                    addHelper(list, addPiece(cva, a2, new BlockPos(-8 + random.nextInt(8), integer3, -70 + random.nextInt(10)), "ship", cap8, true));
                    this.shipCreated = true;
                }
                a2 = addHelper(list, addPiece(cva, a2, new BlockPos(4, integer3, 0), "bridge_end", cap8.getRotated(Rotation.CLOCKWISE_180), true));
                a2.genDepth = -1;
                return true;
            }
        };
        FAT_TOWER_BRIDGES = Lists.<Tuple>newArrayList(new Tuple((A)Rotation.NONE, (B)new BlockPos(4, -1, 0)), new Tuple((A)Rotation.CLOCKWISE_90, (B)new BlockPos(12, -1, 4)), new Tuple((A)Rotation.COUNTERCLOCKWISE_90, (B)new BlockPos(0, -1, 8)), new Tuple((A)Rotation.CLOCKWISE_180, (B)new BlockPos(8, -1, 12)));
        FAT_TOWER_GENERATOR = new SectionGenerator() {
            @Override
            public void init() {
            }
            
            @Override
            public boolean generate(final StructureManager cva, final int integer, final EndCityPiece a, final BlockPos fu, final List<StructurePiece> list, final Random random) {
                final Rotation cap9 = a.placeSettings.getRotation();
                EndCityPiece a2 = addHelper(list, addPiece(cva, a, new BlockPos(-3, 4, -3), "fat_tower_base", cap9, true));
                a2 = addHelper(list, addPiece(cva, a2, new BlockPos(0, 4, 0), "fat_tower_middle", cap9, true));
                for (int integer2 = 0; integer2 < 2 && random.nextInt(3) != 0; ++integer2) {
                    a2 = addHelper(list, addPiece(cva, a2, new BlockPos(0, 8, 0), "fat_tower_middle", cap9, true));
                    for (final Tuple<Rotation, BlockPos> aek12 : EndCityPieces.FAT_TOWER_BRIDGES) {
                        if (random.nextBoolean()) {
                            final EndCityPiece a3 = addHelper(list, addPiece(cva, a2, aek12.getB(), "bridge_end", cap9.getRotated(aek12.getA()), true));
                            recursiveChildren(cva, EndCityPieces.TOWER_BRIDGE_GENERATOR, integer + 1, a3, null, list, random);
                        }
                    }
                }
                a2 = addHelper(list, addPiece(cva, a2, new BlockPos(-2, 8, -2), "fat_tower_top", cap9, true));
                return true;
            }
        };
    }
    
    public static class EndCityPiece extends TemplateStructurePiece {
        private final String templateName;
        private final Rotation rotation;
        private final boolean overwrite;
        
        public EndCityPiece(final StructureManager cva, final String string, final BlockPos fu, final Rotation cap, final boolean boolean5) {
            super(StructurePieceType.END_CITY_PIECE, 0);
            this.templateName = string;
            this.templatePosition = fu;
            this.rotation = cap;
            this.overwrite = boolean5;
            this.loadTemplate(cva);
        }
        
        public EndCityPiece(final StructureManager cva, final CompoundTag le) {
            super(StructurePieceType.END_CITY_PIECE, le);
            this.templateName = le.getString("Template");
            this.rotation = Rotation.valueOf(le.getString("Rot"));
            this.overwrite = le.getBoolean("OW");
            this.loadTemplate(cva);
        }
        
        private void loadTemplate(final StructureManager cva) {
            final StructureTemplate cve3 = cva.getOrCreate(new ResourceLocation("end_city/" + this.templateName));
            final StructurePlaceSettings cvb4 = (this.overwrite ? EndCityPieces.OVERWRITE : EndCityPieces.INSERT).copy().setRotation(this.rotation);
            this.setup(cve3, this.templatePosition, cvb4);
        }
        
        @Override
        protected void addAdditionalSaveData(final CompoundTag le) {
            super.addAdditionalSaveData(le);
            le.putString("Template", this.templateName);
            le.putString("Rot", this.rotation.name());
            le.putBoolean("OW", this.overwrite);
        }
        
        @Override
        protected void handleDataMarker(final String string, final BlockPos fu, final LevelAccessor bqc, final Random random, final BoundingBox ctd) {
            if (string.startsWith("Chest")) {
                final BlockPos fu2 = fu.below();
                if (ctd.isInside(fu2)) {
                    RandomizableContainerBlockEntity.setLootTable(bqc, random, fu2, BuiltInLootTables.END_CITY_TREASURE);
                }
            }
            else if (string.startsWith("Sentry")) {
                final Shulker bch7 = EntityType.SHULKER.create(bqc.getLevel());
                bch7.setPos(fu.getX() + 0.5, fu.getY() + 0.5, fu.getZ() + 0.5);
                bch7.setAttachPosition(fu);
                bqc.addFreshEntity(bch7);
            }
            else if (string.startsWith("Elytra")) {
                final ItemFrame bba7 = new ItemFrame(bqc.getLevel(), fu, this.rotation.rotate(Direction.SOUTH));
                bba7.setItem(new ItemStack(Items.ELYTRA), false);
                bqc.addFreshEntity(bba7);
            }
        }
    }
    
    interface SectionGenerator {
        void init();
        
        boolean generate(final StructureManager cva, final int integer, final EndCityPiece a, final BlockPos fu, final List<StructurePiece> list, final Random random);
    }
}
