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

import java.util.function.Supplier;
import java.util.stream.Stream;
import net.minecraft.world.entity.npc.Villager;
import java.util.UUID;
import java.util.Optional;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ProjectileWeaponItem;
import net.minecraft.world.entity.Mob;
import java.util.function.ToIntFunction;
import java.util.Comparator;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.ai.memory.WalkTarget;
import net.minecraft.world.entity.Entity;
import java.util.function.Predicate;
import net.minecraft.world.entity.EntityType;
import java.util.List;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.world.entity.LivingEntity;

public class BehaviorUtils {
    public static void lockGazeAndWalkToEachOther(final LivingEntity aoy1, final LivingEntity aoy2, final float float3) {
        lookAtEachOther(aoy1, aoy2);
        setWalkAndLookTargetMemoriesToEachOther(aoy1, aoy2, float3);
    }
    
    public static boolean entityIsVisible(final Brain<?> apr, final LivingEntity aoy) {
        return apr.<List<LivingEntity>>getMemory(MemoryModuleType.VISIBLE_LIVING_ENTITIES).filter(list -> list.contains(aoy)).isPresent();
    }
    
    public static boolean targetIsValid(final Brain<?> apr, final MemoryModuleType<? extends LivingEntity> awp, final EntityType<?> aoq) {
        return targetIsValid(apr, awp, aoy -> aoy.getType() == aoq);
    }
    
    private static boolean targetIsValid(final Brain<?> apr, final MemoryModuleType<? extends LivingEntity> awp, final Predicate<LivingEntity> predicate) {
        return apr.getMemory(awp).filter(predicate).filter(LivingEntity::isAlive).filter(aoy -> entityIsVisible(apr, aoy)).isPresent();
    }
    
    private static void lookAtEachOther(final LivingEntity aoy1, final LivingEntity aoy2) {
        lookAtEntity(aoy1, aoy2);
        lookAtEntity(aoy2, aoy1);
    }
    
    public static void lookAtEntity(final LivingEntity aoy1, final LivingEntity aoy2) {
        aoy1.getBrain().<EntityTracker>setMemory((MemoryModuleType<EntityTracker>)MemoryModuleType.LOOK_TARGET, new EntityTracker(aoy2, true));
    }
    
    private static void setWalkAndLookTargetMemoriesToEachOther(final LivingEntity aoy1, final LivingEntity aoy2, final float float3) {
        final int integer4 = 2;
        setWalkAndLookTargetMemories(aoy1, aoy2, float3, 2);
        setWalkAndLookTargetMemories(aoy2, aoy1, float3, 2);
    }
    
    public static void setWalkAndLookTargetMemories(final LivingEntity aoy, final Entity aom, final float float3, final int integer) {
        final WalkTarget awr5 = new WalkTarget(new EntityTracker(aom, false), float3, integer);
        aoy.getBrain().<EntityTracker>setMemory((MemoryModuleType<EntityTracker>)MemoryModuleType.LOOK_TARGET, new EntityTracker(aom, true));
        aoy.getBrain().<WalkTarget>setMemory(MemoryModuleType.WALK_TARGET, awr5);
    }
    
    public static void setWalkAndLookTargetMemories(final LivingEntity aoy, final BlockPos fu, final float float3, final int integer) {
        final WalkTarget awr5 = new WalkTarget(new BlockPosTracker(fu), float3, integer);
        aoy.getBrain().<BlockPosTracker>setMemory((MemoryModuleType<BlockPosTracker>)MemoryModuleType.LOOK_TARGET, new BlockPosTracker(fu));
        aoy.getBrain().<WalkTarget>setMemory(MemoryModuleType.WALK_TARGET, awr5);
    }
    
    public static void throwItem(final LivingEntity aoy, final ItemStack bki, final Vec3 dem) {
        final double double4 = aoy.getEyeY() - 0.30000001192092896;
        final ItemEntity bbg6 = new ItemEntity(aoy.level, aoy.getX(), double4, aoy.getZ(), bki);
        final float float7 = 0.3f;
        Vec3 dem2 = dem.subtract(aoy.position());
        dem2 = dem2.normalize().scale(0.30000001192092896);
        bbg6.setDeltaMovement(dem2);
        bbg6.setDefaultPickUpDelay();
        aoy.level.addFreshEntity(bbg6);
    }
    
