package net.minecraft.world.entity.ai.util;

import java.util.function.Predicate;
import net.minecraft.util.Mth;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import java.util.Random;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator;
import net.minecraft.tags.FluidTags;
import net.minecraft.world.entity.Entity;
import net.minecraft.core.Position;
import net.minecraft.core.BlockPos;
import java.util.function.ToDoubleFunction;
import javax.annotation.Nullable;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.entity.PathfinderMob;

public class RandomPos {
    @Nullable
    public static Vec3 getPos(final PathfinderMob alg, final int integer2, final int integer3) {
        return generateRandomPos(alg, integer2, integer3, 0, null, true, 1.5707963705062866, alg::getWalkTargetValue, false, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getAirPos(final PathfinderMob alg, final int integer2, final int integer3, final int integer4, @Nullable final Vec3 cvl, final double double6) {
        return generateRandomPos(alg, integer2, integer3, integer4, cvl, true, double6, alg::getWalkTargetValue, true, 0, 0, false);
    }
    
    @Nullable
    public static Vec3 getLandPos(final PathfinderMob alg, final int integer2, final int integer3) {
        return getLandPos(alg, integer2, integer3, alg::getWalkTargetValue);
    }
    
    @Nullable
    public static Vec3 getLandPos(final PathfinderMob alg, final int integer2, final int integer3, final ToDoubleFunction<BlockPos> toDoubleFunction) {
        return generateRandomPos(alg, integer2, integer3, 0, null, false, 0.0, toDoubleFunction, true, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getAboveLandPos(final PathfinderMob alg, final int integer2, final int integer3, final Vec3 cvl, final float float5, final int integer6, final int integer7) {
        return generateRandomPos(alg, integer2, integer3, 0, cvl, false, float5, alg::getWalkTargetValue, true, integer6, integer7, true);
    }
    
    @Nullable
    public static Vec3 getPosTowards(final PathfinderMob alg, final int integer2, final int integer3, final Vec3 cvl) {
        final Vec3 cvl2 = cvl.subtract(alg.getX(), alg.getY(), alg.getZ());
        return generateRandomPos(alg, integer2, integer3, 0, cvl2, true, 1.5707963705062866, alg::getWalkTargetValue, false, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getPosTowards(final PathfinderMob alg, final int integer2, final int integer3, final Vec3 cvl, final double double5) {
        final Vec3 cvl2 = cvl.subtract(alg.getX(), alg.getY(), alg.getZ());
        return generateRandomPos(alg, integer2, integer3, 0, cvl2, true, double5, alg::getWalkTargetValue, false, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getAirPosTowards(final PathfinderMob alg, final int integer2, final int integer3, final int integer4, final Vec3 cvl, final double double6) {
        final Vec3 cvl2 = cvl.subtract(alg.getX(), alg.getY(), alg.getZ());
        return generateRandomPos(alg, integer2, integer3, integer4, cvl2, false, double6, alg::getWalkTargetValue, true, 0, 0, false);
    }
    
    @Nullable
    public static Vec3 getPosAvoid(final PathfinderMob alg, final int integer2, final int integer3, final Vec3 cvl) {
        final Vec3 cvl2 = alg.position().subtract(cvl);
        return generateRandomPos(alg, integer2, integer3, 0, cvl2, true, 1.5707963705062866, alg::getWalkTargetValue, false, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getLandPosAvoid(final PathfinderMob alg, final int integer2, final int integer3, final Vec3 cvl) {
        final Vec3 cvl2 = alg.position().subtract(cvl);
        return generateRandomPos(alg, integer2, integer3, 0, cvl2, false, 1.5707963705062866, alg::getWalkTargetValue, true, 0, 0, true);
    }
    
    @Nullable
    private static Vec3 generateRandomPos(final PathfinderMob alg, final int integer2, final int integer3, final int integer4, @Nullable final Vec3 cvl, final boolean boolean6, final double double7, final ToDoubleFunction<BlockPos> toDoubleFunction, final boolean boolean9, final int integer10, final int integer11, final boolean boolean12) {
        final PathNavigation arr14 = alg.getNavigation();
        final Random random15 = alg.getRandom();
        final boolean boolean13 = alg.hasRestriction() && alg.getRestrictCenter().closerThan(alg.position(), alg.getRestrictRadius() + integer2 + 1.0);
        boolean boolean14 = false;
        double double8 = Double.NEGATIVE_INFINITY;
        BlockPos fk2 = new BlockPos(alg);
        for (int integer12 = 0; integer12 < 10; ++integer12) {
            final BlockPos fk3 = getRandomDelta(random15, integer2, integer3, integer4, cvl, double7);
            if (fk3 != null) {
                int integer13 = fk3.getX();
                final int integer14 = fk3.getY();
                int integer15 = fk3.getZ();
                if (alg.hasRestriction() && integer2 > 1) {
                    final BlockPos fk4 = alg.getRestrictCenter();
                    if (alg.getX() > fk4.getX()) {
                        integer13 -= random15.nextInt(integer2 / 2);
                    }
                    else {
                        integer13 += random15.nextInt(integer2 / 2);
                    }
                    if (alg.getZ() > fk4.getZ()) {
                        integer15 -= random15.nextInt(integer2 / 2);
                    }
                    else {
                        integer15 += random15.nextInt(integer2 / 2);
                    }
                }
                BlockPos fk4 = new BlockPos(integer13 + alg.getX(), integer14 + alg.getY(), integer15 + alg.getZ());
                if (fk4.getY() >= 0) {
                    if (fk4.getY() <= alg.level.getMaxBuildHeight()) {
                        if (!boolean13 || alg.isWithinRestriction(fk4)) {
                            if (!boolean12 || arr14.isStableDestination(fk4)) {
                                if (boolean9) {
                                    fk4 = moveUpToAboveSolid(fk4, random15.nextInt(integer10 + 1) + integer11, alg.level.getMaxBuildHeight(), fk -> alg.level.getBlockState(fk).getMaterial().isSolid());
                                }
                                if (boolean6 || !alg.level.getFluidState(fk4).is(FluidTags.WATER)) {
                                    final BlockPathTypes cqm27 = WalkNodeEvaluator.getBlockPathTypeStatic(alg.level, fk4.getX(), fk4.getY(), fk4.getZ());
                                    if (alg.getPathfindingMalus(cqm27) == 0.0f) {
                                        final double double9 = toDoubleFunction.applyAsDouble(fk4);
                                        if (double9 > double8) {
                                            double8 = double9;
                                            fk2 = fk4;
                                            boolean14 = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (boolean14) {
            return new Vec3(fk2);
        }
        return null;
    }
    
    @Nullable
    private static BlockPos getRandomDelta(final Random random, final int integer2, final int integer3, final int integer4, @Nullable final Vec3 cvl, final double double6) {
        if (cvl == null || double6 >= 3.141592653589793) {
            final int integer5 = random.nextInt(2 * integer2 + 1) - integer2;
            final int integer6 = random.nextInt(2 * integer3 + 1) - integer3 + integer4;
            final int integer7 = random.nextInt(2 * integer2 + 1) - integer2;
            return new BlockPos(integer5, integer6, integer7);
        }
        final double double7 = Mth.atan2(cvl.z, cvl.x) - 1.5707963705062866;
        final double double8 = double7 + (2.0f * random.nextFloat() - 1.0f) * double6;
        final double double9 = Math.sqrt(random.nextDouble()) * Mth.SQRT_OF_TWO * integer2;
        final double double10 = -double9 * Math.sin(double8);
        final double double11 = double9 * Math.cos(double8);
        if (Math.abs(double10) > integer2 || Math.abs(double11) > integer2) {
            return null;
        }
        final int integer8 = random.nextInt(2 * integer3 + 1) - integer3 + integer4;
        return new BlockPos(double10, integer8, double11);
    }
    
    static BlockPos moveUpToAboveSolid(final BlockPos fk, final int integer2, final int integer3, final Predicate<BlockPos> predicate) {
        if (integer2 < 0) {
            throw new IllegalArgumentException("aboveSolidAmount was " + integer2 + ", expected >= 0");
        }
        if (predicate.test(fk)) {
            BlockPos fk2;
            for (fk2 = fk.above(); fk2.getY() < integer3 && predicate.test(fk2); fk2 = fk2.above()) {}
            BlockPos fk3;
            BlockPos fk4;
            for (fk3 = fk2; fk3.getY() < integer3 && fk3.getY() - fk2.getY() < integer2; fk3 = fk4) {
                fk4 = fk3.above();
                if (predicate.test(fk4)) {
                    break;
                }
            }
            return fk3;
        }
        return fk;
    }
}
