using UnityEngine;
using UnityEngine.Events;
using TMPro;
using System;
using UnityUtils;

public class HealthComponent : MonoBehaviour, ISquezeDamageReceiver
{
    [SerializeField] private bool onlyCallZeroHealthOnce = true;
    [SerializeField] float maxHealth = 100;

    [SerializeField] float damageTickDelay = 0.25f;
    private float currentDamageTick = 0f;
    private float accumulatedDamageInTick = 0f;

    public float currentHealth {  get; private set; }

    public static event Action<Vector3, float> OnHealthChangeAtPos;

    public UnityEvent OnHealthZero;
    public UnityEvent<float, float> OnHealthChange;

    [Header("Squeze Damage")]
    [SerializeField]
    float minThreshold = 1f;

    [SerializeField]
    float squezeDamageScalor = 1f;

    bool alreadyReachedZero = false;

    void Awake()
    {
        currentHealth = maxHealth;
    }

    void Update()
    {
        if (currentDamageTick < Time.time)
        {
            if (accumulatedDamageInTick < 1f) return;

            OnHealthChangeAtPos?.Invoke(transform.position.Add(y: 2f), accumulatedDamageInTick);
            currentDamageTick = Time.time + damageTickDelay;
            accumulatedDamageInTick = 0f;
        }
    }

    public float getMaxHealth() {
        return maxHealth;
    }

    public void setMaxHealth(float amount, bool heal = false) {
        maxHealth = amount;

        if (heal)
            currentHealth = amount;
    }

    public void TakeDamage(float damage)
    {
        currentHealth -= damage;
        OnHealthChange?.Invoke(currentHealth + damage, currentHealth);

        accumulatedDamageInTick += damage;

        if (currentHealth <= 0) {
            if (alreadyReachedZero && onlyCallZeroHealthOnce) return;

            alreadyReachedZero = true;
            // Make sure to flush accumulated when dying
            if (accumulatedDamageInTick > 1f)
                OnHealthChangeAtPos?.Invoke(transform.position.Add(y: 2f), accumulatedDamageInTick);

            OnHealthZero?.Invoke();

            if (BloodComputeShader.Instance != null)
            {
                int blood = (int)(maxHealth * 100.0f * BloodComputeShader.Instance.scoreMult);

                BloodComputeShader.Instance.createBlood(transform.position, blood / 2, maxHealth / 8.0f);
                BloodComputeShader.Instance.createBlood(transform.position, blood / 2, maxHealth / 8.0f);
            }
        }
    }

    public void TakeSquezeDamage(float squezeDamage)
    {
        if (squezeDamage < minThreshold) return;

        TakeDamage((int) Mathf.Round(squezeDamage * squezeDamageScalor));
    }

    public void EnemyKill()
    {

        Destroy(gameObject);
    }
}