using System.Collections;
using UnityEngine;
using UnityEngine.Events;

namespace Shooter.Gameplay
{
    /// <summary>
    /// Универсальный компонент «здоровья/прочности». Висит на игроке, врагах и
    /// разрушаемых объектах. Принимает урон, хранит запас прочности, оповещает
    /// подписчиков событием <see cref="OnDamaged"/> и подсвечивает модель при попадании.
    /// </summary>
    public class DamageControl : MonoBehaviour
    {
        [Tooltip("Максимальный запас прочности")]
        public float MaxDamage = 100;

        [HideInInspector] public float Damage = 100;      // текущая прочность
        [HideInInspector] public bool IsDead = false;
        [HideInInspector] public bool m_NoDamage = false; // неуязвимость

        [HideInInspector] public Vector3 LastDamageDirection;
        [HideInInspector] public float LastDamageFactor = 1;

        // Подёргивание модели при попадании (враги используют для «тряски»).
        [HideInInspector] public float DamageShakeAmount;
        [HideInInspector] public float DamageShakeAngle;

        public UnityEvent OnDamaged;

        void Awake()
        {
            OnDamaged = new UnityEvent();
        }

        void Start()
        {
            Damage = MaxDamage;
            IsDead = false;
            LastDamageDirection = Vector3.forward;
            DamageShakeAmount = 0;
            DamageShakeAngle = 0;
        }

        void Update()
        {
            // Подёргивание от попадания затухает к нулю.
            DamageShakeAmount = Mathf.Max(0, DamageShakeAmount - 12 * Time.deltaTime);
        }

        public void ApplyDamage(float dmg, Vector3 dir, float DamageFactor)
        {
            if (m_NoDamage || IsDead)
                return;

            ApplyDamageShake();
            LastDamageDirection = dir;
            LastDamageDirection.Normalize();
            LastDamageFactor = DamageFactor;

            Damage -= dmg;
            if (Damage <= 0)
            {
                Damage = 0;
                IsDead = true;
            }

            OnDamaged.Invoke();
            StartCoroutine(Co_HitGlow());
        }

        /// <summary>Кратко подсвечивает все «светящиеся при попадании» части модели.</summary>
        public IEnumerator Co_HitGlow()
        {
            HitGlowControl[] glowControls = GetComponentsInChildren<HitGlowControl>();
            foreach (HitGlowControl item in glowControls)
                item.SetGlow();

            yield return new WaitForSeconds(.1f);

            foreach (HitGlowControl item in glowControls)
                item.SetOriginal();
        }

        public void AddHealth(float h)
        {
            Damage = Mathf.Clamp(Damage + h, 0, MaxDamage);
        }

        /// <summary>Запускает однократное подёргивание модели (если оно уже не идёт).</summary>
        public void ApplyDamageShake()
        {
            if (DamageShakeAmount == 0)
            {
                DamageShakeAmount = 1;
                DamageShakeAngle = Random.Range(-1f, 1f);
            }
        }

        public void Reset()
        {
            Damage = MaxDamage;
            IsDead = false;
        }
    }
}
