// Project Lab - NHTV Igad

#include "UnrealProject.h"
#include "Creatures/NetworkCharacter.h"
#include "Creatures/NetworkPlayer.h"
#include "IllusionCharacter.h"
#include "BlueprintAbilityLibrary.h"
#include "AIController.h"
#include "DealDamageProxy.h"
#include "AbilityInfo.h"
#include "NativeModifiers.h"

AIllusionCharacter::AIllusionCharacter()
{
	PrimaryActorTick.bCanEverTick = true;
	aggroRange = 400;
	acceptenceDistance = 200;
	lifeTime = 30;
}

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

	if (Role != ROLE_Authority)
	{
		return;
	}
	FActorSpawnParameters SpawnInfo;
	SpawnInfo.Instigator = Instigator;
	SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
	SpawnInfo.OverrideLevel = GetLevel();
	SpawnInfo.ObjectFlags |= RF_Transient;	// We never want to save AI controllers into a map
	AController* NewController = GetWorld()->SpawnActor<AController>(AAIController::StaticClass(), GetActorLocation(), GetActorRotation(), SpawnInfo);

	if (NewController != NULL)
	{
		// if successful will result in setting this->Controller 
		// as part of possession mechanics
		NewController->Possess(this);
	}
	
	if (IsValid(illOwner))
	{
		m_maxHealth = illOwner->GetMaxHealth();
		m_health = illOwner->GetHealth();
	}
	else
	{
		FERROR("NO ILLOWNER IN ILLUSIONCHARACTER");
	}
	if (illOwner)
	{
		abilities.Add(illOwner->abilities[0]);
		m_attackSpeed =illOwner->m_attackSpeed;
	}
		m_isdying = false;
}
void AIllusionCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);
}
void AIllusionCharacter::Tick(float deltaTime)
{
	Super::Tick(deltaTime);
	if (Role != ROLE_Authority)
	{
		return;
	}
	lifeTime -= deltaTime;
	if (lifeTime <= 0)
	{
		if(!m_isdying)
			Kill();
		return;
	}
	UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
	if (!NavSys)
	{
		RERROR("there is no nav sys");
	}
	if (!GetController())
	{
		RERROR("there is no controller");
	}
	if (!IsValid(illOwner))
	{
		Kill();
		return;
	}
	if (!IsValid(target))
	{
		attacking = false;
		//targetList = ULib::GetCharacterOverlaps();
		target = GetClosestTarget();
		if (FVector::DistSquared(illOwner->GetActorLocation(), GetActorLocation()) > acceptenceDistance*acceptenceDistance)
		{
			MoveTo(illOwner->GetActorLocation());
			FPRINT("moving to the illOwner");
		}
		else MoveTo(GetActorLocation());
		return;
	}
	if (!attacking)
	{
		attacking = IsAttacking(1.0f);
		return;
	}
	Attack();

}
void AIllusionCharacter::Attack()
{
	int randdistance =0;
	randdistance += ((int)abilities[0]->AICastRange / 2);
	if (FVector::Dist(GetActorLocation(), target->GetActorLocation()) < randdistance)
	{
		MoveTo(GetActorLocation());
		SetActorRotation(FVector(target->GetActorLocation() - GetActorLocation()).Rotation());
	}
	else MoveTo(target->GetActorLocation());
	for (int i = 0; i < abilities.Num(); i++)
	{
		if ((abilities[i])&&FVector::DistSquared(GetActorLocation(),target->GetActorLocation())<abilities[i]->AICastRange*abilities[i]->AICastRange)
		{
			CastAbility(abilities[i]);
		}
	}
}
ANetworkCharacter* AIllusionCharacter::GetClosestTarget()
{
	ANetworkCharacter* returnTarget = nullptr;
	float distance = 1e34;
	for (ANetworkCharacter* character : targetList)
	{
		if(!IsValid(character)||character==this || character->GetTeam()==GetTeam())
			continue;
		float tempdistance = FVector::DistSquared(character->GetActorLocation(), GetActorLocation());
		if (distance > tempdistance)
		{
			distance = tempdistance;
			returnTarget = character;
		}
	}
	return returnTarget;
}
void AIllusionCharacter::MoveTo(FVector Location)
{
	UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
	if (IsPendingKill() || IsPendingKillPending())
		return;
	if (!IsStunned())
	{
		NavSys->SimpleMoveToLocation(this->Controller, Location);
	}
	else
	{
		NavSys->SimpleMoveToLocation(this->Controller, GetActorLocation());
	}
}
bool AIllusionCharacter::IsAttacking(float changePercentage)
{
	int num = rand() % 100;
	if (num > (int)changePercentage)
	{
		return false;
	}
	return true;
}

void AIllusionCharacter::Kill()
{
	if (IsPendingKill() || IsPendingKillPending())
	{
		RERROR("the character is pending kill");
		return;

	}
	ADOTModifier* deathMod = GetWorld()->SpawnActor<ADOTModifier>();
	deathMod->damagePerTick = 500;
	deathMod->lifeTime = 0;
	deathMod->target = this;
	deathMod->character = this;
	deathMod->abilityInfo = abilityInfo;
	m_modifierManager->AddModifier(deathMod);
	m_isdying = true;
	//m_health = 0;
//	m_shouldBeDestroyed = true;
}