// Copyright Pacificao. All Rights Reserved.

#include "AgrarianShelterActor.h"
#include "AgrarianPersistentActorComponent.h"
#include "Components/BoxComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Net/UnrealNetwork.h"

AAgrarianShelterActor::AAgrarianShelterActor()
{
	bReplicates = true;
	NetCullDistanceSquared = FMath::Square(6000.0f);

	Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
	RootComponent = Mesh;

	ProtectionVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("ProtectionVolume"));
	ProtectionVolume->SetupAttachment(RootComponent);
	ProtectionVolume->SetBoxExtent(FVector(250.0f, 250.0f, 180.0f));
	ProtectionVolume->SetCollisionProfileName(TEXT("OverlapAllDynamic"));

	PersistentActorComponent = CreateDefaultSubobject<UAgrarianPersistentActorComponent>(TEXT("PersistentActorComponent"));
	PersistentActorComponent->ActorTypeId = TEXT("primitive_shelter");
}

void AAgrarianShelterActor::BeginPlay()
{
	Super::BeginPlay();
	ClampStructureHealth();
}

float AAgrarianShelterActor::TakeDamage(float DamageAmount, const FDamageEvent& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
	const float PreviousHealth = CurrentStructureHealth;
	ApplyStructureDamage(DamageAmount, DamageCauser);
	return FMath::Max(0.0f, PreviousHealth - CurrentStructureHealth);
}

void AAgrarianShelterActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(AAgrarianShelterActor, MaxStructureHealth);
	DOREPLIFETIME(AAgrarianShelterActor, CurrentStructureHealth);
}

void AAgrarianShelterActor::CapturePersistentState_Implementation(UAgrarianPersistentActorComponent* PersistentComponent) const
{
	if (!PersistentComponent)
	{
		return;
	}

	PersistentComponent->NumberState.Add(TEXT("max_structure_health"), MaxStructureHealth);
	PersistentComponent->NumberState.Add(TEXT("current_structure_health"), CurrentStructureHealth);
}

void AAgrarianShelterActor::ApplyPersistentState_Implementation(UAgrarianPersistentActorComponent* PersistentComponent)
{
	if (!HasAuthority() || !PersistentComponent)
	{
		return;
	}

	if (const float* SavedMaxHealth = PersistentComponent->NumberState.Find(TEXT("max_structure_health")))
	{
		MaxStructureHealth = FMath::Max(1.0f, *SavedMaxHealth);
	}

	if (const float* SavedCurrentHealth = PersistentComponent->NumberState.Find(TEXT("current_structure_health")))
	{
		CurrentStructureHealth = *SavedCurrentHealth;
	}

	ClampStructureHealth();
}

bool AAgrarianShelterActor::ApplyStructureDamage(float DamageAmount, AActor* DamageCauser)
{
	if (!HasAuthority() || DamageAmount <= 0.0f || CurrentStructureHealth <= 0.0f)
	{
		return false;
	}

	CurrentStructureHealth = FMath::Clamp(CurrentStructureHealth - DamageAmount, 0.0f, MaxStructureHealth);
	if (CurrentStructureHealth <= 0.0f && bDestroyWhenHealthDepleted)
	{
		Destroy();
	}

	return true;
}

bool AAgrarianShelterActor::RepairStructure(float RepairAmount)
{
	if (!HasAuthority() || RepairAmount <= 0.0f || CurrentStructureHealth >= MaxStructureHealth)
	{
		return false;
	}

	CurrentStructureHealth = FMath::Clamp(CurrentStructureHealth + RepairAmount, 0.0f, MaxStructureHealth);
	return true;
}

bool AAgrarianShelterActor::Deconstruct(AActor* RequestingActor)
{
	if (!HasAuthority() || !bCanBeDeconstructed)
	{
		return false;
	}

	Destroy();
	return true;
}

float AAgrarianShelterActor::GetStructureHealthRatio() const
{
	return MaxStructureHealth > 0.0f ? FMath::Clamp(CurrentStructureHealth / MaxStructureHealth, 0.0f, 1.0f) : 0.0f;
}

bool AAgrarianShelterActor::IsStructureDamaged() const
{
	return CurrentStructureHealth < MaxStructureHealth;
}

void AAgrarianShelterActor::OnRep_StructureHealth()
{
	ClampStructureHealth();
}

void AAgrarianShelterActor::ClampStructureHealth()
{
	MaxStructureHealth = FMath::Max(1.0f, MaxStructureHealth);
	CurrentStructureHealth = FMath::Clamp(CurrentStructureHealth, 0.0f, MaxStructureHealth);
}
