using System;
using System.Collections.Generic;
using UnityEngine;
using RAIN.Action;
using RAIN.Path;
using RAIN.Core;
using RAIN.Animation;
namespace RAIN.Primitives
{
    /// 
    /// MoveAction is a primitive used to specify a target location to move to, speed at which to move, and optionally an animation to play while moving.
    /// 
    public class MoveAction : Action.Action
    {
        /// 
        /// If the movement target is a GameObject (Transform) then moveContextVariableName contains the name of the variable holding the game object.
        /// This may have been assigned by a DetectAction primitive.
        /// 
        public string moveContextVariableName = null;
        /// 
        /// If the look target is a GameObject (Transform) then moveContextVariableName contains the name of the variable holding the game object.
        /// This may have been assigned by a DetectAction primitive.
        /// 
        public string lookContextVariableName = null;
        /// 
        /// moveTarget is the MoveLookTarget (Vector or Transform) that is moved to
        /// 
        public MoveLookTarget moveTarget = new MoveLookTarget();
        /// 
        /// lookTarget is the MoveLookTarget (Vector or Transform) that is face during movement
        /// 
        public MoveLookTarget lookTarget = new MoveLookTarget();
        /// 
        /// moveSpeed is the target speed for movement.  This is limited by the Agent's overall MaxSpeed
        /// 
        public float moveSpeed = -1.0f;
        /// 
        /// lookSpeed is the target rotation speed for movement.  This is limited by the Agent's overall MaxRotationRate
        /// 
        public float lookSpeed = -1.0f;
        /// 
        /// animationOverride is the animation state name of an animation that should be played during movement.  If animation is driven by an AIAnimationController, this value will override
        /// the controller's normal animation.  Leave null or blank if no custom animation is desired
        /// 
        public string animationOverride = null;
        /// 
        /// animationOverrideBaseSpeed is the baseline speed of the animation state specified in animationOverride.  The animation playback speed will be adjusted based on the difference
        /// between actual movement speed and this base speed
        /// 
        public float animationOverrideBaseSpeed = 1.0f;
        private bool _animationStarted = false;
        public MoveAction() { }
        /// 
        /// ActionResult.Start
        /// Sets up move and look targets from variables if necessary
        /// 
        /// 
        /// 
        /// SUCCESS
        public override ActionResult Start(Agent agent, float deltaTime)
        {
            if (moveContextVariableName != null) moveTarget = GetTargetFromVariable(moveContextVariableName);
            if (lookContextVariableName != null) lookTarget = GetTargetFromVariable(lookContextVariableName);
            _animationStarted = false;
            return ActionResult.SUCCESS;
        }
        /// 
        /// ActionResult.Execute
        /// Move toward the move target, look at the look target.
        /// 
        /// 
        /// 
        /// SUCCESS if the Agent has reached the target, RUNNING otherwise
        public override ActionResult Execute(Agent agent, float deltaTime)
        {
            bool closeEnough = true;
            float maxSpeed = agent.Kinematic.MaxSpeed;
            float maxRotation = agent.Kinematic.MaxRotationRate;
            if (moveSpeed >= 0) agent.Kinematic.MaxSpeed = Mathf.Min(moveSpeed, maxSpeed);
            if (lookSpeed >= 0) agent.Kinematic.MaxRotationRate = Mathf.Min(lookSpeed, maxRotation);
            if ((moveTarget != null) && (moveTarget.TargetType != MoveLookTarget.MoveLookTargetType.NONE))
            {
                agent.MoveTarget = moveTarget;
                closeEnough = agent.Move(deltaTime);
            }
            if ((lookTarget != null) && (lookTarget.TargetType != MoveLookTarget.MoveLookTargetType.NONE))
            {
                agent.LookTarget = lookTarget;
                closeEnough &= agent.Look(deltaTime);
            }
            if (!closeEnough && !_animationStarted)
            {
                if ((animationOverride != null) && (animationOverride.Trim().Length > 0))
                {
                    agent.Avatar.BroadcastMessage("HandleAIAnimationStateMovementOverride", new AnimationParams(animationOverride, animationOverrideBaseSpeed), SendMessageOptions.DontRequireReceiver);
                    _animationStarted = true;
                }
            }
            agent.Kinematic.MaxSpeed = maxSpeed;
            agent.Kinematic.MaxRotationRate = maxRotation;
            if (closeEnough) return ActionResult.SUCCESS;
            return ActionResult.RUNNING;
        }
        /// 
        /// ActionResult.Stop
        /// Stops custom animation override if enabled
        /// 
        /// 
        /// 
        /// SUCCESS
        public override ActionResult Stop(Agent agent, float deltaTime)
        {
            if (_animationStarted && (animationOverride != null) && (animationOverride.Trim().Length > 0))
            {
                agent.Avatar.BroadcastMessage("HandleAIAnimationStateMovementOverride", new AnimationParams(null, 0), SendMessageOptions.DontRequireReceiver);
            }
            _animationStarted = false;
            return ActionResult.SUCCESS;
        }
        private MoveLookTarget GetTargetFromVariable(string variable)
        {
            if (!actionContext.ContextItemExists(variable)) return null;
            MoveLookTarget target = null;
            target = actionContext.GetContextItem(variable);
            if (target != null) return target;
            target = new MoveLookTarget();
            Kinematic k = actionContext.GetContextItem(variable);
            if (k != null)
            {
                target.KinematicTarget = k;
                return target;
            }
            GameObject gobj = actionContext.GetContextItem(variable);
            if (gobj != null)
            {
                target.TransformTarget = gobj.transform;
                return target;
            }
            Vector3 v = actionContext.GetContextItem(variable);
            target.VectorTarget = v;
            return target;
        }
    }
}