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

#include "Lane.h"

// Engine headers.
#include "Components/BoxComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Kismet/GameplayStatics.h"

// Custom game headers.
#include "../GameJamTemplate.h"
#include "../Spawners/TargetSpawner.h"
#include "../Utility/VectorLibrary.h"
#include "Target.h"

ALane::ALane():
	ObjectName(GetName())
{
	PrimaryActorTick.bCanEverTick = true;

	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));

	LeftMarker = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("LeftMarker"));
	LeftMarker->SetupAttachment(RootComponent);

	RightMarker = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("RightMarker"));
	RightMarker->SetupAttachment(RootComponent);

	KillBox = CreateDefaultSubobject<UBoxComponent>(TEXT("KillBox"));
	KillBox->SetupAttachment(RootComponent);

	TargetSpawner = nullptr;
	LaneID = 0;
	bLeftToRight = true;
}

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

	LeftMarkerLocation = LeftMarker->GetComponentLocation();
	RightMarkerLocation = RightMarker->GetComponentLocation();

	KillBox->OnComponentBeginOverlap.AddDynamic(this, &ALane::OnKillBoxBeginOverlap);
	KillBox->SetWorldLocation(LeftMarkerLocation);
}

void ALane::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

int ALane::GetLaneID()
{
	return LaneID;
}

void ALane::SetTargetSpawner(class ATargetSpawner* NewTargetSpawner)
{
	TargetSpawner = NewTargetSpawner;
}

void ALane::SetSpawningDirection(bool bNewLeftToRight)
{
	bLeftToRight = bNewLeftToRight;
	KillBox->SetWorldLocation(bLeftToRight ? RightMarkerLocation : LeftMarkerLocation);
}

void ALane::Spawn(uint8 Heads, uint8 Tails, float MovementSpeed)
{
	UWorld* World = GetWorld();

	if (World != nullptr)
	{
		ATarget* NewTarget = World->SpawnActorDeferred<ATarget>(TargetUClass, GetActorTransform());

		if (NewTarget == nullptr)
		{
			UE_LOG(LogGameJam, Error,
				TEXT("[%s] Error trying to spawn a new target actor."),
				*ObjectName);
			return;
		}

		// Determine the direction the target should be moving in.
		FVector MovementDirection = UVectorLibrary::GetDeltaVector(LeftMarkerLocation, RightMarkerLocation);
		MovementDirection *= bLeftToRight ? 1.0f : -1.0f;

		// Set the target's parameters.
		NewTarget->SetTargetSpawner(TargetSpawner);
		NewTarget->SetLane(this);
		NewTarget->SetFaces((EFaceType)Heads, (EFaceType)Tails);
		NewTarget->SetMovementParameters(MovementSpeed, MovementDirection);

		// Set the target's initial world space location.
		FTransform NewTransform = GetActorTransform();
		NewTransform.SetLocation(bLeftToRight ? LeftMarkerLocation : RightMarkerLocation);

		// Finish spawning the target.
		UGameplayStatics::FinishSpawningActor(NewTarget, NewTransform);
		Targets.Add(NewTarget);

		UE_LOG(LogGameJam, Verbose,
			TEXT("[%s] Spawned target: '%s'."),
			*ObjectName,
			*(NewTarget->GetName()));
	}
}

void ALane::Remove(ATarget* Target)
{
	Targets.Remove(Target);
}

void ALane::Empty()
{
	for (auto& Target : Targets)
	{
		Target->Destroy();
	}

	Targets.Empty();
}

void ALane::FindTargets(TArray<ATarget*>* TargetsInRange, FVector CenterOfBlast, float BlastRadius)
{
	if (TargetsInRange == nullptr)
	{
		return;
	}

	for (auto& Target : Targets)
	{
		FVector TargetLocation = Target->GetActorLocation();
		FVector DeltaVector = CenterOfBlast - TargetLocation;

		if (DeltaVector.Size() <= BlastRadius)
		{
			TargetsInRange->Add(Target);
		}
	}
}

void ALane::OnKillBoxBeginOverlap(
	class UPrimitiveComponent* HitComp,
	class AActor* OtherActor,
	class UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex,
	bool bFromSweep,
	const FHitResult& Hit)
{
	ATarget* Target = Cast<ATarget>(OtherActor);

	if (Target != nullptr)
	{
		// Targets.Remove(Target);
		// Target->Destroy();
	}
}
