package net.minecraft.world.entity.ai.goal.target;

import net.minecraft.world.level.pathfinder.Node;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import javax.annotation.Nullable;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.scores.Team;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.Goal;

public abstract class TargetGoal extends Goal {
    protected final Mob mob;
    protected final boolean mustSee;
    private final boolean mustReach;
    private int reachCache;
    private int reachCacheTime;
    private int unseenTicks;
    protected LivingEntity targetMob;
    protected int unseenMemoryTicks;
    
    public TargetGoal(final Mob aoz, final boolean boolean2) {
        this(aoz, boolean2, false);
    }
    
    public TargetGoal(final Mob aoz, final boolean boolean2, final boolean boolean3) {
        this.unseenMemoryTicks = 60;
        this.mob = aoz;
        this.mustSee = boolean2;
        this.mustReach = boolean3;
    }
    
    @Override
    public boolean canContinueToUse() {
        LivingEntity aoy2 = this.mob.getTarget();
        if (aoy2 == null) {
            aoy2 = this.targetMob;
        }
        if (aoy2 == null) {
            return false;
        }
        if (!aoy2.isAlive()) {
            return false;
        }
        final Team dfo3 = this.mob.getTeam();
        final Team dfo4 = aoy2.getTeam();
        if (dfo3 != null && dfo4 == dfo3) {
            return false;
        }
        final double double5 = this.getFollowDistance();
        if (this.mob.distanceToSqr(aoy2) > double5 * double5) {
            return false;
        }
        if (this.mustSee) {
            if (this.mob.getSensing().canSee(aoy2)) {
                this.unseenTicks = 0;
            }
            else if (++this.unseenTicks > this.unseenMemoryTicks) {
                return false;
            }
        }
        if (aoy2 instanceof Player && ((Player)aoy2).abilities.invulnerable) {
            return false;
        }
        this.mob.setTarget(aoy2);
        return true;
    }
    
    protected double getFollowDistance() {
        return this.mob.getAttributeValue(Attributes.FOLLOW_RANGE);
    }
    
    @Override
    public void start() {
        this.reachCache = 0;
        this.reachCacheTime = 0;
        this.unseenTicks = 0;
    }
    
    @Override
    public void stop() {
        this.mob.setTarget(null);
        this.targetMob = null;
    }
    
    protected boolean canAttack(@Nullable final LivingEntity aoy, final TargetingConditions axs) {
        if (aoy == null) {
            return false;
        }
        if (!axs.test(this.mob, aoy)) {
            return false;
        }
        if (!this.mob.isWithinRestriction(aoy.blockPosition())) {
            return false;
        }
        if (this.mustReach) {
            if (--this.reachCacheTime <= 0) {
                this.reachCache = 0;
            }
            if (this.reachCache == 0) {
                this.reachCache = (this.canReach(aoy) ? 1 : 2);
            }
            if (this.reachCache == 2) {
                return false;
            }
        }
        return true;
    }
    
    private boolean canReach(final LivingEntity aoy) {
        this.reachCacheTime = 10 + this.mob.getRandom().nextInt(5);
        final Path czf3 = this.mob.getNavigation().createPath(aoy, 0);
        if (czf3 == null) {
            return false;
        }
        final Node czd4 = czf3.last();
        if (czd4 == null) {
            return false;
        }
        final int integer5 = czd4.x - Mth.floor(aoy.getX());
        final int integer6 = czd4.z - Mth.floor(aoy.getZ());
        return integer5 * integer5 + integer6 * integer6 <= 2.25;
    }
    
    public TargetGoal setUnseenMemoryTicks(final int integer) {
        this.unseenMemoryTicks = integer;
        return this;
    }
}
