package net.minecraft.world.entity.monster.hoglin;

import net.minecraft.util.TimeUtil;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.core.Vec3i;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.ai.memory.WalkTarget;
import net.minecraft.world.entity.ai.behavior.BehaviorUtils;
import net.minecraft.sounds.SoundEvent;
import java.util.function.Consumer;
import java.util.List;
import net.minecraft.world.entity.ai.behavior.DoNothing;
import net.minecraft.world.entity.ai.behavior.SetWalkTargetFromLookTarget;
import com.mojang.datafixers.util.Pair;
import net.minecraft.world.entity.ai.behavior.RandomStroll;
import net.minecraft.world.entity.ai.behavior.RunOne;
import java.util.function.Predicate;
import net.minecraft.world.entity.ai.behavior.StopAttackingIfTargetInvalid;
import net.minecraft.world.entity.AgableMob;
import net.minecraft.world.entity.ai.behavior.MeleeAttack;
import net.minecraft.world.entity.ai.behavior.SetWalkTargetFromAttackTargetIfTargetOutOfReach;
import net.minecraft.world.entity.ai.behavior.BabyFollowAdult;
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import java.util.Optional;
import java.util.function.Function;
import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.ai.behavior.AnimalMakeLove;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.behavior.BecomePassiveIfMemoryPresent;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.behavior.Behavior;
import com.google.common.collect.ImmutableList;
import net.minecraft.world.entity.ai.behavior.MoveToTargetSink;
import net.minecraft.world.entity.ai.behavior.LookAtTargetSink;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import net.minecraft.world.entity.schedule.Activity;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.util.IntRange;

public class HoglinAi {
    private static final IntRange RETREAT_DURATION;
    private static final IntRange ADULT_FOLLOW_RANGE;
    
    protected static Brain<?> makeBrain(final Brain<Hoglin> apr) {
        initCoreActivity(apr);
        initIdleActivity(apr);
        initFightActivity(apr);
        initRetreatActivity(apr);
        apr.setCoreActivities(ImmutableSet.<Activity>of(Activity.CORE));
        apr.setDefaultActivity(Activity.IDLE);
        apr.useDefaultActivity();
        return apr;
    }
    
    private static void initCoreActivity(final Brain<Hoglin> apr) {
        apr.addActivity(Activity.CORE, 0, ImmutableList.of(new LookAtTargetSink(45, 90), new MoveToTargetSink(200)));
    }
    
    private static void initIdleActivity(final Brain<Hoglin> apr) {
        apr.addActivity(Activity.IDLE, 10, ImmutableList.of(new BecomePassiveIfMemoryPresent(MemoryModuleType.NEAREST_REPELLENT, 200), new AnimalMakeLove(EntityType.HOGLIN, 0.6f), SetWalkTargetAwayFrom.pos(MemoryModuleType.NEAREST_REPELLENT, 1.0f, 8, true), new Behavior(HoglinAi::findNearestValidAttackTarget), new Behavior(Hoglin::isAdult, SetWalkTargetAwayFrom.entity(MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, 0.4f, 8, false)), new Behavior(new SetEntityLookTarget(8.0f), IntRange.of(30, 60)), new BabyFollowAdult(HoglinAi.ADULT_FOLLOW_RANGE, 0.6f), createIdleMovementBehaviors()));
    }
    
    private static void initFightActivity(final Brain<Hoglin> apr) {
        apr.addActivityAndRemoveMemoryWhenStopped(Activity.FIGHT, 10, ImmutableList.of(new BecomePassiveIfMemoryPresent(MemoryModuleType.NEAREST_REPELLENT, 200), new AnimalMakeLove(EntityType.HOGLIN, 0.6f), new SetWalkTargetFromAttackTargetIfTargetOutOfReach(1.0f), new Behavior(Hoglin::isAdult, new MeleeAttack(40)), new Behavior(AgableMob::isBaby, new MeleeAttack(15)), new StopAttackingIfTargetInvalid(), new Behavior(HoglinAi::isBreeding, MemoryModuleType.ATTACK_TARGET)), MemoryModuleType.ATTACK_TARGET);
    }
    
