using System;
using UnityEngine;

namespace Animators.Leonid_Animator.Player
{
    [RequireComponent(
         typeof(Rigidbody),
        typeof(InputHandler),
        typeof(AnimatorHandler))]
    public class CharacterLocomotion : MonoBehaviour
    {
        private Transform _cameraObject;
        private InputHandler _inputHandler;
        private Vector3 _moveDirection;

        [HideInInspector] public Transform myTransform;
        [HideInInspector] public AnimatorHandler myAnimatorHandler;

        public Rigidbody myRigidbody;
        [SerializeField] public float jumpForce;

        [Header("Stats")] 
        [SerializeField] private float movementSpeed = 25;
        [SerializeField] private float rotationSpeed = 10;


        private void Awake()
        {
            myRigidbody = GetComponent<Rigidbody>();
            _inputHandler = GetComponent<InputHandler>();
            myAnimatorHandler = GetComponent<AnimatorHandler>();
        }

        private void Start()
        {
            _cameraObject = Camera.main.transform;
            myTransform = transform;
            myAnimatorHandler.Initialize();
        }

        private void Update()
        {
            var deltaTime = Time.deltaTime;
            _inputHandler.TickInput(deltaTime);
            _moveDirection = _cameraObject.forward * _inputHandler.vertical
                             + _cameraObject.right * _inputHandler.horizontal;
            _moveDirection.Normalize();
            _moveDirection *= movementSpeed;
            _moveDirection.y = 0;

            var projectedVelocity = Vector3.ProjectOnPlane(_moveDirection, _normalVector);
            myRigidbody.velocity = projectedVelocity;

            if (myAnimatorHandler.canRotate)
            {
                HandleRotation(deltaTime);
            }
            
            myAnimatorHandler.UpdateAnimatorValues(
                _inputHandler.moveAmount,
                0,
                _inputHandler.jumpPressed, 
                _inputHandler.crouchPressed,
                            _inputHandler.firePressed);
            
            var velocity = myRigidbody.velocity;
            myRigidbody.AddForce(_inputHandler.jumpPressed ? 
                new Vector3(0, jumpForce, 0) 
                : new Vector3(velocity.x*100, -50, velocity.z * 100));
        }

        private void LateUpdate()
        {
            _inputHandler.jumpPressed = false;
            _inputHandler.crouchPressed = false;
        }

        public Vector3 GetMeshCenter()
        {
            if (myAnimatorHandler.isCrouching)
                return transform.position + 1f * Vector3.up;
            else
            {
                return transform.position + 2f * Vector3.up;
            }
        }

        #region Movement

        private Vector3 _normalVector;
        private Vector3 _targetPosition;

        private void HandleRotation(float delta)
        {
            if (Mathf.Abs(_inputHandler.horizontal) + Mathf.Abs(_inputHandler.vertical) < 0.1)
                return;
            
            var moveAmount = _inputHandler.moveAmount;
            var targetDir = _cameraObject.forward * _inputHandler.vertical
                            + _cameraObject.right * _inputHandler.horizontal;
            targetDir.Normalize();
            targetDir.y = 0;
            if (targetDir == Vector3.zero)
                targetDir = myTransform.forward;

            var rotSpeed = rotationSpeed;

            var rotation = Quaternion.LookRotation(targetDir);
            var targetRotation = Quaternion.Slerp(myTransform.rotation, rotation, rotationSpeed * delta);
            myTransform.rotation = targetRotation;
        }

        #endregion
    }
}