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

public class PlayerMovement : MonoBehaviour
{
    private InputControls inputControls;
    private Rigidbody2D _rigidbody2D;
    private InputActionMap currentActionMap;
    private Collider2D groundCollider;

    //movement
    private Vector3 _velocity = Vector3.zero;
    private float horizontalMove = 0f;
    [Range(0, .3f)] public float _movementSmoothing = .05f;
    public float speed;
    public Animator animator;

    //jumping
    public float jumpSpeed;
    public LayerMask ground;
    public float hangTime = .1f;
    private float hangCounter;
    public float jumpBufferTime = .1f;
    private float jumpBufferCounter;

    private bool goingRight = true;

    public UnityEvent OnLandEvent;
    private void Awake()
    {
        inputControls = new InputControls();
        _rigidbody2D = GetComponent<Rigidbody2D>();
        PlayerInput playerInput = GetComponent<PlayerInput>();
        currentActionMap = playerInput.currentActionMap;
        groundCollider = GetComponent<BoxCollider2D>();
        if (OnLandEvent == null)
            OnLandEvent = new UnityEvent();
    }


    // Start is called before the first frame update
    void Start()
    {
        currentActionMap.FindAction("Jump").started += _ => JumpReady();
        currentActionMap.FindAction("Jump").canceled += _ => JumpCanceled();
    }

    private void OnEnable()
    {
        inputControls.Enable();
    }

    private void OnDisable()
    {
        inputControls.Disable();
    }

    // Update is called once per frame
    void Update()
    {
        horizontalMove = currentActionMap.FindAction("Move").ReadValue<float>();
        animator.SetFloat("speed", Mathf.Abs(horizontalMove));
        AjustPlayerDiretion(horizontalMove);

        if (isGrounded())
        {
            OnLandEvent.Invoke();
            hangCounter = hangTime;
        }
        else
        {
            hangCounter -= Time.deltaTime;
        }

        jumpBufferCounter -= Time.deltaTime;
    }

    private void FixedUpdate()
    {
        Move();
        Jump();
    }

    private void JumpReady() 
    {
        jumpBufferCounter = jumpBufferTime;
    }

    private void JumpCanceled()
    {
        if (_rigidbody2D.velocity.y > 0)
        {
            _rigidbody2D.velocity = new Vector2(_rigidbody2D.velocity.x, _rigidbody2D.velocity.y * .5f);
        }
    }

    private void AjustPlayerDiretion(float move) 
    {
        if (move > 0 && !goingRight)
            Flip();
        else if (move < 0 && goingRight)
            Flip();
    }

    private void Flip()
    {
        goingRight = !goingRight;
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;
        transform.localScale = theScale;
    }


    private bool isGrounded() 
    {
        if (_rigidbody2D.velocity.y > 0f)
            return false;
        Vector2 topLeftPoint = transform.position;
        topLeftPoint.x -= groundCollider.bounds.extents.x / 2;
        topLeftPoint.y += groundCollider.bounds.extents.y;
        Vector2 bottomRightPoint = transform.position;
        bottomRightPoint.x += groundCollider.bounds.extents.x / 2;
        bottomRightPoint.y -= groundCollider.bounds.extents.y + 0.3f;
        return Physics2D.OverlapArea(topLeftPoint, bottomRightPoint, ground);
    }

    private void Move() 
    {
        Vector3 targetVelocity = new Vector2(horizontalMove * speed, _rigidbody2D.velocity.y);
        _rigidbody2D.velocity = Vector3.SmoothDamp(_rigidbody2D.velocity, targetVelocity, ref _velocity, _movementSmoothing);
    }

    private void Jump()
    {
        if (hangCounter > 0f && jumpBufferCounter > 0f)
        {
            animator.SetBool("isJumping", true);
            _rigidbody2D.velocity = new Vector2(_rigidbody2D.velocity.x, jumpSpeed);
            hangCounter = 0f;
            jumpBufferCounter = 0f;
        }
    }

    public void OnLanding() 
    {
        animator.SetBool("isJumping", false);
    }
}


