package net.minecraft.world.level;

import net.minecraft.world.level.block.state.AbstractStateHolder;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.util.Mth;
import javax.annotation.Nullable;
import java.util.Optional;
import net.minecraft.world.level.block.NetherPortalBlock;
import net.minecraft.server.level.TicketType;
import java.util.Comparator;
import net.minecraft.core.Vec3i;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.entity.ai.village.poi.PoiType;
import net.minecraft.world.entity.ai.village.poi.PoiRecord;
import java.util.List;
import net.minecraft.world.level.block.state.pattern.BlockPattern;
import net.minecraft.core.Direction;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.entity.player.Player;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import java.util.Random;
import net.minecraft.server.level.ServerLevel;

public class PortalForcer {
    private final ServerLevel level;
    private final Random random;
    
    public PortalForcer(final ServerLevel xd) {
        this.level = xd;
        this.random = new Random(xd.getSeed());
    }
    
    public boolean findAndMoveToPortal(final Entity akq, final float float2) {
        final Vec3 cvl4 = akq.getPortalEntranceOffset();
        final Direction fp5 = akq.getPortalEntranceForwards();
        final BlockPattern.PortalInfo c6 = this.findPortal(new BlockPos(akq), akq.getDeltaMovement(), fp5, cvl4.x, cvl4.y, akq instanceof Player);
        if (c6 == null) {
            return false;
        }
        final Vec3 cvl5 = c6.pos;
        final Vec3 cvl6 = c6.speed;
        akq.setDeltaMovement(cvl6);
        akq.yRot = float2 + c6.angle;
        akq.forceMove(cvl5.x, cvl5.y, cvl5.z);
        return true;
    }
    
    @Nullable
    public BlockPattern.PortalInfo findPortal(final BlockPos fk, final Vec3 cvl, final Direction fp, final double double4, final double double5, final boolean boolean6) {
        final PoiManager asr10 = this.level.getPoiManager();
        asr10.ensureLoadedAndValid(this.level, fk, 128);
        final List<PoiRecord> list11 = asr10.getInSquare(asu -> asu == PoiType.NETHER_PORTAL, fk, 128, PoiManager.Occupancy.ANY).collect(Collectors.toList());
        final Optional<PoiRecord> optional12 = list11.stream().min(Comparator.comparingDouble(ass -> ass.getPos().distSqr(fk)).thenComparingInt(ass -> ass.getPos().getY()));
        final BlockPos fk2;
        final BlockPattern.BlockPatternMatch b10;
        return optional12.<BlockPattern.PortalInfo>map(ass -> {
            fk2 = ass.getPos();
            this.level.getChunkSource().<BlockPos>addRegionTicket(TicketType.PORTAL, new ChunkPos(fk2), 3, fk2);
            b10 = NetherPortalBlock.getPortalShape(this.level, fk2);
            return b10.getPortalOutput(fp, fk2, double5, cvl, double4);
        }).orElse(null);
    }
    
