package net.minecraft.world.level.pathfinder;

import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BaseRailBlock;
import javax.annotation.Nullable;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.level.PathNavigationRegion;

public class TurtleNodeEvaluator extends WalkNodeEvaluator {
    private float oldWalkableCost;
    private float oldWaterBorderCost;
    
    @Override
    public void prepare(final PathNavigationRegion bkh, final Mob ala) {
        super.prepare(bkh, ala);
        ala.setPathfindingMalus(BlockPathTypes.WATER, 0.0f);
        this.oldWalkableCost = ala.getPathfindingMalus(BlockPathTypes.WALKABLE);
        ala.setPathfindingMalus(BlockPathTypes.WALKABLE, 6.0f);
        this.oldWaterBorderCost = ala.getPathfindingMalus(BlockPathTypes.WATER_BORDER);
        ala.setPathfindingMalus(BlockPathTypes.WATER_BORDER, 4.0f);
    }
    
    @Override
    public void done() {
        this.mob.setPathfindingMalus(BlockPathTypes.WALKABLE, this.oldWalkableCost);
        this.mob.setPathfindingMalus(BlockPathTypes.WATER_BORDER, this.oldWaterBorderCost);
        super.done();
    }
    
    @Override
    public Node getStart() {
        return this.getNode(Mth.floor(this.mob.getBoundingBox().minX), Mth.floor(this.mob.getBoundingBox().minY + 0.5), Mth.floor(this.mob.getBoundingBox().minZ));
    }
    
    @Override
    public Target getGoal(final double double1, final double double2, final double double3) {
        return new Target(this.getNode(Mth.floor(double1), Mth.floor(double2 + 0.5), Mth.floor(double3)));
    }
    
    @Override
    public int getNeighbors(final Node[] arr, final Node cqo) {
        int integer4 = 0;
        final int integer5 = 1;
        final BlockPos fk6 = new BlockPos(cqo.x, cqo.y, cqo.z);
        final double double7 = this.inWaterDependentPosHeight(fk6);
        final Node cqo2 = this.getAcceptedNode(cqo.x, cqo.y, cqo.z + 1, 1, double7);
        final Node cqo3 = this.getAcceptedNode(cqo.x - 1, cqo.y, cqo.z, 1, double7);
        final Node cqo4 = this.getAcceptedNode(cqo.x + 1, cqo.y, cqo.z, 1, double7);
        final Node cqo5 = this.getAcceptedNode(cqo.x, cqo.y, cqo.z - 1, 1, double7);
        final Node cqo6 = this.getAcceptedNode(cqo.x, cqo.y + 1, cqo.z, 0, double7);
        final Node cqo7 = this.getAcceptedNode(cqo.x, cqo.y - 1, cqo.z, 1, double7);
        if (cqo2 != null && !cqo2.closed) {
            arr[integer4++] = cqo2;
        }
        if (cqo3 != null && !cqo3.closed) {
            arr[integer4++] = cqo3;
        }
        if (cqo4 != null && !cqo4.closed) {
            arr[integer4++] = cqo4;
        }
        if (cqo5 != null && !cqo5.closed) {
            arr[integer4++] = cqo5;
        }
        if (cqo6 != null && !cqo6.closed) {
            arr[integer4++] = cqo6;
        }
        if (cqo7 != null && !cqo7.closed) {
            arr[integer4++] = cqo7;
        }
        final boolean boolean15 = cqo5 == null || cqo5.type == BlockPathTypes.OPEN || cqo5.costMalus != 0.0f;
        final boolean boolean16 = cqo2 == null || cqo2.type == BlockPathTypes.OPEN || cqo2.costMalus != 0.0f;
        final boolean boolean17 = cqo4 == null || cqo4.type == BlockPathTypes.OPEN || cqo4.costMalus != 0.0f;
        final boolean boolean18 = cqo3 == null || cqo3.type == BlockPathTypes.OPEN || cqo3.costMalus != 0.0f;
        if (boolean15 && boolean18) {
            final Node cqo8 = this.getAcceptedNode(cqo.x - 1, cqo.y, cqo.z - 1, 1, double7);
            if (cqo8 != null && !cqo8.closed) {
                arr[integer4++] = cqo8;
            }
        }
        if (boolean15 && boolean17) {
            final Node cqo8 = this.getAcceptedNode(cqo.x + 1, cqo.y, cqo.z - 1, 1, double7);
            if (cqo8 != null && !cqo8.closed) {
                arr[integer4++] = cqo8;
            }
        }
        if (boolean16 && boolean18) {
            final Node cqo8 = this.getAcceptedNode(cqo.x - 1, cqo.y, cqo.z + 1, 1, double7);
            if (cqo8 != null && !cqo8.closed) {
                arr[integer4++] = cqo8;
            }
        }
        if (boolean16 && boolean17) {
            final Node cqo8 = this.getAcceptedNode(cqo.x + 1, cqo.y, cqo.z + 1, 1, double7);
            if (cqo8 != null && !cqo8.closed) {
                arr[integer4++] = cqo8;
            }
        }
        return integer4;
    }
    
