// Project Sword & Gun Copyright © 2021 Kevin Poretti


#include "Components/SNGHealthComponent.h"

/** Sets default values for this component's properties */
USNGHealthComponent::USNGHealthComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = false;

	DefaultHealth = 100.0f;
	RecoverSpeed = 5;
	RecoverRate = 60.0f;
	RecoverCooldownDuration = 2.0f;
}

/**
 *	Returns the current amount of health
 *
 *	@returns Current health
 */ 
float USNGHealthComponent::GetHealth() const
{
	return Health;
}

/**
 *	Adds health to the current health variable
 *
 *	@param Delta amount of health to add
 */
void USNGHealthComponent::AddHealth(float Delta)
{
	Health = FMath::Clamp(Health + Delta, 0.0f, DefaultHealth);
	RecoverableHealth = FMath::Clamp(RecoverableHealth - Delta, 0.0f, DefaultHealth);
	
	UE_LOG(LogTemp, Log, TEXT("Health changed %s"), *FString::SanitizeFloat(Health));
	
	OnHealthChanged.Broadcast(this, Health, Delta);
}

/**
 *	Subtracts health from the current health variable
 *
 *	@param Delta amount of health to add
 */
void USNGHealthComponent::SubtractHealth(float Delta)
{
	Health = FMath::Clamp(Health - Delta, 0.0f, DefaultHealth);
	RecoverableHealth = FMath::Clamp(RecoverableHealth + Delta, 0.0f, DefaultHealth);
	UE_LOG(LogTemp, Log, TEXT("Health changed %s"), *FString::SanitizeFloat(Health));

	// Cancel looping timer that adds health over time
	GetWorld()->GetTimerManager().ClearTimer(TimerHandle_RecoverTick);
	
	// Set new timer which should trigger a function that starts health regen when the timer is up
	GetWorld()->GetTimerManager().SetTimer(TimerHandle_RecoverCooldown,
		this, &USNGHealthComponent::OnRecoverCooldownEnd, RecoverCooldownDuration, false);
	
	OnHealthChanged.Broadcast(this, Health, Delta);
}

/** Called when the game starts */
void USNGHealthComponent::BeginPlay()
{
	Super::BeginPlay();
	
	Health = DefaultHealth;
	RecoverableHealth = 0.0f;
}

/**
 *	Adds health back to Health variable and subtracts from RecoverableHealth every (RecoverRate ticks / second)
 */
void USNGHealthComponent::RecoverHealthTick()
{
	float HealthRecovered = FMath::Min(RecoverSpeed / RecoverRate, RecoverableHealth);
	AddHealth(HealthRecovered);

	// if there is no more health to recover reset the tick timer
	if(RecoverableHealth <= 0.0f)
	{
		GetWorld()->GetTimerManager().ClearTimer(TimerHandle_RecoverTick);
	}
}

/**
 *	Sets up the health recovery timer 
 */
void USNGHealthComponent::OnRecoverCooldownEnd()
{
	GetWorld()->GetTimerManager().SetTimer(TimerHandle_RecoverTick,
		this, &USNGHealthComponent::RecoverHealthTick, 1 / RecoverRate, true, 0.0);
}



