using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour
{
    private Rigidbody2D rb;

    public float maxRunSpeed;
    public float runAcceleration;
    public float snappiness = 1;
    public float jumpSpeed;
    [Range(0, 1)] public float airSpeedMultiplier;
    private bool onGround = false;
    private float forward = 1;

    float hangTimeThreshold = 0.1f;
    float hangTimeAccel = 0;
    float hangTimeSpeed = 0;

    private Vector2 movement = Vector2.zero;

    public LayerMask groundLayer;
    public Vector2 boxSize;
    public float maxDistanceFromGround;

    private bool trumpet = false;
    public bool in_range = false;
    public GameObject enemy;

    [Header("State Control:")]
    [SerializeField] private StateController stateController;

    PlayerBehavior playerBehavior;

    void OnValidate()
    {
        this.runAcceleration = Mathf.Clamp(runAcceleration, 0.1f, this.maxRunSpeed);
    }

    void Start()
    {
        playerBehavior = this.gameObject.GetComponent<PlayerBehavior>();
        this.rb = this.GetComponent<Rigidbody2D>();
        stateController = GameObject.Find("StateController").GetComponent<StateController>();
    }

    void OnMove(InputValue value)
    {
        this.movement = value.Get<Vector2>();
        //Debug.Log(this.movement);
    }

    void OnJump()
    {
        if (IsGrounded())
        {
            //need to add a condition so that trumpet is only true in certain scenes
            trumpet = true;
            rb.AddForce(Vector2.up * jumpSpeed, ForceMode2D.Impulse);
        }
        else if (!IsGrounded() && in_range && trumpet)
        {
            Destroy(enemy.gameObject);
            rb.AddForce(Vector2.up * jumpSpeed, ForceMode2D.Impulse);
            enemy = null;
            in_range = false;
        }
        else if (!IsGrounded() && trumpet && !in_range)
        {
            rb.AddForce(Vector2.up * jumpSpeed, ForceMode2D.Impulse);
            trumpet = false;
        }
    }

    void FixedUpdate()
    {
        Run(1);
    }

    float AccelerationRate()
    {
        return this.runAcceleration / this.maxRunSpeed;
    }

    private void Run(float lerpAmount)
    {
        float targetSpeed = this.movement.x * this.maxRunSpeed;

        float speedDiff = targetSpeed - this.rb.velocity.x;
        forward = Mathf.Sign(speedDiff);

        float accel = AccelerationRate() * snappiness;

        float accelRate = (Mathf.Abs(targetSpeed) > 0.1) ? accel : -accel;

        float velPower = 1.0f;

        float move = Mathf.Pow(Mathf.Abs(speedDiff) * accelRate, velPower) * forward;

        this.onGround = IsGrounded();

        float frictionAmount = 0.5f;

        // accelerate
        if (onGround && (Mathf.Abs(this.movement.x) > 0.1f))
        { // regular acceleration
            this.rb.AddForce(move * Vector2.right, ForceMode2D.Force);
        }
        else if (!onGround && (Mathf.Abs(this.movement.x) > 0.1f) && !playerBehavior.grapplingRope.isGrappling)
        { // while in air
            this.rb.AddForce(move * Vector2.right * airSpeedMultiplier, ForceMode2D.Force);
        }
        else if (!playerBehavior.grapplingRope.isGrappling)
        { // while grappling
            this.rb.AddForce(move * Vector2.right * airSpeedMultiplier * airSpeedMultiplier, ForceMode2D.Force);
        }

        // decelerate until stopped
        if (onGround && Mathf.Abs(this.movement.x) < 0.1f)
        {
            if (Mathf.Abs(rb.velocity.x) > 0.1f)
            {
                float amount = Mathf.Min(
                    Mathf.Abs(this.rb.velocity.x),
                    Mathf.Abs(frictionAmount)
                    );
                amount *= Mathf.Sign(this.rb.velocity.x);
                this.rb.AddForce(-amount * Vector2.right * snappiness, ForceMode2D.Impulse);
            }
            else
            {
                this.rb.velocity = new Vector2(0, rb.velocity.y);
            }
        }
    }

    bool IsGrounded()
    {
        if (Physics2D.BoxCast(transform.position, boxSize, 0, -transform.up, maxDistanceFromGround, groundLayer))
        {
            return true;
        }
        return false;
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawCube(transform.position - transform.up * maxDistanceFromGround, boxSize);
    }
}