    private double inWaterDependentPosHeight(final BlockPos fk) {
        if (!this.mob.isInWater()) {
            final BlockPos fk2 = fk.below();
            final VoxelShape cwf4 = this.level.getBlockState(fk2).getCollisionShape(this.level, fk2);
            return fk2.getY() + (cwf4.isEmpty() ? 0.0 : cwf4.max(Direction.Axis.Y));
        }
        return fk.getY() + 0.5;
    }
    
    @Nullable
    private Node getAcceptedNode(final int integer1, int integer2, final int integer3, final int integer4, final double double5) {
        Node cqo8 = null;
        final BlockPos fk9 = new BlockPos(integer1, integer2, integer3);
        final double double6 = this.inWaterDependentPosHeight(fk9);
        if (double6 - double5 > 1.125) {
            return null;
        }
        BlockPathTypes cqm12 = this.getBlockPathType(this.level, integer1, integer2, integer3, this.mob, this.entityWidth, this.entityHeight, this.entityDepth, false, false);
        float float13 = this.mob.getPathfindingMalus(cqm12);
        final double double7 = this.mob.getBbWidth() / 2.0;
        if (float13 >= 0.0f) {
            cqo8 = this.getNode(integer1, integer2, integer3);
            cqo8.type = cqm12;
            cqo8.costMalus = Math.max(cqo8.costMalus, float13);
        }
        if (cqm12 == BlockPathTypes.WATER || cqm12 == BlockPathTypes.WALKABLE) {
            if (integer2 < this.mob.level.getSeaLevel() - 10 && cqo8 != null) {
                final Node node = cqo8;
                ++node.costMalus;
            }
            return cqo8;
        }
        if (cqo8 == null && integer4 > 0 && cqm12 != BlockPathTypes.FENCE && cqm12 != BlockPathTypes.TRAPDOOR) {
            cqo8 = this.getAcceptedNode(integer1, integer2 + 1, integer3, integer4 - 1, double5);
        }
        if (cqm12 == BlockPathTypes.OPEN) {
            final AABB cvf16 = new AABB(integer1 - double7 + 0.5, integer2 + 0.001, integer3 - double7 + 0.5, integer1 + double7 + 0.5, integer2 + this.mob.getBbHeight(), integer3 + double7 + 0.5);
            if (!this.mob.level.noCollision(this.mob, cvf16)) {
                return null;
            }
            final BlockPathTypes cqm13 = this.getBlockPathType(this.level, integer1, integer2 - 1, integer3, this.mob, this.entityWidth, this.entityHeight, this.entityDepth, false, false);
            if (cqm13 == BlockPathTypes.BLOCKED) {
                cqo8 = this.getNode(integer1, integer2, integer3);
                cqo8.type = BlockPathTypes.WALKABLE;
                cqo8.costMalus = Math.max(cqo8.costMalus, float13);
                return cqo8;
            }
            if (cqm13 == BlockPathTypes.WATER) {
                cqo8 = this.getNode(integer1, integer2, integer3);
                cqo8.type = BlockPathTypes.WATER;
                cqo8.costMalus = Math.max(cqo8.costMalus, float13);
                return cqo8;
            }
            int integer5 = 0;
            while (integer2 > 0 && cqm12 == BlockPathTypes.OPEN) {
                --integer2;
                if (integer5++ >= this.mob.getMaxFallDistance()) {
                    return null;
                }
                cqm12 = this.getBlockPathType(this.level, integer1, integer2, integer3, this.mob, this.entityWidth, this.entityHeight, this.entityDepth, false, false);
                float13 = this.mob.getPathfindingMalus(cqm12);
                if (cqm12 != BlockPathTypes.OPEN && float13 >= 0.0f) {
                    cqo8 = this.getNode(integer1, integer2, integer3);
                    cqo8.type = cqm12;
                    cqo8.costMalus = Math.max(cqo8.costMalus, float13);
                    break;
                }
                if (float13 < 0.0f) {
                    return null;
                }
            }
        }
        return cqo8;
    }
    
