package com.tiedup.remake.entities.ai.master;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityMaster;
import com.tiedup.remake.util.teleport.Position;
import com.tiedup.remake.util.teleport.TeleportHelper;
import java.util.EnumSet;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;

/**
 * AI Goal for EntityMaster to follow their pet player.
 *
 * Unlike normal follower mechanics, the Master follows the player.
 * Maintains a distance of 2-8 blocks from the player.
 */
public class MasterFollowPlayerGoal extends Goal {

    private final EntityMaster master;

    /** Minimum distance to maintain from pet */
    private static final double MIN_DISTANCE = 2.0;

    /** Ideal distance to maintain from pet (active following) */
    private static final double IDEAL_DISTANCE = 4.0;

    /** Maximum distance before starting to follow */
    private static final double MAX_DISTANCE = 8.0;

    /** Distance at which to teleport (if too far) */
    private static final double TELEPORT_DISTANCE = 32.0;

    /** Navigation speed */
    private static final double FOLLOW_SPEED = 1.0;

    /** Path recalculation cooldown (ticks) */
    private static final int PATH_RECALC_COOLDOWN = 10;

    private int pathRecalcCooldown = 0;
    private double targetX, targetY, targetZ;

    public MasterFollowPlayerGoal(EntityMaster master) {
        this.master = master;
        this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
    }

    @Override
    public boolean canUse() {
        // Must have a pet
        if (!master.hasPet()) {
            return false;
        }

        // Must be in a following-compatible state
        MasterState state = master.getStateManager().getCurrentState();
        if (
            state != MasterState.FOLLOWING &&
            state != MasterState.OBSERVING &&
            state != MasterState.DISTRACTED
        ) {
            return false;
        }

        // Pet must be online
        ServerPlayer pet = master.getPetPlayer();
        if (pet == null || !pet.isAlive()) {
            return false;
        }

        // Always active in FOLLOWING state — distance is enforced inside
        // tick() rather than by canUse, so the goal keeps running even
        // when the player is right next to the Master.
        return true;
    }

    @Override
    public boolean canContinueToUse() {
        if (!master.hasPet()) {
            return false;
        }

        ServerPlayer pet = master.getPetPlayer();
        if (pet == null || !pet.isAlive()) {
            return false;
        }

        // Only continue in following-compatible states
        MasterState state = master.getStateManager().getCurrentState();
        if (
            state != MasterState.FOLLOWING &&
            state != MasterState.OBSERVING &&
            state != MasterState.DISTRACTED
        ) {
            return false;
        }

        return true;
    }

    @Override
    public void start() {
        this.pathRecalcCooldown = 0;

        TiedUpMod.LOGGER.debug(
            "[MasterFollowPlayerGoal] {} started following pet",
            master.getNpcName()
        );
    }

    @Override
    public void stop() {
        master.getNavigation().stop();

        TiedUpMod.LOGGER.debug(
            "[MasterFollowPlayerGoal] {} stopped following pet",
            master.getNpcName()
        );
    }

    @Override
    public void tick() {
        ServerPlayer pet = master.getPetPlayer();
        if (pet == null) return;

        // Check for dimension change - teleport to pet's dimension if different
        if (!master.level().dimension().equals(pet.level().dimension())) {
            teleportToPetDimension(pet);
            return;
        }

        // Look at pet
        master.getLookControl().setLookAt(pet, 30.0F, 30.0F);

        double distSq = master.distanceToSqr(pet);

        // Teleport if too far (pet probably teleported within same dimension)
        if (distSq > TELEPORT_DISTANCE * TELEPORT_DISTANCE) {
            teleportNearPet(pet);
            return;
        }

        // Update path periodically
        this.pathRecalcCooldown--;
        if (this.pathRecalcCooldown <= 0) {
            this.pathRecalcCooldown = PATH_RECALC_COOLDOWN;

            // FIX: Active following behavior
            // Problem: If Master stops in "comfort zone" (2-8 blocks) and player
            // is on leash, nobody moves = deadlock.
            // Solution: Master actively follows, maintaining IDEAL_DISTANCE from pet.

            if (distSq < MIN_DISTANCE * MIN_DISTANCE) {
                // Too close - stop and let pet have some space
                master.getNavigation().stop();
            } else if (distSq > IDEAL_DISTANCE * IDEAL_DISTANCE) {
                // Beyond ideal distance - follow the pet
                master.getNavigation().moveTo(pet, FOLLOW_SPEED);
            } else if (!master.getNavigation().isInProgress()) {
                // At ideal distance and not moving - pick a random spot near pet
                // This creates natural wandering behavior around the pet
                wanderNearPet(pet);
            }
        }
    }

