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


#include "OverloadModule.h"

#include "Components/SphereComponent.h"
#include "GameFramework/Character.h"

void AOverloadModule::BeginPlay()
{
	Super::BeginPlay();
	
	this->SetActorTickInterval(0.2);
	PlayerChar = GetWorld()->GetFirstPlayerController()->GetCharacter();
	PlayerCam = Cast<UCameraComponent>(PlayerChar->GetComponentByClass(UCameraComponent::StaticClass()));
}


void AOverloadModule::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);

	if (GadgetCantBeUsed()) return;
	CheckForPotentialHackTarget();
}

void AOverloadModule::CheckForPotentialHackTarget()
{
	FHitResult OutHit;
	FVector LT_Start = PlayerCam->GetComponentLocation();
	FVector LT_End = PlayerCam->GetComponentLocation() + (PlayerCam->GetForwardVector() * DeadBodyCheckDistance);

	//DrawDebugLine(GetWorld(), LT_Start, LT_End, FColor::Red, false, 0.2, 0, 1);

	FCollisionQueryParams QueryParams = FCollisionQueryParams::DefaultQueryParam;
	QueryParams.AddIgnoredActor(PlayerChar);
	if (!GetWorld()->LineTraceSingleByChannel(OutHit, LT_Start, LT_End, ECC_Camera, QueryParams) || !(OutHit.GetActor()->ActorHasTag(FName("Enemy")) && OutHit.GetActor()->ActorHasTag(FName("Dead"))))
	{
		PotentialHackTarget = nullptr;
		DisplayNeedADeadEnemy();
		return;
	}

	if (HackedEnemies.Contains(OutHit.GetActor()->GetUniqueID()))
	{
		PotentialHackTarget = nullptr;
		DisplayAlreadyHacked();
		return;
	}
	
	//DrawDebugLine(GetWorld(), LT_Start, OutHit.ImpactPoint, FColor::Green, false, 0.2, 0, 1);
	PotentialHackTarget = OutHit.GetActor();
	DisplayFoundPotentialTarget();
}


void AOverloadModule::Activate()
{
	if (GadgetCantBeUsed() || !IsValid(PotentialHackTarget)) return;
	
	Super::Activate();
	HackedEnemies.Add(PotentialHackTarget->GetUniqueID());
	ExplodeClosestAliveEnemy();
	PlayHackingAnim(GadgetMaxUptime);
}

void AOverloadModule::FinishedUsing()
{
	IsValid(ClosestEnemy) ? DisplayHackingSuccess() : DisplayHackingFailure();	
	SpawnExplosiveOnActor(ClosestEnemy);
	Super::FinishedUsing();
	PlayRechargingAnim(CooldownTime);
}

void AOverloadModule::ExplodeClosestAliveEnemy()
{
	FTransform EmptyTransform;
	USphereComponent* SphereCollision = Cast<USphereComponent>(AddComponentByClass(USphereComponent::StaticClass(), false, EmptyTransform, false));
	
	SphereCollision->SetSphereRadius(AreaOfEffectInMeters * 100, true);

	TArray<AActor*> OverlappingActors;
	TArray<AActor*> EnemiesInRadius;

	// Find all living enemies within the radius
	SphereCollision->GetOverlappingActors(OverlappingActors, ACharacter::StaticClass());
	for (AActor* OverlappingActor : OverlappingActors)
	{
		if (OverlappingActor->ActorHasTag(FName("Enemy")) && !OverlappingActor->ActorHasTag(FName("Dead"))) EnemiesInRadius.Add(OverlappingActor);
	}

	if (EnemiesInRadius.IsEmpty())
	{
		ClosestEnemy = nullptr;
		SphereCollision->DestroyComponent();
		return;
	}

	// Find the closest Enemy in radius
	ClosestEnemy = EnemiesInRadius[0];
	float Dist = FVector::Distance(PlayerChar->GetActorLocation(), ClosestEnemy->GetActorLocation());
	if (EnemiesInRadius.Num() < 2)
	{
		SphereCollision->DestroyComponent();
		return;
	}
	
	for (int i = 1; i < EnemiesInRadius.Num(); i++)
	{
		float ConsideredDist = FVector::Distance(PlayerChar->GetActorLocation(), EnemiesInRadius[i]->GetActorLocation());
		if (ConsideredDist <= Dist)
		{
			ClosestEnemy = EnemiesInRadius[i];
			Dist = ConsideredDist;
		}
	}
	
	SphereCollision->DestroyComponent();
	
}

void AOverloadModule::SpawnExplosiveOnActor(AActor* ActortoExplode)
{
	if (!IsValid(ActortoExplode)) return; 
	FActorSpawnParameters SpawnParams;
	SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
	GetWorld()->SpawnActor<AActor>(Explosive, ActortoExplode->GetActorLocation(), ActortoExplode->GetActorRotation(), SpawnParams);
}

