using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.UI;

public class PlayerMovements : MonoBehaviour
{
    [Header ("Movements------------------------------------")]
    
    [SerializeField] private float speedForce = 10f;
    [SerializeField] private float jumpHeight = 0.8f;
    [SerializeField] private float gravityJump = 4.2f;
    [SerializeField] private float gravityDown = 4.2f;
    [SerializeField] private Transform cam;
    
    [Header("GroundCheck------------------------------------")]

    [SerializeField] private LayerMask groundLayer;
    [SerializeField] private float raycastCheckRadius;
    [SerializeField] private Transform groundCheck;

    [Header("CharacterAnimator------------------------------------")]

    [SerializeField] private Animator animator;

    //-----------------------------------------------------------------------------------------------------
   
    private CharacterController controller;
    private float turnSmoothTime = 0.1f;
    private float turnSmoothVelocity;
    private float downwardForce;
    private bool isGrounded;
    private Vector3 velocity;
    private float speedValue;
    

    private void Start()
    {
        controller = GetComponent<CharacterController>();
        Cursor.lockState = CursorLockMode.Locked;
        speedValue = speedForce;
    }
    //-----------------------------------------------------------------------------------------------------
    private void Update()
    {
       
        //these two variables contain the values of the Horizontal-Axis (W and S keys) and Vertical-Axis (A and D keys) 
        float horizontalInput = Input.GetAxisRaw("Horizontal");
        float verticalInput = Input.GetAxisRaw("Vertical");


        //this is to use its y-axis to make gravity and to know where the values of the two input axis
        velocity = new Vector3(horizontalInput, 0f, verticalInput).normalized;

        //this sum the absolue values of the two input axis to see if the player is moving
        float moveValue = Mathf.Abs(horizontalInput) + Mathf.Abs(verticalInput);
        //this assign to the "isGrounded" bool a raycast to see if the player is touching something that have the layer "ground" or not
        isGrounded = Physics.CheckSphere(groundCheck.position, raycastCheckRadius, groundLayer);

        //about the jumping 
        jumpMethod();

        //is used to tell the script of the movements animations the state of the bool "isGrounded"
        isGroundedActivation();


        //this check if the player is moving
        if (moveValue != 0f)
        {
            //this in general is to make the player smoothly change facing direction and to change the WASD directions according to the facing direction of the camera

            //this specifically use the player facing direction and make him move with the right angles for smoothly turns
            float targetAngle = Mathf.Atan2(velocity.x, velocity.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
            float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
            transform.rotation = Quaternion.Euler(0f, angle, 0f);
            Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;

            //this specifically is to say at the character controller component to use his "Move()" method
            controller.Move(moveDirection.normalized * speedValue * Time.deltaTime);
        }

        //this check if the player is falling, if yes then it activate the animation of the jump land
        
    }

    //-----------------------------------------------------------------------------------------------------

    //this method contain the things about the jump
    private void jumpMethod()
    {
        
        //this if/else check if the player is falling, if yes then it applies the gravity
        if (isGrounded && velocity.y <= 0f)
        {
            downwardForce = 0f;
        }
        else
        {
            downwardForce += Physics.gravity.y * gravityDown * Time.deltaTime;
        }

        //this check if the player press the jump button and if is on the ground, if yes then it make the player jump
        if (isGrounded && Input.GetButtonDown("Jump"))
        {
           
            downwardForce = Mathf.Sqrt(jumpHeight * -2f * Physics.gravity.y) * gravityJump;
            animator.SetTrigger("jump");
        }

        //this assign to the y-axis of the velocity the value of the variable "downwardForce" and then it call the Move() of the character controller
        velocity.y = downwardForce;
        controller.Move(velocity * Time.deltaTime);

        
    }

    //-----------------------------------------------------------------------------------------------------

    //this method is to tell to the script "movementsAnimations" the state of the bool "isGrounded"
    public void isGroundedActivation()
    {
        if (isGrounded)
        {
            FindObjectOfType<movementsAnimations>().isGroundedOn();
        }
        else if (!isGrounded)
        {
            FindObjectOfType<movementsAnimations>().isGroundedOff();
        }
    }
    
    //these two methods are used by the script "movementsAnimation" to tell this script what speedForce value he have to use
    public void speedForceOfRun()
    {
        speedValue = speedForce * 2;
    }
    public void speedForceOfWalk()
    {
        speedValue = speedForce;
    }

    //-----------------------------------------------------------------------------------------------------
    private void OnDrawGizmos()
    {
        //this draw the raycast of the bool "isGrounded"

        Vector3 startPosition = groundCheck.position;
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(startPosition, raycastCheckRadius);
    }
}