    /**
     * Wander to a random position near the pet.
     * Creates natural movement behavior instead of standing still.
     */
    private void wanderNearPet(ServerPlayer pet) {
        // Pick a random angle and position around the pet
        double angle = master.getRandom().nextDouble() * Math.PI * 2;
        double distance =
            IDEAL_DISTANCE + (master.getRandom().nextDouble() - 0.5) * 2;

        double x = pet.getX() + Math.cos(angle) * distance;
        double z = pet.getZ() + Math.sin(angle) * distance;

        // FIX: Use safe ground finder instead of heightmap (works indoors)
        int groundY = findSafeGroundY(
            pet.level(),
            (int) x,
            (int) z,
            (int) pet.getY() + 10
        );
        double y = groundY;

        // Move to the spot at slower speed (wandering, not chasing)
        master.getNavigation().moveTo(x, y, z, FOLLOW_SPEED * 0.6);
    }

    /**
     * Teleport master near pet when too far (same dimension).
     */
    private void teleportNearPet(ServerPlayer pet) {
        double angle = master.getRandom().nextDouble() * Math.PI * 2;
        double distance = MIN_DISTANCE + master.getRandom().nextDouble() * 2;

        double x = pet.getX() + Math.cos(angle) * distance;
        double z = pet.getZ() + Math.sin(angle) * distance;

        // FIX: Use safe ground finder instead of heightmap (works indoors)
        int groundY = findSafeGroundY(
            pet.level(),
            (int) x,
            (int) z,
            (int) pet.getY() + 10
        );
        double y = groundY;

        master.teleportTo(x, y, z);

        TiedUpMod.LOGGER.debug(
            "[MasterFollowPlayerGoal] {} teleported near pet {}",
            master.getNpcName(),
            pet.getName().getString()
        );
    }

    /**
     * Teleport master to pet's dimension.
     * Used when pet changes dimension (nether, end, etc.)
     */
    private void teleportToPetDimension(ServerPlayer pet) {
        // Calculate position near pet
        double angle = master.getRandom().nextDouble() * Math.PI * 2;
        double distance = MIN_DISTANCE + master.getRandom().nextDouble() * 2;

        double x = pet.getX() + Math.cos(angle) * distance;
        double z = pet.getZ() + Math.sin(angle) * distance;

        // FIX: Use safe ground finder instead of heightmap (works indoors)
        int groundY = findSafeGroundY(
            pet.level(),
            (int) x,
            (int) z,
            (int) pet.getY() + 10
        );
        double y = groundY;

        // Create position with dimension info
        Position targetPos = new Position(
            x,
            y,
            z,
            master.getYRot(),
            master.getXRot(),
            pet.level().dimension()
        );

        TiedUpMod.LOGGER.debug(
            "[MasterFollowPlayerGoal] {} teleporting to pet's dimension: {} -> {}",
            master.getNpcName(),
            master.level().dimension().location(),
            pet.level().dimension().location()
        );

        // Use TeleportHelper for cross-dimension teleportation
        TeleportHelper.teleportEntity(master, targetPos);

        TiedUpMod.LOGGER.debug(
            "[MasterFollowPlayerGoal] {} arrived in {} near pet {}",
            master.getNpcName(),
            pet.level().dimension().location(),
            pet.getName().getString()
        );
    }

    /**
     * Find a safe ground Y position by scanning downward.
     * Works correctly indoors (doesn't return roof height like heightmap).
     *
     * @param level The level
     * @param x Target X coordinate
     * @param z Target Z coordinate
     * @param startY Starting Y to scan from (usually entity Y + some offset)
     * @return A safe Y position with solid ground below and 2 air blocks above
     */
    private int findSafeGroundY(Level level, int x, int z, int startY) {
        BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(
            x,
            startY,
            z
        );

        // Scan downward to find a solid floor with 2 air blocks above
        for (int y = startY; y > level.getMinBuildHeight(); y--) {
            pos.setY(y);
            BlockState below = level.getBlockState(pos.below());
            BlockState at = level.getBlockState(pos);
            BlockState above = level.getBlockState(pos.above());

            // Solid floor + 2 blocks of clearance above
            if (below.isSolid() && !at.isSolid() && !above.isSolid()) {
                return y;
            }
        }
        return startY; // Fallback if nothing found
    }
}
