using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class CharacterMovement : MonoBehaviour
{
    [SerializeField] private Rigidbody rb;

    [Header("Enable switches")]
    [SerializeField] private bool canWalk;
    [SerializeField] private bool canJump;
    
    [Header("Movement settings")]
    [SerializeField] private float movementSpeed;
    [SerializeField] private float maxMovementSpeed;
    [SerializeField] private float jumpPower;
    [SerializeField] private float afterJumpHorizontalSlowdownTime;

    [Header("Character properties")]
    [SerializeField] private float groundDrag;
    [SerializeField] private float airDrag;
    [SerializeField] private float playerHeight;
    [SerializeField] private float jumpAirSlowdown;
    [SerializeField] private GrappleHook grappleHook;
    public bool isGrounded;
    private bool isStunned = false;

    private Vector3 rawInputMovement;
    private float afterJumpHorizontalSlowdownTimeCounter;

    private bool stopWalk;
    private void Update()
    {
        if (isGrounded)
        {
            stopWalk = false;
            afterJumpHorizontalSlowdownTimeCounter = afterJumpHorizontalSlowdownTime;
        }
        else
        {
            afterJumpHorizontalSlowdownTimeCounter -= Time.deltaTime;
            stopWalk = true;

        }

        if (afterJumpHorizontalSlowdownTimeCounter <= 0f)
        {
            stopWalk = false;

        }
        SpeedControl();
    }

    private void FixedUpdate()
    {
        if(isStunned){
            return;
        }
        if (canWalk || canJump)
        {
            //The walk is actually handled here
            if (!stopWalk)
            {
                rb.AddForce(new Vector3(rawInputMovement.x * movementSpeed, rawInputMovement.y, rawInputMovement.z * movementSpeed), ForceMode.Impulse);
            }
            else
            {
                rb.AddForce(new Vector3(rawInputMovement.x * movementSpeed/ jumpAirSlowdown, rawInputMovement.y, rawInputMovement.z * movementSpeed/ jumpAirSlowdown), ForceMode.Impulse);
            }
        }
        
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.down) * playerHeight, Color.yellow);

        //Ground Check
        RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.down), out hit, playerHeight, LayerMask.GetMask("Floor")) ||
            Physics.Raycast(transform.position, transform.TransformDirection(Vector3.up), out hit, playerHeight, LayerMask.GetMask("Floor")) ||
            Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, playerHeight, LayerMask.GetMask("Floor")) ||
            Physics.Raycast(transform.position, transform.TransformDirection(Vector3.back), out hit, playerHeight, LayerMask.GetMask("Floor")) ||
            Physics.Raycast(transform.position, transform.TransformDirection(Vector3.left), out hit, playerHeight, LayerMask.GetMask("Floor")) ||
            Physics.Raycast(transform.position, transform.TransformDirection(Vector3.right), out hit, playerHeight, LayerMask.GetMask("Floor")))
        {
            isGrounded = true;
        }
        else
        {
            rawInputMovement = new Vector3(rawInputMovement.x, 0, rawInputMovement.z);
            isGrounded = false;
        }

        //Handle Grounded
        if (isGrounded)
            rb.drag = groundDrag;
        else
            rb.drag= airDrag;
    }

    public void Stun(float duration){
        isStunned = true;
        Invoke("Unstun" ,duration);
    }
    private void Unstun(){
        isStunned = false;
    }

    public void Walk(InputAction.CallbackContext value){

        if (canWalk)
        {
            Vector2 inputMovement = value.ReadValue<Vector2>();
            rawInputMovement = new Vector3(inputMovement.x, 0, inputMovement.y);
        }
    }

    public void Jump(InputAction.CallbackContext value)
    {
        if(canJump && isGrounded)
        {
            float inputMovement = value.ReadValue<float>();
            rb.velocity = new Vector3(rb.velocity.x, jumpPower * inputMovement, rb.velocity.z);
            //rawInputMovement = new Vector3(rawInputMovement.x, jumpPower, rawInputMovement.z);
        }
    }

    private void SpeedControl()
    {
        if (grappleHook.isGrappled())
        {
            Vector3 flatVel = rb.velocity;

            if (flatVel.magnitude > maxMovementSpeed)
            {
                Vector3 limitedVel = flatVel.normalized * maxMovementSpeed;
                rb.velocity = limitedVel;
            }
        }
        else
        {
            Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);

            if (flatVel.magnitude > maxMovementSpeed)
            {
                Vector3 limitedVel = flatVel.normalized * maxMovementSpeed;
                rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z);
            }
        }
    }
}
