using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using Rewired;
using UnityEngine;
using UnityEngine.UI;

namespace GGJ2021
{
    public class PlayerManager : MonoBehaviour
    {
        enum PlayerState
        {
            Frozen,
            Default,
            OnWall
        }

        [SerializeField]
        [Range(0.1f, 0.5f)]
        private float staminaDrainSpeed = 0.25f;

        [SerializeField]
        [Range(0.1f, 0.5f)]
        private float staminaRecoverySpeed = 0.2f;

        [SerializeField]
        private Image staminaBarUI = null;

        [SerializeField]
        private Gradient staminaBarGradient = null;

        [SerializeField]
        private Animator animator = null;

        [SerializeField]
        private GameObject groundRobe = null;

        private PlayerState _playerState;
        private Player _player;
        private PlayerMovementController _playerMovementController;
        private PlayerCamouflage _playerCamouflage;

        private float _currentStamina = 1f;
        private bool _forcedStaminaRecovery = false;

        private void Awake()
        {
            _player = ReInput.players.GetPlayer(0);

            _playerMovementController = GetComponent<PlayerMovementController>();
            _playerCamouflage = GetComponent<PlayerCamouflage>();

            staminaBarUI.color = staminaBarGradient.Evaluate(1f);
            _playerState = PlayerState.Frozen;
            _playerMovementController.pause = true;
        }

        private void Update()
        {
            UpdateStaminaBar();

            var speedPerc = Mathf.Clamp01(_playerMovementController.movement.velocity.magnitude / (_playerMovementController.speed - 1f));
            animator.SetFloat("Speed", speedPerc);

            switch (_playerState)
            {
                case PlayerState.Frozen:
                    {
                        break;
                    }
                case PlayerState.Default:
                    {
                        HandleDefaultInput();
                        break;
                    }
                case PlayerState.OnWall:
                    {
                        HandleWallInput();
                        break;
                    }
            }
        }

        private void OnEnable()
        {
            Messenger.AddListener(Events.OnGameLose, OnGameLose);
        }

        private void OnDisable()
        {
            Messenger.RemoveListener(Events.OnGameLose, OnGameLose);
        }

        private void OnTriggerEnter(Collider other)
        {
            if (other.CompareTag("WinItem"))
            {
                // Win game
                Messenger.Broadcast(Events.OnGameWin);
                _playerMovementController.pause = true;

                foreach (var enemy in FindObjectsOfType<EnemyController>())
                    enemy.Disable();
            }
        }

        private void HandleDefaultInput()
        {
            _currentStamina += staminaRecoverySpeed * Time.deltaTime;
            _currentStamina = Mathf.Clamp01(_currentStamina);

            if (_forcedStaminaRecovery && _currentStamina >= 1f)
            {
                _forcedStaminaRecovery = false;
                staminaBarUI.DOColor(staminaBarGradient.Evaluate(1f), 0.3f);
            }
            else if (!_forcedStaminaRecovery)
            {
                staminaBarUI.color = staminaBarGradient.Evaluate(_currentStamina);
            }

            if (!_forcedStaminaRecovery && _player.GetButtonDown("Action"))
            {
                if (_playerCamouflage.CheckIfNextToCamouflage())
                {
                    _playerState = PlayerState.OnWall;
                    _playerMovementController.pause = true;
                    animator.SetBool("Camo", true);
                    Messenger.Broadcast(Events.OnHideStart);
                    // StartCoroutine(TurnOnGroundRobe());
                }
            }

            if (_player.GetButtonDown("SelectLeft"))
                _playerCamouflage.HandleChangeCamo(false);
            else if (_player.GetButtonDown("SelectRight"))
                _playerCamouflage.HandleChangeCamo(true);
        }

        private IEnumerator TurnOnGroundRobe()
        {
            yield return new WaitForSeconds(0.2f);
            groundRobe.SetActive(true);
        }

        private void HandleWallInput()
        {
            if (_player.GetButtonUp("Action"))
            {
                ReleaseFromWall();
            }

            _currentStamina -= staminaDrainSpeed * Time.deltaTime;
            _currentStamina = Mathf.Clamp01(_currentStamina);
            staminaBarUI.color = staminaBarGradient.Evaluate(_currentStamina);

            if (_currentStamina <= 0)
            {
                ForceReleaseFromWall();
            }
        }

        private void ForceReleaseFromWall()
        {
            _forcedStaminaRecovery = true;
            staminaBarUI.color = staminaBarGradient.Evaluate(0f);
            ReleaseFromWall();
            Messenger.Broadcast(Events.OnHideEndByForce);
        }

        private void ReleaseFromWall()
        {
            _playerCamouflage.ReleaseFromWall();
            _playerState = PlayerState.Default;
            _playerMovementController.pause = false;
            animator.SetBool("Camo", false);
            // groundRobe.SetActive(false);
            Messenger.Broadcast(Events.OnHideEnd);
        }

        private void UpdateStaminaBar()
        {
            staminaBarUI.fillAmount = _currentStamina;
        }

        private void OnGameLose()
        {
            _playerMovementController.pause = true;
            _playerState = PlayerState.Frozen;

            foreach (var enemy in FindObjectsOfType<EnemyController>())
                enemy.Disable();
        }

        public void EnableControls()
        {
            _playerMovementController.pause = false;
            _playerState = PlayerState.Default;
        }
    }
}
