// Project Lab - NHTV Igad

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

AGeneralEnemy::AGeneralEnemy()
{

	PrimaryActorTick.bCanEverTick = true;
}
void AGeneralEnemy::BeginPlay()
{
	Super::BeginPlay();
	if (Role != ROLE_Authority)
		return;
	if (m_spawn)
	{
		m_spawn->hasGeneral = true;
		FVector addVector;
		for (int i = 0; i < 4; i++)
		{
			addVector = m_spawn->GetActorForwardVector().RotateAngleAxis(i * 90, FVector::UpVector);
			patrolLocations.Add(addVector);
		}
	}
	if (distance == 0)
	{
		distance = 100.0f;
	}
/*	for (int i = 0; i < formationEnemies.Num(); i++)
	{
		formationEnemies[i]->general = this;
	}*/


}
void AGeneralEnemy::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);
	if (Role != ROLE_Authority)
		return;
	for (int i = 0; i < formationEnemies.Num(); i++)
	{
		formationEnemies[i]->ResetConfusionTimer(3.0f);
		formationEnemies[i]->general = nullptr;
	}
	if (m_spawn != nullptr)
		m_spawn->hasGeneral = false;
	//formationEnemies.Empty();
}
void AGeneralEnemy::Tick(float deltaTime)
{
	Super::Tick(deltaTime);
	if (Role != ROLE_Authority)
		return;
	if (!IsValid(m_spawn))
	{
		RERROR("There is no spawn for the general enemy");
		return;
	}
	for (int i = 0; i < formationEnemies.Num(); i++)
	{
		if (IsValid(formationEnemies[i]->general))
			continue;
		formationEnemies[i]->general = this;
		
	}

	if (IsValid(target))
	{


		FVector2D locationVec = FVector2D(target->GetActorLocation()) - FVector2D(GetActorLocation());
		locationVec.Normalize();
		if (FVector::DistSquaredXY(GetActorLocation(), target->GetActorLocation()) > m_spawn->formationDistance* m_spawn->formationDistance)
		{

			MoveToPoint((target->GetActorLocation()));// +(FVector(locationVec, 0))* m_spawn->formationDistance));
			DefaultFormation();

		}
		else
		{
			GetCharacterMovement()->Velocity = FVector::ZeroVector;
			MoveToPoint(GetActorLocation());
			GetCharacterMovement()->Velocity = FVector::ZeroVector;
			SetActorRotation(FVector(target->GetActorLocation() - GetActorLocation()).Rotation());
			ChargeFormation();
		}

	}
	else
	{
		IdleFormation(deltaTime);
	}
}
void AGeneralEnemy::SingleTargetFormation(int enemyNum)
{
	if ((formationEnemies[enemyNum]->enemycontroller)->IsA(AEnemyAIController::StaticClass()))
	{
		formationEnemies[enemyNum]->target = target;
		formationEnemies[enemyNum]->enemycontroller->SetBool(true, FName("EnableTree"));
		formationEnemies[enemyNum]->SetActorRotation(FVector(target->GetActorLocation() - formationEnemies[enemyNum]->GetActorLocation()).Rotation());
		if (count < 3)
		{
			formationEnemies[enemyNum]->enemycontroller->SetBool(false, FName("GuardKey"));
			formationEnemies[enemyNum]->enemycontroller->SetVector(target->GetActorLocation() + target->GetActorForwardVector() * 200, FName("FrontLoc"));
			formationEnemies[enemyNum]->enemycontroller->SetVector(target->GetActorLocation() + target->GetActorForwardVector() * -200, FName("BacktLoc"));
			formationEnemies[enemyNum]->enemycontroller->SetVector(target->GetActorLocation() + target->GetActorRightVector() *-200, FName("LeftLoc"));
			formationEnemies[enemyNum]->enemycontroller->SetVector(target->GetActorLocation() + target->GetActorRightVector() * 200, FName("RightLoc"));
		}
		else
		{
			formationEnemies[enemyNum]->enemycontroller->SetBool(true, FName("GuardKey"));
			formationEnemies[enemyNum]->enemycontroller->SetVector(GetActorLocation() + GetActorForwardVector() * 100, FName("HomeLocation"));
		}
		count++;
	}

}
void AGeneralEnemy::ChargeFormation()
{
	if (!IsValid(target))
		return;
	 count = 0;
	 TArray<ANetworkPlayer*> targetArray = m_spawn->GetNearbyPlayers();
	 if (targetArray.Num() == 0)
		 return;
	for (int i = 0; i < formationEnemies.Num(); i++)
	{
		if (targetArray.Num() == 1)
		{
			SingleTargetFormation(i);
			continue;
		}
		if (Cast<AOffensiveEnemy>(formationEnemies[i]))
		{
			formationEnemies[i]->target = m_spawn->GetClosestPlayer();
			formationEnemies[i]->MoveToPoint(target->GetActorLocation());
		}
		else
		{
			ANetworkPlayer* newTarget = nullptr;
			for (int j = 0; j < targetArray.Num(); j++)
			{
				if(targetArray[j]==m_spawn->GetClosestPlayer())
					continue;
				newTarget = targetArray[j];
				continue;
			}
			formationEnemies[i]->target = newTarget;
		}
	}
}
void AGeneralEnemy::DefaultFormation()
{
	FVector rotatedFormation;
	for (int i = 0; i < formationEnemies.Num(); i++)
	{
		if (!IsValid(formationEnemies[i]) || !IsValid(m_spawn) || (m_spawn->formationPoints.Num() + 1) < formationEnemies.Num())
		{
			continue;
		}


		formationEnemies[i]->target = target;
		rotatedFormation = GetActorRotation().RotateVector(FVector(m_spawn->formationPoints[i + 1].X - m_spawn->formationPoints[0].X, m_spawn->formationPoints[i + 1].Y - m_spawn->formationPoints[0].Y, 0));

		formationEnemies[i]->MoveToPoint(GetActorLocation() + rotatedFormation);
		formationEnemies[i]->SetActorRotation(FRotator(0, m_spawn->formationRotation[i + 1], 0) + (GetActorRotation()));

		formationEnemies[i]->enemycontroller->SetBool(false, FName("EnableTree"));
		formationEnemies[i]->enemycontroller->SetVector(formationEnemies[i]->GetActorLocation(), FName("HomeLocation"));


	}
}
int AGeneralEnemy::NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore, class UAbilityInfo* ability)
{
	//CHANGEANIMATION(EMinionAnimState::MAS_Pointing);
	ChangeNPCAnimation((uint8)EMinionAnimState::MAS_Pointing);
	return Super::NativeDealDamage(dealer, damage, armorPercentageIgnore, ability);
}
void AGeneralEnemy::NativeOnKilled(class ANetworkCharacter* killer, class UAbilityInfo* ability)
{
	Super::NativeOnKilled(killer, ability);
	if (Role != ROLE_Authority)
		return;
	if (m_spawn &&m_spawn->possesable)
	{
		int32 team = killer->GetTeam();
		m_spawn->CaptureCamp(team);

	}
}
void AGeneralEnemy::IdleFormation(float deltaTime)
{
	// Move to a random point near the spawn point;

	//controll enemies in the formation
	int counter = 0; 
	for (int i = 0; i < formationEnemies.Num(); i++)
	{
		if (!IsValid(formationEnemies[i]) || !IsValid(m_spawn) || (m_spawn->formationPoints.Num() + 1) < formationEnemies.Num())
		{
			continue;
		}

		if (!formationEnemies[i]->m_tempTarget)
		{
			if (Cast<AOffensiveEnemy>(formationEnemies[i])&&counter<4)
			{
				formationEnemies[i]->PatrolBetweenLocations (patrolLocations[counter].RotateAngleAxis( 90, FVector::UpVector)*500+ patrolLocations[counter]* 500 + m_spawn->GetActorLocation(), patrolLocations[counter].RotateAngleAxis( 270, FVector::UpVector) * 500 + patrolLocations[counter] * 500 + m_spawn->GetActorLocation(), deltaTime);
				counter++;
				continue;
			}

			formationEnemies[i]->MoveToPoint(FVector(m_spawn->formationPoints[i + 1],0)+m_spawn->GetActorLocation());
			//formationEnemies[i]->MoveToPointSlow(randpos + m_spawn->GetActorLocation(), 50.0f);


		}
		else
		{
			if(formationEnemies[i]->IsA(AOffensiveEnemy::StaticClass()))
				Cast<AOffensiveEnemy>(formationEnemies[i])->BasicBehavior();
			if(formationEnemies[i]->IsA(ARangedEnemy::StaticClass()))
				Cast<ARangedEnemy>(formationEnemies[i])->BasicBehavior();
		}
		formationEnemies[i]->target = nullptr;
	}
}