    @Override
    protected BlockPathTypes evaluateBlockPathType(final BlockGetter bjg, final boolean boolean2, final boolean boolean3, final BlockPos fk, BlockPathTypes cqm) {
        if (cqm == BlockPathTypes.RAIL && !(bjg.getBlockState(fk).getBlock() instanceof BaseRailBlock) && !(bjg.getBlockState(fk.below()).getBlock() instanceof BaseRailBlock)) {
            cqm = BlockPathTypes.FENCE;
        }
        if (cqm == BlockPathTypes.DOOR_OPEN || cqm == BlockPathTypes.DOOR_WOOD_CLOSED || cqm == BlockPathTypes.DOOR_IRON_CLOSED) {
            cqm = BlockPathTypes.BLOCKED;
        }
        if (cqm == BlockPathTypes.LEAVES) {
            cqm = BlockPathTypes.BLOCKED;
        }
        return cqm;
    }
    
    @Override
    public BlockPathTypes getBlockPathType(final BlockGetter bjg, final int integer2, final int integer3, final int integer4) {
        BlockPathTypes cqm6 = WalkNodeEvaluator.getBlockPathTypeRaw(bjg, integer2, integer3, integer4);
        if (cqm6 == BlockPathTypes.WATER) {
            for (final Direction fp10 : Direction.values()) {
                final BlockPathTypes cqm7 = WalkNodeEvaluator.getBlockPathTypeRaw(bjg, integer2 + fp10.getStepX(), integer3 + fp10.getStepY(), integer4 + fp10.getStepZ());
                if (cqm7 == BlockPathTypes.BLOCKED) {
                    return BlockPathTypes.WATER_BORDER;
                }
            }
            return BlockPathTypes.WATER;
        }
        if (cqm6 == BlockPathTypes.OPEN && integer3 >= 1) {
            final Block bph7 = bjg.getBlockState(new BlockPos(integer2, integer3 - 1, integer4)).getBlock();
            final BlockPathTypes cqm8 = WalkNodeEvaluator.getBlockPathTypeRaw(bjg, integer2, integer3 - 1, integer4);
            if (cqm8 == BlockPathTypes.WALKABLE || cqm8 == BlockPathTypes.OPEN || cqm8 == BlockPathTypes.LAVA) {
                cqm6 = BlockPathTypes.OPEN;
            }
            else {
                cqm6 = BlockPathTypes.WALKABLE;
            }
            if (cqm8 == BlockPathTypes.DAMAGE_FIRE || bph7 == Blocks.MAGMA_BLOCK || bph7 == Blocks.CAMPFIRE) {
                cqm6 = BlockPathTypes.DAMAGE_FIRE;
            }
            if (cqm8 == BlockPathTypes.DAMAGE_CACTUS) {
                cqm6 = BlockPathTypes.DAMAGE_CACTUS;
            }
            if (cqm8 == BlockPathTypes.DAMAGE_OTHER) {
                cqm6 = BlockPathTypes.DAMAGE_OTHER;
            }
        }
        if (cqm6 == BlockPathTypes.WALKABLE) {
            cqm6 = WalkNodeEvaluator.checkNeighbourBlocks(bjg, integer2, integer3, integer4, cqm6);
        }
        return cqm6;
    }
}
