// Fill out your copyright notice in the Description page of Project Settings.


#include "AI_EnemyController.h"

#include "EnemyCharacter.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "EndlessVendetta/EndlessVendettaCharacter.h"
#include "Perception/AIPerceptionComponent.h"
#include "Perception/AISenseConfig_Hearing.h"
#include "Perception/AISenseConfig_Sight.h"


// Sets default values
AAI_EnemyController::AAI_EnemyController(FObjectInitializer const& ObjectInitializer)
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	AAIController::SetGenericTeamId(FGenericTeamId(1));
	SetupPerceptionSystem();
}

// Called when the game starts or when spawned
void AAI_EnemyController::BeginPlay()
{
	Super::BeginPlay();
}

void AAI_EnemyController::OnPossess(APawn* InPawn)
{
	Super::OnPossess(InPawn);
	if (const AEnemyCharacter* EnemyCharacter = Cast<AEnemyCharacter>(InPawn))
	{
		if (UBehaviorTree* const BehaviorTree = EnemyCharacter->GetBehaviorTree())
		{
			UBlackboardComponent* TempBlackboardPtr;
			UseBlackboard(BehaviorTree->BlackboardAsset, TempBlackboardPtr);
			Blackboard = TempBlackboardPtr;
			if (IsValid(EnemyCharacter->GetPatrolPath()))
			{
				Blackboard->SetValueAsBool("IsPatroling", true);
			}
			else
			{
				Blackboard->SetValueAsBool("IsPatroling", false);
			}
			RunBehaviorTree(BehaviorTree);
		}
	}
}

// Called every frame
void AAI_EnemyController::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	if (GetBlackboardComponent()->GetValueAsBool("CanSeePlayer"))
	{
		GetBlackboardComponent()->SetValueAsVector("TargetLocation", GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation());
	}
}

void AAI_EnemyController::AssignPatrolPathLate()
{
	Blackboard->SetValueAsBool("IsPatroling", true);
}


void AAI_EnemyController::SetupPerceptionSystem()
{
	SightConfig = CreateDefaultSubobject<UAISenseConfig_Sight>(TEXT("Sight Config"));
	SightConfig->SightRadius = 2000.0f;
	SightConfig->LoseSightRadius = 2100.0f;
	SightConfig->PeripheralVisionAngleDegrees = 70.0f;
	SightConfig->SetMaxAge(20.0f);
	SightConfig->AutoSuccessRangeFromLastSeenLocation = 520.0f;
	SightConfig->DetectionByAffiliation.bDetectEnemies = true;
	SightConfig->DetectionByAffiliation.bDetectFriendlies = true;
	SightConfig->DetectionByAffiliation.bDetectNeutrals = true;

	HearingConfig = CreateDefaultSubobject<UAISenseConfig_Hearing>(TEXT("Hearing Config"));
	HearingConfig->HearingRange = 2000.0f;
	HearingConfig->DetectionByAffiliation.bDetectEnemies = true;
	HearingConfig->DetectionByAffiliation.bDetectFriendlies = true;
	HearingConfig->DetectionByAffiliation.bDetectNeutrals = true;

	if (!IsValid(SightConfig)) return;
	if (!IsValid(HearingConfig)) return;

	SetPerceptionComponent(*CreateDefaultSubobject<UAIPerceptionComponent>(TEXT("Perception Component")));
	GetPerceptionComponent()->SetDominantSense(*SightConfig->GetSenseImplementation());
	GetPerceptionComponent()->OnTargetPerceptionUpdated.AddDynamic(this, &AAI_EnemyController::OnTargetPerceptionUpdated);
	GetPerceptionComponent()->ConfigureSense(*SightConfig);
	GetPerceptionComponent()->ConfigureSense(*HearingConfig);
}

void AAI_EnemyController::OnTargetPerceptionUpdated(AActor* Actor, FAIStimulus const Stimulus)
{
	if (AEndlessVendettaCharacter* const PlayerCharacter = Cast<AEndlessVendettaCharacter>(Actor))
	{
		if (Stimulus.WasSuccessfullySensed() && Stimulus.Type == SightConfig->GetSenseID())
		{
			GetBlackboardComponent()->SetValueAsObject("TargetPlayer", Actor);
			GetBlackboardComponent()->SetValueAsVector("TargetLocation", Stimulus.StimulusLocation);
			GetBlackboardComponent()->SetValueAsBool("CanSeePlayer", true);
		}
		else if (!Stimulus.WasSuccessfullySensed() && Stimulus.Type == SightConfig->GetSenseID())
		{
			GetBlackboardComponent()->ClearValue("TargetActor");
			GetBlackboardComponent()->ClearValue("TargetLocation");
			GetBlackboardComponent()->SetValueAsBool("CanSeePlayer", false);
		}

		if (Stimulus.WasSuccessfullySensed() && Stimulus.Type == HearingConfig->GetSenseID())
		{
			GetBlackboardComponent()->SetValueAsObject("TargetPlayer", Actor);
			GetBlackboardComponent()->SetValueAsVector("InvestigationLocation", Stimulus.StimulusLocation);
			GetBlackboardComponent()->SetValueAsBool("IsInvestigating", true);
		}
	}
}
