package com.tiedup.remake.compat.mca.ai.goals;

import java.util.EnumSet;
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;

/**
 * AI Goal: MCA villager follows the entity holding their leash.
 *
 * Similar to vanilla's FollowOwnerGoal but for leash holders.
 * Active when villager is leashed to a captor.
 */
public class MCAFollowCaptorGoal extends Goal {

    private final Mob mob;
    private final double speedModifier;
    private final float stopDistance;
    private final float startDistance;
    private LivingEntity captor;
    private int timeToRecalcPath;

    /** How often to recalculate path (in ticks) */
    private static final int PATH_RECALC_INTERVAL = 10;

    /**
     * Create follow captor goal.
     *
     * @param mob The MCA villager mob
     * @param speedModifier Speed multiplier when following
     * @param startDistance Distance at which to start following
     * @param stopDistance Distance at which to stop following
     */
    public MCAFollowCaptorGoal(
        Mob mob,
        double speedModifier,
        float startDistance,
        float stopDistance
    ) {
        this.mob = mob;
        this.speedModifier = speedModifier;
        this.startDistance = startDistance;
        this.stopDistance = stopDistance;
        this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
    }

    @Override
    public boolean canUse() {
        if (!mob.isLeashed()) return false;

        Entity holder = mob.getLeashHolder();
        if (!(holder instanceof LivingEntity living)) return false;

        // Don't follow if too close already
        double distance = mob.distanceToSqr(holder);
        if (distance < startDistance * startDistance) return false;

        this.captor = living;
        return true;
    }

    @Override
    public boolean canContinueToUse() {
        if (!mob.isLeashed()) return false;
        if (captor == null || !captor.isAlive()) return false;

        // Stop following if close enough
        double distance = mob.distanceToSqr(captor);
        return distance > stopDistance * stopDistance;
    }

    @Override
    public void start() {
        this.timeToRecalcPath = 0;
        mob.getNavigation().moveTo(captor, speedModifier);
    }

    @Override
    public void stop() {
        this.captor = null;
        mob.getNavigation().stop();
    }

    @Override
    public void tick() {
        // Look at captor
        mob
            .getLookControl()
            .setLookAt(captor, 10.0f, (float) mob.getMaxHeadXRot());

        // Recalculate path periodically
        if (--timeToRecalcPath <= 0) {
            timeToRecalcPath = PATH_RECALC_INTERVAL;

            // Navigate towards captor
            if (!mob.getNavigation().moveTo(captor, speedModifier)) {
                // If can't find path, try teleporting if very far
                double distance = mob.distanceToSqr(captor);
                if (distance > 256) {
                    // 16 blocks squared
                    // Teleport near captor
                    double x =
                        captor.getX() +
                        (mob.getRandom().nextDouble() - 0.5) * 2;
                    double y = captor.getY();
                    double z =
                        captor.getZ() +
                        (mob.getRandom().nextDouble() - 0.5) * 2;
                    mob.teleportTo(x, y, z);
                }
            }
        }
    }
}
