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

import net.minecraft.world.level.BlockGetter;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.level.ClipContext;
import net.minecraft.Util;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.level.pathfinder.SwimNodeEvaluator;
import net.minecraft.world.entity.animal.Dolphin;
import net.minecraft.world.level.pathfinder.PathFinder;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.Mob;

public class WaterBoundPathNavigation extends PathNavigation {
    private boolean allowBreaching;
    
    public WaterBoundPathNavigation(final Mob ala, final Level bjw) {
        super(ala, bjw);
    }
    
    @Override
    protected PathFinder createPathFinder(final int integer) {
        this.allowBreaching = (this.mob instanceof Dolphin);
        this.nodeEvaluator = new SwimNodeEvaluator(this.allowBreaching);
        return new PathFinder(this.nodeEvaluator, integer);
    }
    
    @Override
    protected boolean canUpdatePath() {
        return this.allowBreaching || this.isInLiquid();
    }
    
    @Override
    protected Vec3 getTempMobPos() {
        return new Vec3(this.mob.getX(), this.mob.getY(0.5), this.mob.getZ());
    }
    
    @Override
    public void tick() {
        ++this.tick;
        if (this.hasDelayedRecomputation) {
            this.recomputePath();
        }
        if (this.isDone()) {
            return;
        }
        if (this.canUpdatePath()) {
            this.updatePath();
        }
        else if (this.path != null && this.path.getIndex() < this.path.getSize()) {
            final Vec3 cvl2 = this.path.getPos(this.mob, this.path.getIndex());
            if (Mth.floor(this.mob.getX()) == Mth.floor(cvl2.x) && Mth.floor(this.mob.getY()) == Mth.floor(cvl2.y) && Mth.floor(this.mob.getZ()) == Mth.floor(cvl2.z)) {
                this.path.setIndex(this.path.getIndex() + 1);
            }
        }
        DebugPackets.sendPathFindingPacket(this.level, this.mob, this.path, this.maxDistanceToWaypoint);
        if (this.isDone()) {
            return;
        }
        final Vec3 cvl2 = this.path.currentPos(this.mob);
        this.mob.getMoveControl().setWantedPosition(cvl2.x, cvl2.y, cvl2.z, this.speedModifier);
    }
    
    @Override
    protected void updatePath() {
        if (this.path == null) {
            return;
        }
        final Vec3 cvl2 = this.getTempMobPos();
        final float float3 = this.mob.getBbWidth();
        float float4 = (float3 > 0.75f) ? (float3 / 2.0f) : (0.75f - float3 / 2.0f);
        final Vec3 cvl3 = this.mob.getDeltaMovement();
        if (Math.abs(cvl3.x) > 0.2 || Math.abs(cvl3.z) > 0.2) {
            float4 *= (float)(cvl3.length() * 6.0);
        }
        final int integer6 = 6;
        Vec3 cvl4 = this.path.currentPos();
        if (Math.abs(this.mob.getX() - (cvl4.x + 0.5)) < float4 && Math.abs(this.mob.getZ() - (cvl4.z + 0.5)) < float4 && Math.abs(this.mob.getY() - cvl4.y) < float4 * 2.0f) {
            this.path.next();
        }
        for (int integer7 = Math.min(this.path.getIndex() + 6, this.path.getSize() - 1); integer7 > this.path.getIndex(); --integer7) {
            cvl4 = this.path.getPos(this.mob, integer7);
            if (cvl4.distanceToSqr(cvl2) <= 36.0) {
                if (this.canMoveDirectly(cvl2, cvl4, 0, 0, 0)) {
                    this.path.setIndex(integer7);
                    break;
                }
            }
        }
        this.doStuckDetection(cvl2);
    }
    
    @Override
    protected void doStuckDetection(final Vec3 cvl) {
        if (this.tick - this.lastStuckCheck > 100) {
            if (cvl.distanceToSqr(this.lastStuckCheckPos) < 2.25) {
                this.stop();
            }
            this.lastStuckCheck = this.tick;
            this.lastStuckCheckPos = cvl;
        }
        if (this.path != null && !this.path.isDone()) {
            final Vec3 cvl2 = this.path.currentPos();
            if (cvl2.equals(this.timeoutCachedNode)) {
                this.timeoutTimer += Util.getMillis() - this.lastTimeoutCheck;
            }
            else {
                this.timeoutCachedNode = cvl2;
                final double double4 = cvl.distanceTo(this.timeoutCachedNode);
                this.timeoutLimit = ((this.mob.getSpeed() > 0.0f) ? (double4 / this.mob.getSpeed() * 100.0) : 0.0);
            }
            if (this.timeoutLimit > 0.0 && this.timeoutTimer > this.timeoutLimit * 2.0) {
                this.timeoutCachedNode = Vec3.ZERO;
                this.timeoutTimer = 0L;
                this.timeoutLimit = 0.0;
                this.stop();
            }
            this.lastTimeoutCheck = Util.getMillis();
        }
    }
    
    @Override
    protected boolean canMoveDirectly(final Vec3 cvl1, final Vec3 cvl2, final int integer3, final int integer4, final int integer5) {
        final Vec3 cvl3 = new Vec3(cvl2.x, cvl2.y + this.mob.getBbHeight() * 0.5, cvl2.z);
        return this.level.clip(new ClipContext(cvl1, cvl3, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this.mob)).getType() == HitResult.Type.MISS;
    }
    
    @Override
    public boolean isStableDestination(final BlockPos fk) {
        return !this.level.getBlockState(fk).isSolidRender(this.level, fk);
    }
    
    @Override
    public void setCanFloat(final boolean boolean1) {
    }
}
