using System;
using Unity.Behavior;
using UnityEngine;
using Action = Unity.Behavior.Action;
using Unity.Properties;
using UnityEngine.AI;

[Serializable, GeneratePropertyBag]
[NodeDescription(
    name: "Warp",
    description: "Warp a GameObject towards another GameObject using NavMeshAgent." +
        "\nIf NavMeshAgent is not available on the [Agent] or its children, moves the Agent using its transform.",
    story: "[Agent] warp to [Target]",
    category: "Action/Navigation",
    id: "3bda4aa1c06c62c4f9f8f7813fcd4293")]
public partial class WarpAction : Action
{
    [SerializeReference] public BlackboardVariable<GameObject> Agent;
    [SerializeReference] public BlackboardVariable<GameObject> Target;
    [SerializeReference] public BlackboardVariable<float> DistanceThreshold = new BlackboardVariable<float>(0.2f);

    private NavMeshAgent m_NavMeshAgent;

    protected override Status OnStart()
    {
        if (Agent.Value == null || Target.Value == null)
        {
            return Status.Failure;
        }
        return Status.Running;
    }

    protected override Status OnUpdate()
    {
        // Add the extents of the colliders to the stopping distance.
        Vector3 agentPosition = Agent.Value.transform.position;
        Vector3 targetPosition = Target.Value.transform.position;
        float distanceRemain = Vector3.Distance(agentPosition, targetPosition);
        if (distanceRemain <= (DistanceThreshold))
        {
            return Status.Success;
        }

        // If using a navigation mesh, set target position for navigation mesh agent.
        m_NavMeshAgent = Agent.Value.GetComponentInChildren<NavMeshAgent>();
        if (m_NavMeshAgent != null)
        {
            if (!m_NavMeshAgent.isOnNavMesh)
            {
                Debug.LogError($"{m_NavMeshAgent} not on NavMesh");
                return Status.Failure;
            }

            try
            {
                if (m_NavMeshAgent.Warp(targetPosition))
                {
                    m_NavMeshAgent.transform.position = targetPosition;
                    return Status.Success;
                }
                else
                {
                    return Status.Failure;
                }
            }
            catch (Exception ex)
            {
                return Status.Failure;
            }
        }
        else // transform-based movement
        {
            Agent.Value.transform.position = targetPosition;
            return Status.Success;
        }
    }

    protected override void OnEnd()
    {
    }
}

