using System;
using Godot;
using Playground.Common.CharacterMovement;

namespace KarrotStarterTemplate.Common.CharacterMovement;

[GlobalClass]
public partial class CharacterMovementController : Node
{
	[Export] public CharacterBody3D characterBody { get; set; }
	[Export] public CharacterMovementMode defaultMovementMode { get; set; }
	[Export] public AnimationMixer animationTree { get; set; }

	public CharacterMovementMode currentMovementMode { get; private set; }

	private Vector3 _temporaryMovementDirection = Vector3.Zero;
	public Vector2 blendspacePosition { get; private set; }


	public override void _Ready()
	{
		currentMovementMode = defaultMovementMode;
		
		characterBody ??= (CharacterBody3D)GetParent();
	}

	// Called every frame. 'delta' is the elapsed time since the previous frame.
	public override void _PhysicsProcess(double delta)
	{
		Vector3 velocity = characterBody.Velocity;

		CharacterMovementMode v = currentMovementMode;

		if (v.gravityScale != 0 && !characterBody.IsOnFloor())
		{
			velocity += characterBody.GetGravity() * (float)delta;
		}
		
		_temporaryMovementDirection = _temporaryMovementDirection.Normalized();

		if (!_temporaryMovementDirection.IsZeroApprox())
		{
			// velocity.X = _temporaryMovementDirection.X * v.speed;
			// velocity.Y += _temporaryMovementDirection.Y * v.speed;
			// velocity.Z = _temporaryMovementDirection.Z * v.speed;
			
			velocity = velocity.Lerp(_temporaryMovementDirection * v.speed, 3 * (float)delta);
			
			if (v.rotationRate > 0)
			{
				Vector3 c = characterBody.GlobalRotation;
				characterBody.GlobalRotation = new Vector3(0, Mathf.LerpAngle(c.Y, Mathf.Atan2(velocity.X, velocity.Z), Mathf.DegToRad(v.rotationRate) * (float)delta) , 0);
				// characterBody.LookAt(characterBody.GlobalPosition + velocity);
			}
		}
		else
		{
			if (velocity.Length() < .3)
			{
				velocity = velocity.MoveToward(new Vector3(0, velocity.Y, 0), 2 * (float)delta);
			}
			else
			{
				velocity = velocity.Lerp(new Vector3(0, velocity.Y, 0), 2 * (float)delta);

			}
		}

		_temporaryMovementDirection = Vector3.Zero;
		
		characterBody.Velocity = velocity;
		characterBody.MoveAndSlide();
	}

	public override void _Process(double delta)
	{
		float x = characterBody.GlobalTransform.Basis.X.Dot(characterBody.Velocity);
		float z = characterBody.GlobalTransform.Basis.Z.Dot(characterBody.Velocity);

		blendspacePosition = blendspacePosition.MoveToward(new Vector2(x, z) , 6 * (float)delta * 1f);
	}

	public void SetMovementMode(CharacterMovementMode movementMode)
	{
		currentMovementMode = movementMode ?? defaultMovementMode;
	}

	public void AddMovementInput(Vector2 direction, float value)
	{
		AddMovementInput(new Vector3(direction.X, 0f, direction.Y), value);
	}
	public void AddMovementInput(Vector3 direction, float value)
	{
		if (currentMovementMode.ignoreUpDirection)
		{
			direction = new Vector3(direction.X, 0f, direction.Z);
		}

		_temporaryMovementDirection += direction.Normalized() * value;
		GD.Print( _temporaryMovementDirection);
	}
}