// Copyright CodeSpartan, 2022. All rights reserved.

#include "PlayerControllerCpp.h"
#include "CollisionQueryParams.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/HUD.h"
#include "Engine/LocalPlayer.h"
#include "Engine/GameViewportClient.h"
#include "Engine/World.h"
#include "Engine/Engine.h"
#include "UnrealClient.h"

APlayerControllerCpp::APlayerControllerCpp(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

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

	GEngine->GameViewport->Viewport->ViewportResizedEvent.AddWeakLambda(
		this,
		[this](FViewport* ViewPort, uint32 val)
		{
			ViewportResizeEvent.Broadcast();
		}
	);
}

void APlayerControllerCpp::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);
}

bool APlayerControllerCpp::GetHitResultUnderCursorForObjectsWithIgnore(const TArray<TEnumAsByte<EObjectTypeQuery> >& ObjectTypes, bool bTraceComplex, const TArray<AActor*>& InIgnoreActors, FHitResult& HitResult) const
{
	ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player);
	bool bHit = false;
	if (LocalPlayer && LocalPlayer->ViewportClient)
	{
		FVector2D MousePosition;
		if (LocalPlayer->ViewportClient->GetMousePosition(MousePosition))
		{
			bHit = GetHitResultAtScreenPositionWithIgnore(MousePosition, ObjectTypes, bTraceComplex, InIgnoreActors, HitResult);
		}
	}

	if (!bHit)	//If there was no hit we reset the results. This is redundant but helps Blueprint users
	{
		HitResult = FHitResult();
	}

	return bHit;
}

bool APlayerControllerCpp::GetHitResultAtScreenPositionWithIgnore(const FVector2D ScreenPosition, const TArray<TEnumAsByte<EObjectTypeQuery> >& ObjectTypes, bool bTraceComplex, const TArray<AActor*>& InIgnoreActors, FHitResult& HitResult) const
{
	// Early out if we clicked on a HUD hitbox
	if (GetHUD() != nullptr && GetHUD()->GetHitBoxAtCoordinates(ScreenPosition, true))
	{
		return false;
	}

	FVector WorldOrigin;
	FVector WorldDirection;
	if (UGameplayStatics::DeprojectScreenToWorld(this, ScreenPosition, WorldOrigin, WorldDirection) == true)
	{
		FCollisionObjectQueryParams const ObjParam(ObjectTypes);
		FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(ClickableTrace), bTraceComplex);
		QueryParams.AddIgnoredActors(InIgnoreActors);
		return GetWorld()->LineTraceSingleByObjectType(HitResult, WorldOrigin, WorldOrigin + WorldDirection * HitResultTraceDistance, ObjParam, QueryParams);
	}

	return false;
}