using UnityEngine;


namespace Resources.Project.Game.Player

{

    public class PlayerMovement : MonoBehaviour

    {

        [Header("Move")]

        [SerializeField] private float sprintSpeed;

        [SerializeField] private float crouchSpeed;

        [SerializeField] private float moveSpeedOnGround;

        [SerializeField] private float moveSpeedInAir;


        [Header("Jump")]

        [SerializeField] private float jumpPower;


        [Header("Physic")]

        [SerializeField] private float gravityScale;

        [SerializeField] private float accelerationOnGround;

        [SerializeField] private float accelerationInAir;

        [SerializeField] private float sprintAcceleration;

        [SerializeField] private float slideOnGround;

        [SerializeField] private float slideInAir;


        [Header("GroundCheck")]

        [SerializeField] private Transform groundCheckPosition;

        [SerializeField] private LayerMask groundLayerMask;

        [SerializeField] private float groundCheckSphereRadius;


        [Header("Rotate Target")]

        [SerializeField] private Transform rotationTarget;


        private CharacterController characterController;

        private PlayerInputHandler playerInputHandler;

        private PlayerAnimation playerAnimation;

        

        private Vector3 velocity;

        private Vector3 moveVelocity;

        private Vector3 smoothVelocity;


        public float Speed;


        public bool IsMoving { get; private set; }

        public bool IsSprinting { get; private set; }

        public bool IsJumped { get; private set; }

        public bool IsCrouching { get; private set; }


        public bool IsGrounded { get; private set; }


        public bool IsAbleToMove { get; private set; } = true;

        public bool IsAbleToSprint { get; private set; } = true;

        public bool IsAbleToJump { get; private set; } = true;

        public bool IsAbleToCrouching { get; private set; } = true;


        public void Awake()

        {

            characterController = GetComponent<CharacterController>();;


            playerInputHandler = GetComponentInParent<PlayerInputHandler>();

            playerAnimation = GetComponent<PlayerAnimation>();


            playerAnimation.PlayIdleAnimation();

            Speed = moveSpeedOnGround;

        }


        private void Update()

        {

            IsGrounded = Physics.CheckSphere(groundCheckPosition.position, groundCheckSphereRadius, groundLayerMask);


            Move();

            Sprint();

            Jump();


            if(IsGrounded && velocity.y < -2F)

                velocity.y = -2f;


            if(!IsGrounded)

                velocity.y += gravityScale * Time.deltaTime;


            transform.rotation = Quaternion.Euler(0F, rotationTarget.eulerAngles.y, 0F);

            characterController.Move((moveVelocity + velocity) * Time.deltaTime);

        }


        private void Move()

        {

            if(!IsAbleToMove || IsCrouching)

                return;


            Vector3 flatVelocity = new Vector3(characterController.velocity.x, 0f, characterController.velocity.z);


            IsMoving = flatVelocity.normalized.magnitude > 0.3F;


            Vector3 moveDirection = playerInputHandler.MoveDirection.normalized;


            float deltaSpeed = IsGrounded ? Speed : moveSpeedInAir;


            float acceleration = IsGrounded ? accelerationOnGround : accelerationInAir;

            float slide = IsGrounded ? slideOnGround : slideInAir;


            float deltaAcceleration = moveDirection.magnitude == 0 ? slide : acceleration;


            smoothVelocity = Vector3.MoveTowards(smoothVelocity, moveDirection * deltaSpeed, deltaAcceleration * deltaSpeed * Time.deltaTime);

            moveVelocity = transform.TransformDirection(smoothVelocity);


            if(IsGrounded)

            {

                if(IsMoving)

                    playerAnimation.PlayMoveAnimation(moveDirection.normalized);


                else

                    playerAnimation.PlayIdleAnimation();

            }

                

        }


        private void Jump()

        {

            IsJumped = false;


            if(!IsAbleToJump)

                return;


            if(IsGrounded && playerInputHandler.JumpKey.IsDown)

            {

                velocity.y = jumpPower;


                playerAnimation.PlayJumpAnimation();


                IsJumped = true;

            }

        }


        private void Sprint()

        {

            if(!IsAbleToSprint || IsCrouching)

                return;


            if(IsGrounded)

            {

                IsSprinting = playerInputHandler.SprintKey.IsKeep && moveVelocity.magnitude > 0.01f;


                float targetSpeed = IsSprinting ? sprintSpeed : moveSpeedOnGround;


                Speed = Mathf.MoveTowards(Speed, targetSpeed, sprintAcceleration * Time.deltaTime);


                playerAnimation.PlaySprintAnimation(IsSprinting);

            }

        }


        public void AddForce(Vector3 force) => characterController.Move(transform.TransformDirection(force));

    }

} 평가좀