/*
 *  Copyright 2025-2026 R3944Realms
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package top.r3944realms.eroticdungeongame.content.entity.npc.ai.navigation;

import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.pathfinder.*;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.eroticdungeongame.content.entity.npc.NPCServerPlayer;
import top.r3944realms.eroticdungeongame.content.entity.npc.ai.navigation.pathfinder.NPCPathFinder;
import top.r3944realms.eroticdungeongame.content.entity.npc.ai.navigation.pathfinder.NPCWalkNodeEvaluator;

@SuppressWarnings("deprecation")
public class NPCGroupGroundPathNavigation extends NPCPathNavigation {
    private boolean avoidSun;

    public NPCGroupGroundPathNavigation(NPCServerPlayer npc, Level level) {
        super(npc, level);
    }

    protected NPCPathFinder createPathFinder(int maxVisitedNodes) {
        this.nodeEvaluator = new NPCWalkNodeEvaluator();
        this.nodeEvaluator.setCanPassDoors(true);
        return new NPCPathFinder(this.nodeEvaluator, maxVisitedNodes);
    }

    protected boolean canUpdatePath() {
        return this.npc.onGround() || this.isInLiquid() || this.npc.isPassenger();
    }

    protected Vec3 getTempMobPos() {
        return new Vec3(this.npc.getX(), this.getSurfaceY(), this.npc.getZ());
    }

    /**
     * Returns path to given BlockPos
     */
    public Path createPath(BlockPos pos, int accuracy) {
        if (this.level.getBlockState(pos).isAir()) {
            BlockPos blockpos;
            for(blockpos = pos.below(); blockpos.getY() > this.level.getMinBuildHeight() && this.level.getBlockState(blockpos).isAir(); blockpos = blockpos.below()) {
            }

            if (blockpos.getY() > this.level.getMinBuildHeight()) {
                return super.createPath(blockpos.above(), accuracy);
            }

            while(blockpos.getY() < this.level.getMaxBuildHeight() && this.level.getBlockState(blockpos).isAir()) {
                blockpos = blockpos.above();
            }

            pos = blockpos;
        }

        if (!this.level.getBlockState(pos).isSolid()) {
            return super.createPath(pos, accuracy);
        } else {
            BlockPos blockpos1;
            for(blockpos1 = pos.above(); blockpos1.getY() < this.level.getMaxBuildHeight() && this.level.getBlockState(blockpos1).isSolid(); blockpos1 = blockpos1.above()) {
            }

            return super.createPath(blockpos1, accuracy);
        }
    }

    /**
     * Returns a path to the given entity or null
     */
    public Path createPath(@NotNull Entity entity, int accuracy) {
        return this.createPath(entity.blockPosition(), accuracy);
    }

    private int getSurfaceY() {
        if (this.npc.isInWater() && this.canFloat()) {
            int i = this.npc.getBlockY();
            BlockState blockstate = this.level.getBlockState(BlockPos.containing(this.npc.getX(), i, this.npc.getZ()));
            int j = 0;

            while(blockstate.is(Blocks.WATER)) {
                ++i;
                blockstate = this.level.getBlockState(BlockPos.containing(this.npc.getX(), i, this.npc.getZ()));
                ++j;
                if (j > 16) {
                    return this.npc.getBlockY();
                }
            }

            return i;
        } else {
            return Mth.floor(this.npc.getY() + 0.5D);
        }
    }

    protected void trimPath() {
        super.trimPath();
        if (this.avoidSun) {
            if (this.level.canSeeSky(BlockPos.containing(this.npc.getX(), this.npc.getY() + 0.5D, this.npc.getZ()))) {
                return;
            }

            if (this.path != null) {
                for(int i = 0; i < this.path.getNodeCount(); ++i) {
                    Node node = this.path.getNode(i);
                    if (this.level.canSeeSky(new BlockPos(node.x, node.y, node.z))) {
                        this.path.truncateNodes(i);
                        return;
                    }
                }
            }
        }

    }

    protected boolean hasValidPathType(BlockPathTypes pathType) {
        if (pathType == BlockPathTypes.WATER) {
            return false;
        } else if (pathType == BlockPathTypes.LAVA) {
            return false;
        } else {
            return pathType != BlockPathTypes.OPEN;
        }
    }

    public void setCanOpenDoors(boolean canOpenDoors) {
        this.nodeEvaluator.setCanOpenDoors(canOpenDoors);
    }

    public boolean canPassDoors() {
        return this.nodeEvaluator.canPassDoors();
    }

    public void setCanPassDoors(boolean canPassDoors) {
        this.nodeEvaluator.setCanPassDoors(canPassDoors);
    }

    public boolean canOpenDoors() {
        return this.nodeEvaluator.canPassDoors();
    }

    public void setAvoidSun(boolean avoidSun) {
        this.avoidSun = avoidSun;
    }

    public void setCanWalkOverFences(boolean canWalkOverFences) {
        this.nodeEvaluator.setCanWalkOverFences(canWalkOverFences);
    }
}
