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

public class Player : MonoBehaviour
{
    private Rigidbody2D _rigidbody;
    
    [Header("이동속도")]
    [Range(1, 20)] public float jumpVelocity;
    [Range(1, 20)] public float moveVelocity;
    
    [Header("대쉬 설정")]
    [Range(1,10)] public float dashDistance = 5f;
    public float dashDuration = 0.2f;
    public float gravityRecoveryTime = 0.15f;

    [Header("중력 물리")]
    public float fallMultiplier = 2.5f;
    public float lowJumpMultiplier = 2f;
    private float _gravityWeight = 1f;

    [Header("체력")]
    [SerializeField] private int currentHp;
    [SerializeField] private int maxHp = 10;

    [Header("레이어 설정")] 
    [SerializeField] private LayerMask enemyLayer;

    [Header("공격 설정")]
    [SerializeField] private Vector2 attackBoxSize = new Vector2(2f, 1f);

    public bool _isJumping;
    private bool _isGrounded;
    private bool _isJumpOnAir;
    private bool _isDashing;
    private bool _isFacingRight;
    
    public Collider2D footCollider;

    private Vector2 _inputVector;
    private float _gravity;

    public bool IsDashing => _isDashing;

    void Start()
    {
        _rigidbody = GetComponent<Rigidbody2D>();
        _gravity = Physics2D.gravity.y;
        currentHp = maxHp;
        _isFacingRight = true;
    }

    public void SetInputVector(InputValue value)
    {
        _inputVector = value.Get<Vector2>();
        if (_inputVector.x != 0)
        {
            transform.localScale = new Vector3(_inputVector.x > 0 ? 1 : -1, 1, 1);
            _isFacingRight = _inputVector.x > 0;
        }
    }

    public void SetJumpState(bool isPressed)
    {
        _isJumping = isPressed;
        if (isPressed)
        {
            Jump();
        }
    }

    public void Jump()
    {
        if (_isDashing) return;
        
        if (_isGrounded || !_isJumpOnAir)
        {
            _rigidbody.linearVelocity = Vector2.up * jumpVelocity;
            if (!_isGrounded)
            {
                _isJumpOnAir = true;
            }
        }
    }

    public void Dash()
    {
        if (_isDashing || _inputVector == Vector2.zero) return;
        StartCoroutine(DashRoutine());
    }
    
    public void MoveHorizontal()
    {
        if (_isDashing) return;
        _rigidbody.linearVelocity = new Vector2(_inputVector.x * moveVelocity, _rigidbody.linearVelocity.y);
    }
    
    public void AddGravityForceOnJump()
    {
        if (_isDashing) return;
        
        if (GroundCheck())
        {
            _gravityWeight = 1f;
            return;
        }

        float gravityMultiplier = 0f;
        if (_rigidbody.linearVelocity.y < 0)
        {
            gravityMultiplier = fallMultiplier;
        } 
        else if (_rigidbody.linearVelocity.y > 0 && !_isJumping)
        {
            gravityMultiplier = lowJumpMultiplier;
        }
        else
        {
            gravityMultiplier = 1f;
        }
        
        Vector2 gravityForce = Vector2.up * _gravity * (gravityMultiplier - 1) * Time.deltaTime;
        _rigidbody.linearVelocity += gravityForce * _gravityWeight;
    }

    private bool GroundCheck()
    {
        _isGrounded = footCollider.IsTouchingLayers(LayerMask.GetMask("Ground"));
        if (_isGrounded)
        {
            _isJumpOnAir = false;
        }
        return _isGrounded;
    }
    
    private IEnumerator DashRoutine()
    {
        float originGravity = _rigidbody.gravityScale;

        _rigidbody.gravityScale = 0f;
        _isDashing = true;
        _gravityWeight = 0f;
        
        float dashSpeed = dashDistance / dashDuration;
        Vector2 dashVelocity = _inputVector.normalized * dashSpeed;
        
        float startTime = Time.time;
        while (Time.time < startTime + dashDuration)
        {
            _rigidbody.linearVelocity = dashVelocity;
            yield return new WaitForFixedUpdate();
        }
        
        _rigidbody.gravityScale = originGravity;
        _isDashing = false;
        _rigidbody.linearVelocity = Vector2.zero;
        
        float elapsed = 0f;
        while (elapsed < gravityRecoveryTime)
        {
            elapsed += Time.deltaTime;
            _gravityWeight = Mathf.Lerp(0f, 1f, elapsed / gravityRecoveryTime);
            yield return null;
        }
        _gravityWeight = 1f;
    }

    public void TakeDamage(int damage)
    {
        currentHp -= damage;

        if (GameManager.instance != null)
        {
            GameManager.instance.ResetCombo();
        }
        
        if (currentHp <= 0)
        {
            Die();
        }
    }

    private void Die()
    {
        Time.timeScale = 1f;
    }

    public void Heal(int amount)
    {
        currentHp += amount;
        if (currentHp > maxHp) currentHp = maxHp;
    }

    public void Attack()
    {
        if (_isDashing)
        {
            return;
        }

        Vector2 originPos = transform.TransformPoint(new Vector2(attackBoxSize.x / 2f, 0f));
        Collider2D[] enimes = Physics2D.OverlapBoxAll(originPos, attackBoxSize, 0, enemyLayer);
        foreach (Collider2D enemy in enimes)
        {
            enemy.gameObject.GetComponent<Entity>().TakeDamage(10);
        }
    }
}