// Project Lab - NHTV Igad

#include "UnrealProject.h"
#include "NetworkCharacter.h"

#include "ProjectileBase.h"
#include "BlueprintAbilityLibrary.h"

#include "AbilityTriggerBase.h"

AProjectileBase::AProjectileBase()
{
	m_finishTimer = 0.0f;
	m_fixedTimer = 0.0f;
	maxDistance = 1000.0f;
	distanceTraveled = 0.0f;
	keepAliveAfterFinish = 1.0f;
	filter = EAbilityFilter::EnemyAll;
	m_finished = false;

	//server client replication
	bReplicateMovement = true;
	bReplicates = true;
	bAlwaysRelevant = true;
	PrimaryActorTick.bCanEverTick = true;
}

void AProjectileBase::BeginPlay()
{
	// Get collider component
	collider = Cast<UPrimitiveComponent>(GetRootComponent());
	if(!collider)
	{
		GWERROR(L"Projectile does not have a collider root!");
		Destroy();
		return;
	}


	if(Role != ROLE_Authority)
	{
		collider->SetCollisionEnabled(ECollisionEnabled::NoCollision);
	}
	else
	{
		collider->OnComponentHit.AddDynamic(this, &AProjectileBase::m_OnHit);
		collider->OnComponentBeginOverlap.AddDynamic(this, &AProjectileBase::m_OnOverlapBegin);
		//	collider->SetCollisionProfileName("Projectiles");
	}
	Super::BeginPlay();
}

void AProjectileBase::NativeFixedProjectileTick(float DeltaTime)
{
	FixedProjectileTick(DeltaTime);
}

//call this in inherited classes, will call move
void AProjectileBase::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	// Fixed timestep for projectiles
	m_fixedTimer += DeltaTime;
	FVector startPos = GetActorLocation();
	const float delta = 1.0f / 60.0f;
	while(m_fixedTimer >= delta)
	{
		NativeFixedProjectileTick(delta);
		if (autoMove)
		{
			NativeMove(DeltaTime);

			FVector newLocation = GetActorLocation();
			FVector movedVector = newLocation - startPos;
			startPos = newLocation;

			distanceTraveled += movedVector.Size();
		}
		if (distanceTraveled > maxDistance)
		{
			Finish();
			break;
		}
		m_fixedTimer -= delta;
	}

	if(m_finished && autoDestroy)
	{
		if((m_finishTimer -= DeltaTime) <= 0.0f)
		{
			Destroy();
		}
	}
}


void AProjectileBase::m_OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	ANetworkCharacter* netChar = Cast<ANetworkCharacter>(OtherActor);
	if(netChar && ULib::CheckAbilityFilter(filter, character, netChar))
	{
		OnProjectileHit(netChar);
	}
}
void AProjectileBase::m_OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	Finish();
}

void AProjectileBase::Finish_Implementation()
{
	if(!m_finished)
	{
		if(Role == ROLE_Authority)
		{
			NativeServerOnFinish();
		}
		NativeOnProjectileFinished();
		if(collider)
			collider->SetCollisionEnabled(ECollisionEnabled::NoCollision);
		m_finishTimer = keepAliveAfterFinish;
		m_finished = true;
	}
}

void AProjectileBase::FixedProjectileTick_Implementation(float DeltaTime)
{
}
void AProjectileBase::OnProjectileHit_Implementation(ANetworkCharacter* character)
{
	NativeOnProjectileHit(character);
}

void AProjectileBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME_CONDITION(AProjectileBase, speed, COND_InitialOnly);
	DOREPLIFETIME_CONDITION(AProjectileBase, filter, COND_InitialOnly);
	DOREPLIFETIME_CONDITION(AProjectileBase, maxDistance, COND_InitialOnly);
	DOREPLIFETIME_CONDITION(AProjectileBase, autoMove, COND_InitialOnly);
	DOREPLIFETIME_CONDITION(AProjectileBase, autoDestroy, COND_InitialOnly);
}

void AProjectileBase::Move(float DeltaTime)
{
	NativeMove(DeltaTime);
}

void AProjectileBase::NativeMove(float DeltaTime)
{
	//moves with sweep to get collision
	float distance = speed * DeltaTime;
	AddActorWorldOffset(GetActorForwardVector() * distance,true);
}

void AProjectileBase::OnProjectileFinished_Implementation()
{

}
void AProjectileBase::NativeOnProjectileFinished()
{
	OnProjectileFinished();
}

void AProjectileBase::NativeOnProjectileHit(ANetworkCharacter* hitCharacter)
{
}

void AProjectileBase::NativeServerOnFinish()
{
	ServerOnFinish();
}
