using Drawing;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using ParadoxNotion.Services;
using UnityEngine;


namespace NodeCanvas.Tasks.Actions {

	[Category("Reset/Movement")]
	[Description("Pulls the agent towards a position with a spring-like effect")]
	public class DoGrapplePull : ActionTask<CharacterController>{
		public BBParameter<Vector3> grapplePoint;
		public BBParameter<Vector3> offset;

		public BBParameter<float> pullAccelerationSpeed;
		public BBParameter<float> pullDeaccelerationSpeed;
		
		[Tooltip("X is minimum speed, Y is maximum speed")]
		public BBParameter<Vector2> pullTimeRange;
		[Tooltip("X is the distance where the curve will first be evaluated, Y is the distance where the curve will last be evaluated")]
		public BBParameter<Vector2> pullSpeedRange;

		public BBParameter<float> slowdownDistance;

		public BBParameter<AnimationCurve> pullSpeedCurve;
		public BBParameter<AnimationCurve> endDeaccelerationCurve;
		

		private float startTime;
			
		private float currentSpeed;
		private Vector3 smoothedInput;
		private Vector3 smoothedInputRefVelocity;
		
	//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(){
			MonoManager.current.onLateUpdate += DrawGrappleGizmo;
			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(){
			startTime = Time.time;
			currentSpeed = pullSpeedCurve.value[0].value * pullSpeedRange.value.y;
		}

		//Called once per frame while the action is active.
		protected override void OnUpdate(){
			// Create the distance variables
			Vector3 dirToPoint = agent.transform.position.DirectionTo(grapplePoint.value);
				
			float evaluatedSpeed = pullSpeedCurve.value.Evaluate(Mathf.Clamp((Time.time - startTime) / 6f, 0f, Mathf.Infinity));

			float speedAgainstCurve = Mathf.Lerp(pullSpeedRange.value.x, pullSpeedRange.value.y, evaluatedSpeed);
			
			// Find how far from 0-1 the player is from the max and minimum distance
			// Get the base distance then account for the minimum distance to the point so that being the minimum away will Lerp to 1
			float currentDist = Vector3.Distance(agent.transform.position, grapplePoint.value); 
			// float currentDistMinimumAccounted = (currentDist - pullSpeedDistances.value.x); 

			if (currentDist < slowdownDistance.value) {
				float change = endDeaccelerationCurve.value.Evaluate((slowdownDistance.value - currentDist) / slowdownDistance.value);
				speedAgainstCurve = speedAgainstCurve * change;
				
				// Debug.Log($"prev: {speedAgainstCurve}, norm: {(slowdownDistance.value - currentDist) / slowdownDistance.value}, change: {change}, output: {speedAgainstCurve * change} ");
			}

			// Evaluate the normalized value
			// float normaled = Mathf.Lerp(0, 1f, 1f - elapsedTime / (pullSpeedDistances.value.y - pullSpeedDistances.value.x)); 
			
			// Use the curve evaluation to set the speed
			// float outputSpeed = Mathf.Lerp(pullTimeRange.value.x, pullTimeRange.value.y, evaluatedSpeed);

			// Soften the speed changes
			currentSpeed = Mathf.Lerp(currentSpeed, speedAgainstCurve, 10f * Time.deltaTime);
			
			// Add input changes
			Vector2 rawInput = agent.GetComponent<PlayerControls>().rawMoveInput;
			Vector3 input = Quaternion.LookRotation(dirToPoint) * new Vector3(rawInput.x, rawInput.y, 0f);

			smoothedInput = Vector3.SmoothDamp(smoothedInput, input, ref smoothedInputRefVelocity, 30f * Time.deltaTime); 
			
			Debug.Log(input);

			dirToPoint.y *= 2.5f;

			agent.Move((dirToPoint.normalized + smoothedInput) * currentSpeed * Time.deltaTime);
			// Debug.Log( $"{ endDeaccelerationCurve.value.Evaluate(((slowdownDistance.value - currentDist)) )}");

			// EndAction(true);
		}

		public void DrawGrappleGizmo(){
			// Vector3 dirToPoint = agent.transform.position.DirectionTo(grapplePoint.value);
			//
			// using (Draw.WithColor(Color.yellow)){
			// 	Draw.Line(agent.transform.position + Vector3.up, grapplePoint.value);
			//
			// 	// Draw Gizmo for minimum distance
			// 	Vector3 minLocation = agent.transform.position + (Vector3.up * 1) + (dirToPoint * pullSpeedDistances.value.x);
			// 	Vector3 minToScreen = minLocation.DirectionTo(Camera.main.transform.position);
			//
			// 	Draw.SolidCircle(minLocation,minToScreen , .2f);
			// 	
			// 	// Draw Gizmo for minimum distance
			// 	Vector3 maxLocation = agent.transform.position + (Vector3.up * .8f) + (dirToPoint * pullSpeedDistances.value.y);
			// 	Vector3 maxToScreen = maxLocation.DirectionTo(Camera.main.transform.position);
			//
			// 	Draw.SolidCircle(maxLocation,maxToScreen , .2f);
			// }
		}
		
		//Called when the task is disabled.
		protected override void OnStop() {
			
		}

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