// Fill out your copyright notice in the Description page of Project Settings.


#include "SurvivalStatsComponent.h"

#include "Engine/World.h"
#include "TimerManager.h"

USurvivalStatsComponent::USurvivalStatsComponent()
{
	// Pas de Tick : tout passe par un timer a basse frequence.
	PrimaryComponentTick.bCanEverTick = false;
}

void USurvivalStatsComponent::BeginPlay()
{
	Super::BeginPlay();

	Health = MaxHealth;
	Hunger = MaxHunger;
	Thirst = MaxThirst;
	bDead = false;

	if (UWorld* World = GetWorld())
	{
		World->GetTimerManager().SetTimer(
			UpdateTimerHandle, this, &USurvivalStatsComponent::UpdateStats,
			FMath::Max(UpdateInterval, 0.05f), /*bLoop=*/true);
	}

	OnStatsChanged.Broadcast();
}

void USurvivalStatsComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	// Un timer laisse en vie apres la destruction du composant rappellerait
	// une methode sur un objet mort.
	if (UWorld* World = GetWorld())
	{
		World->GetTimerManager().ClearTimer(UpdateTimerHandle);
	}

	Super::EndPlay(EndPlayReason);
}

void USurvivalStatsComponent::UpdateStats()
{
	if (bDead)
	{
		return;
	}

	// Les vitesses sont par minute, l'intervalle en secondes.
	const float Minutes = FMath::Max(UpdateInterval, 0.05f) / 60.f;

	Hunger = FMath::Max(0.f, Hunger - HungerDecayPerMinute * Minutes);
	Thirst = FMath::Max(0.f, Thirst - ThirstDecayPerMinute * Minutes);

	// Faim ET soif a zero cumulent leurs degats : mourir de soif pendant
	// qu'on meurt de faim doit aller plus vite.
	float Damage = 0.f;
	if (Hunger <= 0.f)
	{
		Damage += StarvationDamagePerMinute * Minutes;
	}
	if (Thirst <= 0.f)
	{
		Damage += DehydrationDamagePerMinute * Minutes;
	}

	if (Damage > 0.f)
	{
		Health = FMath::Max(0.f, Health - Damage);
	}

	OnStatsChanged.Broadcast();

	if (Health <= 0.f && !bDead)
	{
		bDead = true;

		if (UWorld* World = GetWorld())
		{
			World->GetTimerManager().ClearTimer(UpdateTimerHandle);
		}

		UE_LOG(LogTemp, Log, TEXT("USurvivalStatsComponent : %s est mort."), *GetNameSafe(GetOwner()));
		OnDied.Broadcast();
	}
}

void USurvivalStatsComponent::ApplyRestore(float HealthAmount, float HungerAmount, float ThirstAmount)
{
	if (bDead)
	{
		return;
	}

	Health = FMath::Clamp(Health + HealthAmount, 0.f, MaxHealth);
	Hunger = FMath::Clamp(Hunger + HungerAmount, 0.f, MaxHunger);
	Thirst = FMath::Clamp(Thirst + ThirstAmount, 0.f, MaxThirst);

	OnStatsChanged.Broadcast();
}

void USurvivalStatsComponent::ApplyDamage(float Amount)
{
	if (bDead || Amount <= 0.f)
	{
		return;
	}

	Health = FMath::Max(0.f, Health - Amount);
	OnStatsChanged.Broadcast();

	if (Health <= 0.f)
	{
		bDead = true;

		if (UWorld* World = GetWorld())
		{
			World->GetTimerManager().ClearTimer(UpdateTimerHandle);
		}

		OnDied.Broadcast();
	}
}
