using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// GAME 1303 Tier 1 — Generic health for players, enemies, bosses, and breakables.
///
/// SETUP
///  - Add to anything that can take damage. Set Max Health.
///  - Invulnerability Time gives i-frames after a hit (set 0 for enemies).
///  - Hook things up in the Inspector events:
///       OnHealthChanged(current, max) -> HUD health bar
///       OnDamaged                     -> hurt animation, SFX, screen shake
///       OnDied                        -> RespawnManager.RespawnPlayer, or Destroy for enemies
///  - "Destroy On Death" is a convenience for enemies/breakables. Leave it OFF for the player.
///
/// From other scripts:  GetComponent&lt;Health&gt;().TakeDamage(1);
/// </summary>
public class Health : MonoBehaviour
{
    [Header("Stats")]
    public int maxHealth = 3;
    [Tooltip("Seconds of invulnerability after taking damage. 0 = none.")]
    public float invulnerabilityTime = 1f;
    [Tooltip("Blink the sprite while invulnerable (needs a SpriteRenderer).")]
    public bool flashWhileInvulnerable = true;

    [Header("On Death")]
    public bool destroyOnDeath = false;
    public float destroyDelay = 0f;

    [Header("Events")]
    public UnityEvent<int, int> OnHealthChanged;   // (current, max)
    public UnityEvent OnDamaged;
    public UnityEvent OnHealed;
    public UnityEvent OnDied;

    public int CurrentHealth { get; private set; }
    public bool IsDead => CurrentHealth <= 0;
    public bool IsInvulnerable => invulnTimer > 0f;

    private float invulnTimer;
    private SpriteRenderer sr;

    void Awake()
    {
        CurrentHealth = maxHealth;
        sr = GetComponentInChildren<SpriteRenderer>();
    }

    void Start()
    {
        OnHealthChanged?.Invoke(CurrentHealth, maxHealth);
    }

    void Update()
    {
        if (invulnTimer > 0f)
        {
            invulnTimer -= Time.deltaTime;
            if (flashWhileInvulnerable && sr != null)
                sr.enabled = Mathf.FloorToInt(invulnTimer * 10f) % 2 == 0;   // 10 Hz blink
            if (invulnTimer <= 0f && sr != null) sr.enabled = true;
        }
    }

    /// <summary>Deal damage. Returns true if damage was actually applied.</summary>
    public bool TakeDamage(int amount)
    {
        if (IsDead || IsInvulnerable || amount <= 0) return false;

        CurrentHealth = Mathf.Max(0, CurrentHealth - amount);
        OnHealthChanged?.Invoke(CurrentHealth, maxHealth);
        OnDamaged?.Invoke();

        if (CurrentHealth == 0) Die();
        else invulnTimer = invulnerabilityTime;

        return true;
    }

    public void Heal(int amount)
    {
        if (IsDead || amount <= 0) return;
        CurrentHealth = Mathf.Min(maxHealth, CurrentHealth + amount);
        OnHealthChanged?.Invoke(CurrentHealth, maxHealth);
        OnHealed?.Invoke();
    }

    /// <summary>Instant kill regardless of i-frames (pits, acid, crushers).</summary>
    public void Kill()
    {
        if (IsDead) return;
        CurrentHealth = 0;
        OnHealthChanged?.Invoke(CurrentHealth, maxHealth);
        Die();
    }

    /// <summary>Restore to full. RespawnManager calls this.</summary>
    public void ResetHealth()
    {
        CurrentHealth = maxHealth;
        invulnTimer = 0f;
        if (sr != null) sr.enabled = true;
        OnHealthChanged?.Invoke(CurrentHealth, maxHealth);
    }

    void Die()
    {
        OnDied?.Invoke();
        if (destroyOnDeath) Destroy(gameObject, destroyDelay);
    }
}