    private static void initRetreatActivity(final Brain<Hoglin> apr) {
        apr.addActivityAndRemoveMemoryWhenStopped(Activity.AVOID, 10, ImmutableList.of(SetWalkTargetAwayFrom.entity(MemoryModuleType.AVOID_TARGET, 1.3f, 15, false), createIdleMovementBehaviors(), new Behavior(new SetEntityLookTarget(8.0f), IntRange.of(30, 60)), new Behavior(HoglinAi::wantsToStopFleeing, MemoryModuleType.AVOID_TARGET)), MemoryModuleType.AVOID_TARGET);
    }
    
    private static RunOne<Hoglin> createIdleMovementBehaviors() {
        return new RunOne<Hoglin>(ImmutableList.of(Pair.of(new RandomStroll(0.4f), 2), Pair.of(new SetWalkTargetFromLookTarget(0.4f, 3), 2), Pair.of(new DoNothing(30, 60), 1)));
    }
    
    protected static void updateActivity(final Hoglin bcx) {
        final Brain<Hoglin> apr2 = bcx.getBrain();
        final Activity bfl3 = apr2.getActiveNonCoreActivity().orElse(null);
        apr2.setActiveActivityToFirstValid(ImmutableList.<Activity>of(Activity.FIGHT, Activity.AVOID, Activity.IDLE));
        final Activity bfl4 = apr2.getActiveNonCoreActivity().orElse(null);
        if (bfl3 != bfl4) {
            getSoundForCurrentActivity(bcx).ifPresent(bcx::playSound);
        }
        bcx.setAggressive(apr2.hasMemoryValue(MemoryModuleType.ATTACK_TARGET));
    }
    
    protected static void onHitTarget(final Hoglin bcx, final LivingEntity aoy) {
        if (bcx.isBaby()) {
            return;
        }
        if (aoy.getType() == EntityType.PIGLIN && piglinsOutnumberHoglins(bcx)) {
            setAvoidTarget(bcx, aoy);
            broadcastRetreat(bcx, aoy);
            return;
        }
        broadcastAttackTarget(bcx, aoy);
    }
    
    private static void broadcastRetreat(final Hoglin bcx, final LivingEntity aoy) {
        getVisibleAdultHoglins(bcx).forEach(bcx -> retreatFromNearestTarget(bcx, aoy));
    }
    
    private static void retreatFromNearestTarget(final Hoglin bcx, final LivingEntity aoy) {
        LivingEntity aoy2 = aoy;
        final Brain<Hoglin> apr4 = bcx.getBrain();
        aoy2 = BehaviorUtils.getNearestTarget(bcx, apr4.<LivingEntity>getMemory(MemoryModuleType.AVOID_TARGET), aoy2);
        aoy2 = BehaviorUtils.getNearestTarget(bcx, apr4.<LivingEntity>getMemory(MemoryModuleType.ATTACK_TARGET), aoy2);
        setAvoidTarget(bcx, aoy2);
    }
    
    private static void setAvoidTarget(final Hoglin bcx, final LivingEntity aoy) {
        bcx.getBrain().<LivingEntity>eraseMemory(MemoryModuleType.ATTACK_TARGET);
        bcx.getBrain().<WalkTarget>eraseMemory(MemoryModuleType.WALK_TARGET);
        bcx.getBrain().<LivingEntity>setMemoryWithExpiry(MemoryModuleType.AVOID_TARGET, aoy, HoglinAi.RETREAT_DURATION.randomValue(bcx.level.random));
    }
    
