using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System;

public class Movement : MonoBehaviour
{
    [Header("Movement")]
    public float walkSpeed = 5f;
    private float height = 2f;
    public float inputSmoothTime = .025f;
    // private variables
    private float horizontalInput;
    private float verticalInput;
    private Vector3 playerInput;
    private Vector3 moveDirection;

    [Header("Jumping")]
    public float jumpHeight = 2f;
    public float gravityScale = 1.5f;
    // private variables
    private float yVelocity;

    [Header("Sprinting")]
    public float sprintSpeed = 9f;
    public bool isSprinting;

    [Header("Crouching")]
    public float crouchHeight = .75f;
    public float crouchSpeed = 2.5f;
    public bool isCrouching;

    [Header("Camera")]
    public Transform cam;
    public Camera playerCamera;
    public float sensitivity = 1f;
    // private variables
    private float mouseX;
    private float mouseY;
    public float normalFOV = 60f;
    public float sprintFOV = 80f;
    public float fovChangeSpeed = 5f;

    [Header("Labels")]
    public TextMeshProUGUI speedText;
    public TextMeshProUGUI heightText;
    public TextMeshProUGUI coordinatesText;

    private CharacterController characterController;

    private Vector3 r_playerInputSmoothed;
    private Vector3 smoothPlayerInput;

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        characterController.height = height;

        playerCamera = cam.GetComponent<Camera>();
        playerCamera.fieldOfView = normalFOV;

        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }

    void Update()
    {
        GetInput();
        ManipulateController();
        MouseLook();
        SimulatePhysics();
        UpdateText();
    }

    void GetInput()
    {
        horizontalInput = Input.GetAxisRaw("Horizontal");
        verticalInput = Input.GetAxisRaw("Vertical");

        playerInput = new Vector3(horizontalInput, 0, verticalInput).normalized;
        smoothPlayerInput = Vector3.SmoothDamp(smoothPlayerInput, playerInput, ref r_playerInputSmoothed, inputSmoothTime);

        isSprinting = Input.GetKey(KeyCode.LeftShift);
        isCrouching = Input.GetKey(KeyCode.C);

        mouseX = Input.GetAxisRaw("Mouse X") * sensitivity;
        mouseY -= Input.GetAxisRaw("Mouse Y") * sensitivity;

        mouseY = Mathf.Clamp(mouseY, -90f, 90f);
        playerCamera.fieldOfView = isSprinting && isCrouching == false ? Mathf.Lerp(playerCamera.fieldOfView, sprintFOV, Time.deltaTime * fovChangeSpeed) : Mathf.Lerp(playerCamera.fieldOfView, normalFOV, Time.deltaTime * fovChangeSpeed);

        if(Input.GetKeyDown(KeyCode.Space) && characterController.isGrounded)
        {
            yVelocity = Mathf.Sqrt(jumpHeight * -2f * Physics.gravity.y);
        }

        if(Input.GetKeyDown(KeyCode.C))
        {
            characterController.height = crouchHeight;
        }
        if(Input.GetKeyUp(KeyCode.C))
        {
            characterController.height = height;
        }

        if(Input.GetKeyDown(KeyCode.F))
        {
            // dash here
        }
    }

    void MouseLook()
    {
        cam.localRotation = Quaternion.Euler(mouseY, 0, 0);
        transform.Rotate(0, mouseX, 0);
    }

    void SimulatePhysics()
    {
        if (yVelocity <= 0 && characterController.isGrounded)
        {
            yVelocity = Physics.gravity.y * Time.deltaTime;
        }
        else
        {
            yVelocity += Physics.gravity.y * gravityScale * Time.deltaTime;
        }
    }

    void ManipulateController()
    {
        moveDirection = transform.rotation * smoothPlayerInput;

        float speed = isSprinting && isCrouching == false ? sprintSpeed : (isCrouching ? crouchSpeed : walkSpeed);

        moveDirection *= speed;
        moveDirection.y = yVelocity;
        moveDirection *= Time.deltaTime;

        characterController.Move(moveDirection);
    }

    void UpdateText()
    {
        if (speedText != null)
        {
            float playerSpeed = moveDirection.magnitude / Time.deltaTime;
            speedText.text = "Speed: " + playerSpeed.ToString("F2") + " units/s";
        }

        if (heightText != null)
        {
            float characterHeight = characterController.height;
            heightText.text = "Height: " + characterHeight.ToString("F2") + " m";
        }

        if (coordinatesText != null)
        {
            coordinatesText.text = "Coordinates: " + transform.position.ToString("F2");
        }
    }
}