using UnityEngine;
using UnityEngine.InputSystem;




public enum MoveState
{
    Idle,
    Run,
    Jump,
    Fall,
    WallSlide,
}

public class PlayerMovement : MonoBehaviour
{
    public MoveState state;
    Vector2 input;
    Rigidbody2D rb;
    public float speed;


    public float fallMulti;
    public float jumpPower;

    public CollisionChecker groundChecker;
    public CollisionChecker rightWall;
    public CollisionChecker leftWall;


    public float coyoteTime = 0.1f;
    float coyoteNowTime = 0f;

    public float jumpBufferTime = 0.1f;
    float jumpBufferNow = 0f;

    public float wallSlideSpeed;

    public float minJumpTime = 0.05f;
    public float maxJumpTime = 0.15f;
    bool jumpPressed = false;
    public float jumpCutMultiplier = 0.33f; // ������ ���� �� �ӵ� ���� ����

    float jumpTimer = 0f;

    private void Start()
    {
        ChangeState(MoveState.Idle);
        InputManager.moveEvent += OnMove;
        InputManager.jumpEvent += OnJump;
        rb= GetComponent<Rigidbody2D>();
    }


    private void Update()
    {
        if (!groundChecker.isTouched)
        {
            coyoteNowTime -= Time.deltaTime;
        }
        else
        {
            coyoteNowTime = coyoteTime;
        }

        if (jumpBufferNow > 0f)
        {
            jumpBufferNow -= Time.deltaTime;
        }

        if (state == MoveState.Jump)
        {
            jumpTimer += Time.deltaTime;
        }
        else
        {
            jumpTimer = 0;
        }
    }

    public void ChangeState(MoveState newState)
    {



        switch (state) // EXIT
        {
            case MoveState.Jump:
                StopJump();
                break;
        }

        state = newState;

        switch (newState) // ENTER
        {
            case MoveState.Jump:
                StartJump();
                break;
        }
    }


    public void HoldState()
    {
        switch (state)
        {
            case MoveState.Jump:
                HoldState_Jump();
                break;
            case MoveState.Idle:
                HoldState_Idle();
                break;
            case MoveState.Fall:
                HoldState_Fall();
                break;
            case MoveState.Run:
                HoldState_Run();
                break;
        }
    }


    private void FixedUpdate()
    {
        rb.linearVelocity = new Vector2(input.x * speed, rb.linearVelocityY);
        HoldState();
        setGravity();
    }


    public void HandleJump()
    {
        if (jumpBufferNow > 0f && (groundChecker.isTouched || coyoteNowTime > 0))
        {
            ChangeState(MoveState.Jump);
            jumpBufferNow = 0f;
            coyoteNowTime = 0;
        }
    }
    void HoldState_Run()
    {

        HandleJump();
        if (!groundChecker.isTouched && rb.linearVelocity.y < 0)
        {
            ChangeState(MoveState.Fall);
        }
        else if (input.x == 0)
        {
            ChangeState(MoveState.Idle);
        }
    }
    void HoldState_Jump()
    {
        HandleJump();

        if (jumpPressed && jumpTimer < maxJumpTime)
        {
            // ����, AND �����ð� < �������ð�
        }
        else if (jumpTimer < minJumpTime)
        {
            // !����, �����ð� < �������ð� �� ��
        }
        else
        {
            ChangeState(MoveState.Fall);
        }
    }
    void HoldState_Fall()
    {
        if (groundChecker.isTouched)
        {
            ChangeState(MoveState.Idle);
        }
    }
    void HoldState_Idle()
    {
        HandleJump();

        if (groundChecker.isTouched)
        {
            if (input.x != 0 && state != MoveState.Run)
            {
                ChangeState(MoveState.Run);
            }
        }
        else if (!groundChecker.isTouched)
        {
            if (rb.linearVelocityY < 0f)
            {
                ChangeState(MoveState.Fall);
            }
        }

    }

    public void setGravity()
    {
        if (state == MoveState.Fall)
        {
            rb.linearVelocityY += Physics2D.gravity.y * fallMulti * Time.fixedDeltaTime;
            return;
        }
    }



    public void OnJump(InputAction.CallbackContext context)
    {
        if (context.started)
        {
            jumpPressed = true;
            jumpBufferNow = jumpBufferTime;
        }
        if (context.canceled)
        {
            jumpPressed = false;
        }
    }


    public void StartJump()
    {
        if (groundChecker.isTouched || coyoteNowTime > 0)
        {
            rb.linearVelocity = new Vector2(rb.linearVelocityX, jumpPower);
        }
    }

    public void HoldJump()
    {
       // rb.linearVelocity = new Vector2(rb.linearVelocityX, jumpPower);
    }

    public void StopJump()
    {
        rb.linearVelocity = new Vector2(rb.linearVelocity.x, rb.linearVelocity.y * jumpCutMultiplier);

    }

    public void WallSlide()
    {
        rb.linearVelocityY = Mathf.Max(rb.linearVelocityY, -wallSlideSpeed);
    }

    public void OnMove(Vector2 vec)
    {
        input = vec;
    }
}