// Project Lab - NHTV Igad

#include "UnrealProject.h"
#include "SpawnerBase.h"
#include "EnemyBase.h"
#include "AbilityInfo.h"
#include "NetworkPlayer.h"
#include "GeneralEnemy.h"
#include "BehaviorTree/EnemyAIController.h"
#include "BehaviorTree/BehaviorTree.h"
#include "MinionAnimInstance.h"

AEnemyBase::AEnemyBase()
{
	PrimaryActorTick.bCanEverTick = true;
	finnishedAttack = false;
	informGeneralTime = 2.0f;
	m_tempTarget = nullptr;
	//	AIControllerClass = AEnemyAIController::StaticClass();
}
void AEnemyBase::BeginPlay()
{
	Super::BeginPlay();

	specialAbilityChance = m_ReCalcChance(specialAbilityChance);
	enemycontroller = Cast<AEnemyAIController>(GetController());
	if (enemycontroller && m_spawn)
	{
		enemycontroller->SetBool(true, FName("ClimbKey"));
		enemycontroller->SetVector(FVector(0, 0, 1), FName("ClimbDirection"));
		enemycontroller->SetVector(m_spawn->GetActorLocation() + FVector(0, 0, 100), FName("ClimbLocation"));

	}
	else
	{

		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>(AEnemyAIController::StaticClass(), GetActorLocation(), GetActorRotation(), SpawnInfo);
		if (NewController != NULL)
		{
			// if successful will result in setting this->Controller 
			// as part of possession mechanics
			NewController->Possess(this);
		}
		enemycontroller = Cast<AEnemyAIController>(GetController());
		if (enemycontroller && m_spawn)
		{
			if (m_spawn->SpawnLocation.Num() > 0)
			{
				PlayClimbingAnimation();
				enemycontroller->SetBool(true, FName("ClimbKey"));
				enemycontroller->SetVector(FVector(0, 0, 1), FName("ClimbDirection"));
				enemycontroller->SetVector(m_spawn->GetActorLocation() + FVector(0, 0, 100), FName("ClimbLocation"));
			}
		}
		else
		{
			//		RERROR("There is no valid controller on this enemy");
		}
	}
	hasSpawned = false;
	
}
void AEnemyBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);
	general = nullptr;
	if (m_spawn)
	{

		if (m_spawn->hasGeneral)
		{
			m_spawn->formationEnemies.Remove(this);
		}
	}
}

void AEnemyBase::Tick(float deltaTime)
{
	Super::Tick(deltaTime);
	if (Role != ROLE_Authority)
	{
		return;
	}
	m_confusionTimer -= deltaTime;
	if (!IsA(AGeneralEnemy::StaticClass()))
		m_hasGeneral = hasGeneral;
	if (!hasGeneral && enemycontroller && enemycontroller->IsA(AEnemyAIController::StaticClass()))
	{
		
		enemycontroller->SetBool(false, FName("EnableTree"));
	}

	if (IsValid(target))
	{
		if (hasGeneral)
		{
			m_informGeneralTimer -= deltaTime;
			if (m_informGeneralTimer < 0.0f&&IsValid(general))
				InformGeneral();
		}
		else
		{
			SwitchAgro();
		}
	} 
	else if(!hasGeneral)
	{
		FVector randpos = FMath::VRand();
		randpos.Z = 0.0f;
		float randomRange = FMath::FRandRange(m_spawn->aggroRadius / 4, m_spawn->aggroRadius);

		randpos = randpos*randomRange;

		MoveToPointSlow(randpos + m_spawn->GetActorLocation(), 50.0f);
	}
}
void AEnemyBase::InformGeneral()
{
	if (!IsValid(general) || !IsValid(target))
		return;
	if (FVector::DistSquared(m_spawn->GetActorLocation(), target->GetActorLocation()) > m_spawn->deaggroRadius*m_spawn->deaggroRadius)
		return;
	if( !IsValid(general->target))
	{
		general->target = m_tempTarget;
		ChangeNPCAnimation((uint8)EMinionAnimState::MAS_Pointing);
		//CHANGEANIMATION(EMinionAnimState::MAS_Pointing);

		m_informGeneralTimer = informGeneralTime;
		m_tempTarget = nullptr;
	}
}
void AEnemyBase::SwitchAgro()
{
	if (m_spawn->GetNearbyPlayers().Num() <= 1)
		return;
	float mostDamage =0.0f;
	ANetworkCharacter* character = nullptr;
	for (int i = 0; i < m_spawn->GetNearbyPlayers().Num(); i++)
	{     
		if (m_spawn->GetNearbyPlayers()[i]->GetTotalDamage()>mostDamage)
		{
			mostDamage = m_spawn->GetNearbyPlayers()[i]->GetTotalDamage();
			character = m_spawn->GetNearbyPlayers()[i];
		}
	}
	if(IsValid(character))
		this->target = character;
}
void AEnemyBase::ConfusionBehavior()
{
	FVector randpos = FMath::VRand();
	randpos.Z = 0.0f;
	float randomRange = FMath::FRandRange(m_spawn->aggroRadius / 4, m_spawn->aggroRadius);

	randpos = randpos*randomRange;

	MoveToPointSlow(randpos + m_spawn->GetActorLocation(), 50.0f);
}
void AEnemyBase::ChargeBehavior()
{

}
void AEnemyBase::OffensiveBehavior()
{

	
}
void AEnemyBase::RangedBehavior()
{
}
void AEnemyBase::ResetConfusionTimer(float confusionTime)
{
	m_confusionTimer = confusionTime;
}
float AEnemyBase::m_ReCalcChance(float chance)
{
	return (1000 - (chance * 10));
}
int32  AEnemyBase::NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability)
{
	m_tempTarget = dealer;
	m_informGeneralTimer = informGeneralTime;
	return Super::NativeDealDamage(dealer, damage, armorPercentageIgnore, ability);
}