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.world.level.material.Fluid;
import net.minecraft.tags.Tag;
import net.minecraft.tags.FluidTags;
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 apg, final int integer2, final int integer3) {
        return generateRandomPos(apg, integer2, integer3, 0, null, true, 1.5707963705062866, apg::getWalkTargetValue, false, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getAirPos(final PathfinderMob apg, final int integer2, final int integer3, final int integer4, @Nullable final Vec3 dem, final double double6) {
        return generateRandomPos(apg, integer2, integer3, integer4, dem, true, double6, apg::getWalkTargetValue, true, 0, 0, false);
    }
    
    @Nullable
    public static Vec3 getLandPos(final PathfinderMob apg, final int integer2, final int integer3) {
        return getLandPos(apg, integer2, integer3, apg::getWalkTargetValue);
    }
    
    @Nullable
    public static Vec3 getLandPos(final PathfinderMob apg, final int integer2, final int integer3, final ToDoubleFunction<BlockPos> toDoubleFunction) {
        return generateRandomPos(apg, integer2, integer3, 0, null, false, 0.0, toDoubleFunction, true, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getAboveLandPos(final PathfinderMob apg, final int integer2, final int integer3, final Vec3 dem, final float float5, final int integer6, final int integer7) {
        return generateRandomPos(apg, integer2, integer3, 0, dem, false, float5, apg::getWalkTargetValue, true, integer6, integer7, true);
    }
    
    @Nullable
    public static Vec3 getLandPosTowards(final PathfinderMob apg, final int integer2, final int integer3, final Vec3 dem) {
        final Vec3 dem2 = dem.subtract(apg.getX(), apg.getY(), apg.getZ());
        return generateRandomPos(apg, integer2, integer3, 0, dem2, false, 1.5707963705062866, apg::getWalkTargetValue, true, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getPosTowards(final PathfinderMob apg, final int integer2, final int integer3, final Vec3 dem) {
        final Vec3 dem2 = dem.subtract(apg.getX(), apg.getY(), apg.getZ());
        return generateRandomPos(apg, integer2, integer3, 0, dem2, true, 1.5707963705062866, apg::getWalkTargetValue, false, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getPosTowards(final PathfinderMob apg, final int integer2, final int integer3, final Vec3 dem, final double double5) {
        final Vec3 dem2 = dem.subtract(apg.getX(), apg.getY(), apg.getZ());
        return generateRandomPos(apg, integer2, integer3, 0, dem2, true, double5, apg::getWalkTargetValue, false, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getAirPosTowards(final PathfinderMob apg, final int integer2, final int integer3, final int integer4, final Vec3 dem, final double double6) {
        final Vec3 dem2 = dem.subtract(apg.getX(), apg.getY(), apg.getZ());
        return generateRandomPos(apg, integer2, integer3, integer4, dem2, false, double6, apg::getWalkTargetValue, true, 0, 0, false);
    }
    
    @Nullable
    public static Vec3 getPosAvoid(final PathfinderMob apg, final int integer2, final int integer3, final Vec3 dem) {
        final Vec3 dem2 = apg.position().subtract(dem);
        return generateRandomPos(apg, integer2, integer3, 0, dem2, true, 1.5707963705062866, apg::getWalkTargetValue, false, 0, 0, true);
    }
    
    @Nullable
    public static Vec3 getLandPosAvoid(final PathfinderMob apg, final int integer2, final int integer3, final Vec3 dem) {
        final Vec3 dem2 = apg.position().subtract(dem);
        return generateRandomPos(apg, integer2, integer3, 0, dem2, false, 1.5707963705062866, apg::getWalkTargetValue, true, 0, 0, true);
    }
    
    @Nullable
    private static Vec3 generateRandomPos(final PathfinderMob apg, final int integer2, final int integer3, final int integer4, @Nullable final Vec3 dem, final boolean boolean6, final double double7, final ToDoubleFunction<BlockPos> toDoubleFunction, final boolean boolean9, final int integer10, final int integer11, final boolean boolean12) {
        final PathNavigation awv14 = apg.getNavigation();
        final Random random15 = apg.getRandom();
        final boolean boolean13 = apg.hasRestriction() && apg.getRestrictCenter().closerThan(apg.position(), apg.getRestrictRadius() + integer2 + 1.0);
        boolean boolean14 = false;
        double double8 = Double.NEGATIVE_INFINITY;
        BlockPos fu2 = apg.blockPosition();
        for (int integer12 = 0; integer12 < 10; ++integer12) {
            final BlockPos fu3 = getRandomDelta(random15, integer2, integer3, integer4, dem, double7);
            if (fu3 != null) {
                int integer13 = fu3.getX();
                final int integer14 = fu3.getY();
                int integer15 = fu3.getZ();
                if (apg.hasRestriction() && integer2 > 1) {
                    final BlockPos fu4 = apg.getRestrictCenter();
                    if (apg.getX() > fu4.getX()) {
                        integer13 -= random15.nextInt(integer2 / 2);
                    }
                    else {
                        integer13 += random15.nextInt(integer2 / 2);
                    }
                    if (apg.getZ() > fu4.getZ()) {
                        integer15 -= random15.nextInt(integer2 / 2);
                    }
                    else {
                        integer15 += random15.nextInt(integer2 / 2);
                    }
                }
                BlockPos fu4 = new BlockPos(integer13 + apg.getX(), integer14 + apg.getY(), integer15 + apg.getZ());
                if (fu4.getY() >= 0) {
                    if (fu4.getY() <= apg.level.getMaxBuildHeight()) {
                        if (!boolean13 || apg.isWithinRestriction(fu4)) {
                            if (!boolean12 || awv14.isStableDestination(fu4)) {
                                if (boolean9) {
                                    fu4 = moveUpToAboveSolid(fu4, random15.nextInt(integer10 + 1) + integer11, apg.level.getMaxBuildHeight(), fu -> apg.level.getBlockState(fu).getMaterial().isSolid());
                                }
                                if (boolean6 || !apg.level.getFluidState(fu4).is(FluidTags.WATER)) {
                                    final BlockPathTypes czb27 = WalkNodeEvaluator.getBlockPathTypeStatic(apg.level, fu4.mutable());
                                    if (apg.getPathfindingMalus(czb27) == 0.0f) {
                                        final double double9 = toDoubleFunction.applyAsDouble(fu4);
                                        if (double9 > double8) {
                                            double8 = double9;
                                            fu2 = fu4;
                                            boolean14 = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (boolean14) {
            return Vec3.atBottomCenterOf(fu2);
        }
        return null;
    }
    
    @Nullable
    private static BlockPos getRandomDelta(final Random random, final int integer2, final int integer3, final int integer4, @Nullable final Vec3 dem, final double double6) {
        if (dem == 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(dem.z, dem.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 fu, final int integer2, final int integer3, final Predicate<BlockPos> predicate) {
        if (integer2 < 0) {
            throw new IllegalArgumentException("aboveSolidAmount was " + integer2 + ", expected >= 0");
        }
        if (predicate.test(fu)) {
            BlockPos fu2;
            for (fu2 = fu.above(); fu2.getY() < integer3 && predicate.test(fu2); fu2 = fu2.above()) {}
            BlockPos fu3;
            BlockPos fu4;
            for (fu3 = fu2; fu3.getY() < integer3 && fu3.getY() - fu2.getY() < integer2; fu3 = fu4) {
                fu4 = fu3.above();
                if (predicate.test(fu4)) {
                    break;
                }
            }
            return fu3;
        }
        return fu;
    }
}