    private static Optional<? extends LivingEntity> findNearestValidAttackTarget(final Hoglin bcx) {
        if (isPacified(bcx) || isBreeding(bcx)) {
            return Optional.empty();
        }
        return bcx.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_TARGETABLE_PLAYER);
    }
    
    static boolean isPosNearNearestRepellent(final Hoglin bcx, final BlockPos fu) {
        final Optional<BlockPos> optional3 = bcx.getBrain().<BlockPos>getMemory(MemoryModuleType.NEAREST_REPELLENT);
        return optional3.isPresent() && optional3.get().closerThan(fu, 8.0);
    }
    
    private static boolean wantsToStopFleeing(final Hoglin bcx) {
        return bcx.isAdult() && !piglinsOutnumberHoglins(bcx);
    }
    
    private static boolean piglinsOutnumberHoglins(final Hoglin bcx) {
        if (bcx.isBaby()) {
            return false;
        }
        final int integer2 = bcx.getBrain().<Integer>getMemory(MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT).orElse(0);
        final int integer3 = bcx.getBrain().<Integer>getMemory(MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT).orElse(0) + 1;
        return integer2 > integer3;
    }
    
    protected static void wasHurtBy(final Hoglin bcx, final LivingEntity aoy) {
        final Brain<Hoglin> apr3 = bcx.getBrain();
        apr3.<Boolean>eraseMemory(MemoryModuleType.PACIFIED);
        apr3.<AgableMob>eraseMemory(MemoryModuleType.BREED_TARGET);
        if (bcx.isBaby()) {
            retreatFromNearestTarget(bcx, aoy);
            return;
        }
        maybeRetaliate(bcx, aoy);
    }
    
    private static void maybeRetaliate(final Hoglin bcx, final LivingEntity aoy) {
        if (bcx.getBrain().isActive(Activity.AVOID) && aoy.getType() == EntityType.PIGLIN) {
            return;
        }
        if (!EntitySelector.ATTACK_ALLOWED.test(aoy)) {
            return;
        }
        if (aoy.getType() == EntityType.HOGLIN) {
            return;
        }
        if (BehaviorUtils.isOtherTargetMuchFurtherAwayThanCurrentAttackTarget(bcx, aoy, 4.0)) {
            return;
        }
        setAttackTarget(bcx, aoy);
        broadcastAttackTarget(bcx, aoy);
    }
    
    private static void setAttackTarget(final Hoglin bcx, final LivingEntity aoy) {
        final Brain<Hoglin> apr3 = bcx.getBrain();
        apr3.<Long>eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE);
        apr3.<AgableMob>eraseMemory(MemoryModuleType.BREED_TARGET);
        apr3.<LivingEntity>setMemoryWithExpiry(MemoryModuleType.ATTACK_TARGET, aoy, 200L);
    }
    
    private static void broadcastAttackTarget(final Hoglin bcx, final LivingEntity aoy) {
        getVisibleAdultHoglins(bcx).forEach(bcx -> setAttackTargetIfCloserThanCurrent(bcx, aoy));
    }
    
    private static void setAttackTargetIfCloserThanCurrent(final Hoglin bcx, final LivingEntity aoy) {
        if (isPacified(bcx)) {
            return;
        }
        final Optional<LivingEntity> optional3 = bcx.getBrain().<LivingEntity>getMemory(MemoryModuleType.ATTACK_TARGET);
        final LivingEntity aoy2 = BehaviorUtils.getNearestTarget(bcx, optional3, aoy);
        setAttackTarget(bcx, aoy2);
    }
    
    public static Optional<SoundEvent> getSoundForCurrentActivity(final Hoglin bcx) {
        return bcx.getBrain().getActiveNonCoreActivity().<SoundEvent>map(bfl -> getSoundForActivity(bcx, bfl));
    }
    
    private static SoundEvent getSoundForActivity(final Hoglin bcx, final Activity bfl) {
        if (bfl == Activity.AVOID || bcx.isConverting()) {
            return SoundEvents.HOGLIN_RETREAT;
        }
        if (bfl == Activity.FIGHT) {
            return SoundEvents.HOGLIN_ANGRY;
        }
        if (isNearRepellent(bcx)) {
            return SoundEvents.HOGLIN_RETREAT;
        }
        return SoundEvents.HOGLIN_AMBIENT;
    }
    
    private static List<Hoglin> getVisibleAdultHoglins(final Hoglin bcx) {
        return bcx.getBrain().<List<Hoglin>>getMemory(MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS).orElse(ImmutableList.of());
    }
    
    private static boolean isNearRepellent(final Hoglin bcx) {
        return bcx.getBrain().hasMemoryValue(MemoryModuleType.NEAREST_REPELLENT);
    }
    
    private static boolean isBreeding(final Hoglin bcx) {
        return bcx.getBrain().hasMemoryValue(MemoryModuleType.BREED_TARGET);
    }
    
    protected static boolean isPacified(final Hoglin bcx) {
        return bcx.getBrain().hasMemoryValue(MemoryModuleType.PACIFIED);
    }
    
    static {
        RETREAT_DURATION = TimeUtil.rangeOfSeconds(5, 20);
        ADULT_FOLLOW_RANGE = IntRange.of(5, 16);
    }
}
