using System;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using ParadoxNotion.Serialization.FullSerializer;
using Sirenix.OdinInspector;
using UnityEngine;

namespace NodeCanvas.Tasks.Actions {

	[Category("Reset")]
	[Description("Update the agent's position and rotation (scale too, sure whynot) either instantly or over time.")]
	public class ChangeAgentTransform : ActionTask<CharacterController>{
		public enum TransformProperty{
			Position,
			Rotation,
			Scale
		}

		protected override string info {
			get{
				string basicText = string.Format($"Player {targetProperty.ToString()} to {(targetValue.isPresumedDynamic ? targetValue.name : targetValue.value)}");
				basicText += relativeToSelf.value ? ", relative to Self" : "";
				
				return basicText;
			}
		}

		public TransformProperty targetProperty;

		[ParadoxNotion.Design.ShowIf("targetProperty", 1), Space(5)]
		public BBParameter<bool> forcePositionChange;

		public BBParameter<Vector3> targetValue;
		
		public BBParameter<bool> relativeToSelf;
		
		[Tooltip("Set this to the current position if you're trying to rotate by 'this much'. Keep it zero for world space values.")]
		public BBParameter<Vector3> relativeValue;

		public BBParameter<bool> changeInstantly;
		public BBParameter<float> smoothing;

		private Vector3 currentVel;
		
		
		//Use for initialization. This is called only once in the lifetime of the task.
		//Return null if init was successfull. Return an error string otherwise
		protected override string OnInit() {
			return null;
		}

		//This is called once each time the task is enabled.
		//Call EndAction() to mark the action as finished, either in success or failure.
		//EndAction can be called from anywhere.
		protected override void OnExecute() {
			switch (targetProperty) {
				case TransformProperty.Position:
					Vector3 relativeUseValue = relativeValue.value;
					if (relativeToSelf.value) {
						relativeUseValue = agent.transform.position;
					}

					if (changeInstantly.value) {
						agent.Move(agent.transform.position.DirectionTo(relativeUseValue + targetValue.value));
					} 
					
					break;
				case TransformProperty.Rotation:
					agent.transform.rotation = Quaternion.LookRotation(relativeValue.value) * Quaternion.Euler(targetValue.value);
					break;
				case TransformProperty.Scale:
					break;
				default:
					throw new ArgumentOutOfRangeException();
			}

			if (changeInstantly.value) {
				EndAction(true);
			}
		}

		//Called once per frame while the action is active.
		protected override void OnUpdate() {
			switch (targetProperty) {
				case TransformProperty.Position:
					Vector3 relativeUseValue = relativeValue.value;
					if (relativeToSelf.value) {
						relativeUseValue = agent.transform.position;
					}

					if (!changeInstantly.value) {
						Vector3 targetPosition = relativeUseValue + targetValue.value;
						// agent.transform.position = Vector3.SmoothDamp(agent.transform.position, targetPosition,
						// 	ref currentVel, smoothing.value * Time.deltaTime);
						
						agent.Move((agent.transform.position.DirectionTo(targetPosition)).normalized * .5f * Mathf.Lerp(0, 1, Vector3.Distance(agent.transform.position, targetPosition)) * smoothing.value * Time.deltaTime);
						EndAction();
					} 
					
					break;
				case TransformProperty.Rotation:
					agent.transform.rotation = Quaternion.Euler(relativeValue.value) * Quaternion.Euler(targetValue.value);
					break;
				case TransformProperty.Scale:
					break;
				default:
					throw new ArgumentOutOfRangeException();
			}
		}

		//Called when the task is disabled.
		protected override void OnStop() {
			
		}

		//Called when the task is paused.
		protected override void OnPause() {
			
		}
	}
}