    public boolean createPortal(final Entity akq) {
        final int integer3 = 16;
        double double4 = -1.0;
        final int integer4 = Mth.floor(akq.getX());
        final int integer5 = Mth.floor(akq.getY());
        final int integer6 = Mth.floor(akq.getZ());
        int integer7 = integer4;
        int integer8 = integer5;
        int integer9 = integer6;
        int integer10 = 0;
        final int integer11 = this.random.nextInt(4);
        final BlockPos.MutableBlockPos a14 = new BlockPos.MutableBlockPos();
        for (int integer12 = integer4 - 16; integer12 <= integer4 + 16; ++integer12) {
            final double double5 = integer12 + 0.5 - akq.getX();
            for (int integer13 = integer6 - 16; integer13 <= integer6 + 16; ++integer13) {
                final double double6 = integer13 + 0.5 - akq.getZ();
            Label_0463:
                for (int integer14 = this.level.getHeight() - 1; integer14 >= 0; --integer14) {
                    if (this.level.isEmptyBlock(a14.set(integer12, integer14, integer13))) {
                        while (integer14 > 0 && this.level.isEmptyBlock(a14.set(integer12, integer14 - 1, integer13))) {
                            --integer14;
                        }
                        for (int integer15 = integer11; integer15 < integer11 + 4; ++integer15) {
                            int integer16 = integer15 % 2;
                            int integer17 = 1 - integer16;
                            if (integer15 % 4 >= 2) {
                                integer16 = -integer16;
                                integer17 = -integer17;
                            }
                            for (int integer18 = 0; integer18 < 3; ++integer18) {
                                for (int integer19 = 0; integer19 < 4; ++integer19) {
                                    for (int integer20 = -1; integer20 < 4; ++integer20) {
                                        final int integer21 = integer12 + (integer19 - 1) * integer16 + integer18 * integer17;
                                        final int integer22 = integer14 + integer20;
                                        final int integer23 = integer13 + (integer19 - 1) * integer17 - integer18 * integer16;
                                        a14.set(integer21, integer22, integer23);
                                        if (integer20 < 0 && !this.level.getBlockState(a14).getMaterial().isSolid()) {
                                            continue Label_0463;
                                        }
                                        if (integer20 >= 0 && !this.level.isEmptyBlock(a14)) {
                                            continue Label_0463;
                                        }
                                    }
                                }
                            }
                            final double double7 = integer14 + 0.5 - akq.getY();
                            final double double8 = double5 * double5 + double7 * double7 + double6 * double6;
                            if (double4 < 0.0 || double8 < double4) {
                                double4 = double8;
                                integer7 = integer12;
                                integer8 = integer14;
                                integer9 = integer13;
                                integer10 = integer15 % 4;
                            }
                        }
                    }
                }
            }
        }
        if (double4 < 0.0) {
            for (int integer12 = integer4 - 16; integer12 <= integer4 + 16; ++integer12) {
                final double double5 = integer12 + 0.5 - akq.getX();
                for (int integer13 = integer6 - 16; integer13 <= integer6 + 16; ++integer13) {
                    final double double6 = integer13 + 0.5 - akq.getZ();
                Label_0837:
                    for (int integer14 = this.level.getHeight() - 1; integer14 >= 0; --integer14) {
                        if (this.level.isEmptyBlock(a14.set(integer12, integer14, integer13))) {
                            while (integer14 > 0 && this.level.isEmptyBlock(a14.set(integer12, integer14 - 1, integer13))) {
                                --integer14;
                            }
                            for (int integer15 = integer11; integer15 < integer11 + 2; ++integer15) {
                                final int integer16 = integer15 % 2;
                                final int integer17 = 1 - integer16;
                                for (int integer18 = 0; integer18 < 4; ++integer18) {
                                    for (int integer19 = -1; integer19 < 4; ++integer19) {
                                        final int integer20 = integer12 + (integer18 - 1) * integer16;
                                        final int integer21 = integer14 + integer19;
                                        final int integer22 = integer13 + (integer18 - 1) * integer17;
                                        a14.set(integer20, integer21, integer22);
                                        if (integer19 < 0 && !this.level.getBlockState(a14).getMaterial().isSolid()) {
                                            continue Label_0837;
                                        }
                                        if (integer19 >= 0 && !this.level.isEmptyBlock(a14)) {
                                            continue Label_0837;
                                        }
                                    }
                                }
                                final double double7 = integer14 + 0.5 - akq.getY();
                                final double double8 = double5 * double5 + double7 * double7 + double6 * double6;
                                if (double4 < 0.0 || double8 < double4) {
                                    double4 = double8;
                                    integer7 = integer12;
                                    integer8 = integer14;
                                    integer9 = integer13;
                                    integer10 = integer15 % 2;
                                }
                            }
                        }
                    }
                }
            }
        }
        int integer12 = integer10;
        final int integer24 = integer7;
        int integer25 = integer8;
        int integer13 = integer9;
        int integer26 = integer12 % 2;
        int integer27 = 1 - integer26;
        if (integer12 % 4 >= 2) {
            integer26 = -integer26;
            integer27 = -integer27;
        }
        if (double4 < 0.0) {
            integer8 = (integer25 = Mth.clamp(integer8, 70, this.level.getHeight() - 10));
            for (int integer14 = -1; integer14 <= 1; ++integer14) {
                for (int integer15 = 1; integer15 < 3; ++integer15) {
                    for (int integer16 = -1; integer16 < 3; ++integer16) {
                        final int integer17 = integer24 + (integer15 - 1) * integer26 + integer14 * integer27;
                        final int integer18 = integer25 + integer16;
                        final int integer19 = integer13 + (integer15 - 1) * integer27 - integer14 * integer26;
                        final boolean boolean27 = integer16 < 0;
                        a14.set(integer17, integer18, integer19);
                        this.level.setBlockAndUpdate(a14, boolean27 ? Blocks.OBSIDIAN.defaultBlockState() : Blocks.AIR.defaultBlockState());
                    }
                }
            }
        }
        for (int integer14 = -1; integer14 < 3; ++integer14) {
            for (int integer15 = -1; integer15 < 4; ++integer15) {
                if (integer14 == -1 || integer14 == 2 || integer15 == -1 || integer15 == 3) {
                    a14.set(integer24 + integer14 * integer26, integer25 + integer15, integer13 + integer14 * integer27);
                    this.level.setBlock(a14, Blocks.OBSIDIAN.defaultBlockState(), 3);
                }
            }
        }
        final BlockState byj21 = ((AbstractStateHolder<O, BlockState>)Blocks.NETHER_PORTAL.defaultBlockState()).<Direction.Axis, Direction.Axis>setValue(NetherPortalBlock.AXIS, (integer26 == 0) ? Direction.Axis.Z : Direction.Axis.X);
        for (int integer15 = 0; integer15 < 2; ++integer15) {
            for (int integer16 = 0; integer16 < 3; ++integer16) {
                a14.set(integer24 + integer15 * integer26, integer25 + integer16, integer13 + integer15 * integer27);
                this.level.setBlock(a14, byj21, 18);
            }
        }
        return true;
    }
}
