using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(PlayerInput))]
public class PlayerMovement : MonoBehaviour {
	public PlayerData data;
	public MapData mapData;

	public bool tiledDirection = false;
	
	new Rigidbody rigidbody;
	Vector2 moveInput;
	Vector3 moveDirection;
	Transform camTransform;

	MapData.Direction lastDirection;

	void Awake() {
		rigidbody = GetComponent<Rigidbody>();

		var playerInput = GetComponent<PlayerInput>();

		playerInput.actions["Move"].started += OnMove;
		playerInput.actions["Move"].performed += OnMove;
		playerInput.actions["Move"].canceled += OnMove;

		if (Camera.main != null)
			camTransform = Camera.main.transform;
		else
			Debug.LogError("Couldn't find the main camera.");
	}

	void Update() {
		Vector3 camForward = camTransform.forward;
		camForward.y = 0;
		camForward.Normalize();
		
		Vector3 direction = camForward * moveInput.y + camTransform.right * moveInput.x;
		lastDirection = GetDirection(direction);

		if (tiledDirection) {
			Vector2 coords = mapData.WorldToAxial(transform.position);
			Vector2 neighborCoords = MapData.GetNeighbor(coords, lastDirection);
			Vector3 neighborWorld = mapData.AxialToWorld(neighborCoords) + Vector3.up * transform.position.y;
			moveDirection = (neighborWorld - transform.position).normalized * direction.magnitude;
		}else
			moveDirection = direction;
	}

	float GetAngle(Vector3 direction) {
		float angle = Vector3.SignedAngle(Vector3.forward, direction, Vector3.up);
		if (angle < 0)
			angle += 360f;
		
		return angle;
	}

	float GetRoundAngleOffset(Vector3 direction)
		=> 29 - (GetAngle(direction) + 29) % 60;

	Vector3 RoundedDirection(Vector3 direction)
		=> Quaternion.AngleAxis(GetRoundAngleOffset(direction), Vector3.up) * direction;

	MapData.Direction GetDirection(Vector3 direction) {
		float angle = GetAngle(direction);
		float deltaAngle = GetRoundAngleOffset(direction);
		
		int index = (Mathf.RoundToInt(angle + deltaAngle) / 60) % 6;
		return (MapData.Direction) index;
	}

	void FixedUpdate() {
		if (moveDirection != Vector3.zero) {
			rigidbody.MovePosition(rigidbody.position + moveDirection * data.speed * Time.fixedDeltaTime);

			AlignGroundedRotation();
		}
	}

	void AlignGroundedRotation() {
		Quaternion goalRot = Quaternion.LookRotation(moveDirection);
		Quaternion slerp = Quaternion.Slerp(transform.rotation, goalRot, data.turnSpeed * moveDirection.magnitude * Time.fixedDeltaTime);

		transform.rotation = slerp;
	}

	void OnMove(InputAction.CallbackContext ctx) {
		Vector2 input = ctx.ReadValue<Vector2>();
		if (input.sqrMagnitude > 1f)
			input.Normalize();

		moveInput = input;
	}

	/*void OnDrawGizmos() {
		Gizmos.color = Color.blue;
		var nearestAxial = mapData.WorldToAxial(new Vector2(transform.position.x, transform.position.z));
		Gizmos.DrawSphere(mapData.AxialToWorld(nearestAxial) + Vector3.up, 0.2f);
		
		Gizmos.color = Color.green;
		var coords = MapData.GetNeighbor(nearestAxial, lastDirection);
		Gizmos.DrawSphere(mapData.AxialToWorld(coords) + Vector3.up, 0.2f);
	}*/
}