using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = System.Random;

namespace Creatures.Player.Movement
{
    public class PlayerAttack : MonoBehaviour
    {
        private InputManager _inputManager;
        private LayerMask _enemyLayermask;
        private Animate _animate;
        private Collider _hurtbox;
        private string[] _availableAttacks;
        private float _baseDamage;
        private float _comboStep;
        private AnimationCurve _comboCurve;
        private PlayerSound _playerSound;
        public void initialize(InputManager inputManager, LayerMask enemyLayermask, Animate animate, Collider hurtbox, string[] availableAttacks, float baseDamage, float comboStep, AnimationCurve comboCurve, PlayerSound playerSound)
        {
            _inputManager = inputManager;
            _enemyLayermask = enemyLayermask;
            _hurtbox = hurtbox;
            _animate = animate;
            _availableAttacks = availableAttacks;
            _baseDamage = baseDamage;
            _comboStep = comboStep;
            _comboCurve = comboCurve;
            _playerSound = playerSound;
        
            OnEnable();
        }

        #region Event Setup

        private void OnEnable()
        {
            if (_animate != null)
            {
                _animate.OnReset += _onResetHandler;
                _animate.OnStartDamage += _onStartDamageHandler;
                _animate.OnEndDamage += _onEndDamageHandler;
                _animate.OnAnimationEnd += _onAnimationEndHandler;
            }
        
            _canAttack = true;
            _attacking = false;
            _damageEnded = true;
            _currentDamageMultiplier = new Dictionary<int, float>();
        }

        private void OnDisable()
        {
            _animate.OnReset -= _onResetHandler;
            _animate.OnStartDamage -= _onStartDamageHandler;
            _animate.OnEndDamage -= _onEndDamageHandler;
            _animate.OnAnimationEnd -= _onAnimationEndHandler;
        }
    
        private void _onResetHandler()
        {
            _canAttack = true;
        }
    
        private void _onAnimationEndHandler()
        {
            _attacking = false;
            _currentDamageMultiplier = new Dictionary<int, float>();
            _lastDamageMultiplier = new Dictionary<int, float>();
        }

        private void _onStartDamageHandler()
        {
            StartCoroutine(DealDamage());
        }

        private void _onEndDamageHandler()
        {
            _damageEnded = true;
        }
    
        #endregion
    
        private bool _attacking=false;
        private bool _canAttack = true;
        private int _attack = 0;
        public bool Attack()
        {
            if (_canAttack && _inputManager.attackPerformed)
            {
                if (_attack >= 2 || _animate.IsCurrentAnimation("Blend Tree"))
                {
                    _attack = 0;
                }

                _playerSound.playWooshSound();
                _animate.TriggerAnimation(_availableAttacks[_attack]);
            
                _canAttack = false;
                _attack++;
                _attacking = true;
            }

            return _attacking;
        }

        private bool _damageEnded = true;
        Dictionary<int, float> _lastDamageMultiplier = new Dictionary<int, float>();
        Dictionary<int, float> _currentDamageMultiplier = new Dictionary<int, float>();
        private bool hitSoundPlayed = false;
        IEnumerator DealDamage()
        {
            List<Collider> damagedColliders = new List<Collider>();
            _currentDamageMultiplier = new Dictionary<int, float>();
            _damageEnded = false;
            
            while (!_damageEnded)
            {
                hitSoundPlayed = false;
                Collider[] hitColliders = Physics.OverlapBox(_hurtbox.bounds.center, _hurtbox.bounds.extents, Quaternion.identity, _enemyLayermask);
            
                foreach (Collider enemy in hitColliders)
                {
                    if (!damagedColliders.Contains(enemy))
                    {
                        if (!hitSoundPlayed)
                        {
                            hitSoundPlayed = true;
                            _playerSound.playHitSound();
                        }
                        print(enemy.gameObject.GetComponent<Vitals>());
                        enemy.gameObject.GetComponent<Vitals>().Health = -CalculateDamage(enemy);
                        damagedColliders.Add(enemy);
                    }
                }
                
                yield return null;
            }
            
            _lastDamageMultiplier = _currentDamageMultiplier;
        }

        float CalculateDamage(Collider enemy)
        {
            print(_lastDamageMultiplier.ContainsKey(enemy.GetInstanceID()));
            // If enemy is hit for the first time during "Combo" he gets added to the dictionary to get its own combo mult
            if (!_lastDamageMultiplier.ContainsKey(enemy.GetInstanceID()))
            {
                _currentDamageMultiplier.Add(enemy.GetInstanceID(), 0f);
            }
            // If enemy gets hit again its Combo mult is incremented
            else if(_lastDamageMultiplier.ContainsKey(enemy.GetInstanceID()))
            {
                _currentDamageMultiplier.Add(enemy.GetInstanceID(), _lastDamageMultiplier[enemy.GetInstanceID()]);
                Random rnd = new Random();
                _currentDamageMultiplier[enemy.GetInstanceID()] += _comboStep * (rnd.Next(1, 10) / 10f);
            }
            
            return _baseDamage * _comboCurve.Evaluate(_currentDamageMultiplier[enemy.GetInstanceID()]);
        }
    }
}