    public static SectionPos findSectionClosestToVillage(final ServerLevel zd, final SectionPos go, final int integer) {
        final int integer2 = zd.sectionsToVillage(go);
        return SectionPos.cube(go, integer).filter(go -> zd.sectionsToVillage(go) < integer2).min(Comparator.comparingInt(zd::sectionsToVillage)).orElse(go);
    }
    
    public static boolean isWithinAttackRange(final Mob aoz, final LivingEntity aoy, final int integer) {
        final Item bke4 = aoz.getMainHandItem().getItem();
        if (bke4 instanceof ProjectileWeaponItem && aoz.canFireProjectileWeapon((ProjectileWeaponItem)bke4)) {
            final int integer2 = ((ProjectileWeaponItem)bke4).getDefaultProjectileRange() - integer;
            return aoz.closerThan(aoy, integer2);
        }
        return isWithinMeleeAttackRange(aoz, aoy);
    }
    
    public static boolean isWithinMeleeAttackRange(final LivingEntity aoy1, final LivingEntity aoy2) {
        final double double3 = aoy1.distanceToSqr(aoy2.getX(), aoy2.getY(), aoy2.getZ());
        final double double4 = aoy1.getBbWidth() * 2.0f * (aoy1.getBbWidth() * 2.0f) + aoy2.getBbWidth();
        return double3 <= double4;
    }
    
    public static boolean isOtherTargetMuchFurtherAwayThanCurrentAttackTarget(final LivingEntity aoy1, final LivingEntity aoy2, final double double3) {
        final Optional<LivingEntity> optional5 = aoy1.getBrain().<LivingEntity>getMemory(MemoryModuleType.ATTACK_TARGET);
        if (!optional5.isPresent()) {
            return false;
        }
        final double double4 = aoy1.distanceToSqr(optional5.get().position());
        final double double5 = aoy1.distanceToSqr(aoy2.position());
        return double5 > double4 + double3 * double3;
    }
    
    public static boolean canSee(final LivingEntity aoy1, final LivingEntity aoy2) {
        final Brain<?> apr3 = aoy1.getBrain();
        return apr3.hasMemoryValue(MemoryModuleType.VISIBLE_LIVING_ENTITIES) && apr3.<List<LivingEntity>>getMemory(MemoryModuleType.VISIBLE_LIVING_ENTITIES).get().contains(aoy2);
    }
    
    public static LivingEntity getNearestTarget(final LivingEntity aoy1, final Optional<LivingEntity> optional, final LivingEntity aoy3) {
        if (!optional.isPresent()) {
            return aoy3;
        }
        return getTargetNearestMe(aoy1, optional.get(), aoy3);
    }
    
    public static LivingEntity getTargetNearestMe(final LivingEntity aoy1, final LivingEntity aoy2, final LivingEntity aoy3) {
        final Vec3 dem4 = aoy2.position();
        final Vec3 dem5 = aoy3.position();
        return (aoy1.distanceToSqr(dem4) < aoy1.distanceToSqr(dem5)) ? aoy2 : aoy3;
    }
    
    public static Optional<LivingEntity> getLivingEntityFromUUIDMemory(final LivingEntity aoy, final MemoryModuleType<UUID> awp) {
        final Optional<UUID> optional3 = aoy.getBrain().<UUID>getMemory(awp);
        return optional3.<LivingEntity>map(uUID -> (LivingEntity)((ServerLevel)aoy.level).getEntity(uUID));
    }
    
    public static Stream<Villager> getNearbyVillagersWithCondition(final Villager bdp, final Predicate<Villager> predicate) {
        return bdp.getBrain().<List<LivingEntity>>getMemory(MemoryModuleType.LIVING_ENTITIES).<Stream<Villager>>map(list -> list.stream().filter(aoy -> aoy instanceof Villager && aoy != bdp).map(aoy -> aoy).filter(LivingEntity::isAlive).filter(predicate)).orElseGet(Stream::empty);
    }
}
