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.core.BlockPos;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import javax.annotation.Nullable;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.monster.SharedMonsterAttributes;
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 ala, final boolean boolean2) {
        this(ala, boolean2, false);
    }
    
    public TargetGoal(final Mob ala, final boolean boolean2, final boolean boolean3) {
        this.unseenMemoryTicks = 60;
        this.mob = ala;
        this.mustSee = boolean2;
        this.mustReach = boolean3;
    }
    
    @Override
    public boolean canContinueToUse() {
        LivingEntity akz2 = this.mob.getTarget();
        if (akz2 == null) {
            akz2 = this.targetMob;
        }
        if (akz2 == null) {
            return false;
        }
        if (!akz2.isAlive()) {
            return false;
        }
        final Team cwn3 = this.mob.getTeam();
        final Team cwn4 = akz2.getTeam();
        if (cwn3 != null && cwn4 == cwn3) {
            return false;
        }
        final double double5 = this.getFollowDistance();
        if (this.mob.distanceToSqr(akz2) > double5 * double5) {
            return false;
        }
        if (this.mustSee) {
            if (this.mob.getSensing().canSee(akz2)) {
                this.unseenTicks = 0;
            }
            else if (++this.unseenTicks > this.unseenMemoryTicks) {
                return false;
            }
        }
        if (akz2 instanceof Player && ((Player)akz2).abilities.invulnerable) {
            return false;
        }
        this.mob.setTarget(akz2);
        return true;
    }
    
    protected double getFollowDistance() {
        final AttributeInstance alr2 = this.mob.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE);
        return (alr2 == null) ? 16.0 : alr2.getValue();
    }
    
    @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 akz, final TargetingConditions ask) {
        if (akz == null) {
            return false;
        }
        if (!ask.test(this.mob, akz)) {
            return false;
        }
        if (!this.mob.isWithinRestriction(new BlockPos(akz))) {
            return false;
        }
        if (this.mustReach) {
            if (--this.reachCacheTime <= 0) {
                this.reachCache = 0;
            }
            if (this.reachCache == 0) {
                this.reachCache = (this.canReach(akz) ? 1 : 2);
            }
            if (this.reachCache == 2) {
                return false;
            }
        }
        return true;
    }
    
    private boolean canReach(final LivingEntity akz) {
        this.reachCacheTime = 10 + this.mob.getRandom().nextInt(5);
        final Path cqq3 = this.mob.getNavigation().createPath(akz, 0);
        if (cqq3 == null) {
            return false;
        }
        final Node cqo4 = cqq3.last();
        if (cqo4 == null) {
            return false;
        }
        final int integer5 = cqo4.x - Mth.floor(akz.getX());
        final int integer6 = cqo4.z - Mth.floor(akz.getZ());
        return integer5 * integer5 + integer6 * integer6 <= 2.25;
    }
    
    public TargetGoal setUnseenMemoryTicks(final int integer) {
        this.unseenMemoryTicks = integer;
        return this;
    }
}
