AI/ActionSystem/BehaviorTree/Nodes/FollowTargetNode.cs
namespace HC3;

/// <summary>
/// A node that makes an agent follow a target until it is close enough.
/// It supports repathing if the target moves significantly.
/// </summary>
public sealed class FollowTargetNode : Node
{
	private readonly Agent _agent;
	private readonly GameObject _target;
	private readonly float _requiredDistance;
	private readonly float _repathDistance;
	private readonly string _reason;
	private Vector3 _lastTargetPosition;

	public FollowTargetNode( Agent agent, GameObject target, float distance, float repath, string reason )
	{
		_agent = agent;
		_target = target;
		_requiredDistance = distance;
		_repathDistance = repath;
		_reason = reason;
	}

	protected override void OnStart()
	{
		_lastTargetPosition = _target.WorldPosition;
		_agent.Controller.Navigate( _lastTargetPosition );
	}

	public override Status Tick()
	{
		if ( !_target.IsValid() )
			return Status.Failure;

		// Check if target has moved significantly
		float distanceToTarget = _agent.WorldPosition.Distance( _target.WorldPosition );
		float targetMovement = _lastTargetPosition.Distance( _target.WorldPosition );

		// Repath if target has moved significantly
		if ( targetMovement > _repathDistance / 2 )
		{
			_lastTargetPosition = _target.WorldPosition;
			_agent.Controller.Navigate( _lastTargetPosition );
		}

		// Continue pursuing if we're too far
		if ( distanceToTarget > _requiredDistance )
		{
			// If we're not navigating for some reason, restart navigation
			if ( !_agent.Controller.IsNavigating )
			{
				_agent.Controller.Navigate( _target.WorldPosition );
			}
			return Status.Running;
		}

		// We're close enough to the target
		_agent.Controller.ClearNavigation();
		return Status.Success;
	}

	public override ActionDisplayInfo? GetDisplay()
	{
		return new ActionDisplayInfo(
			"pest_control",
			_reason,
			_agent.Controller.GetPathProgress()
		);
	}
}