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


#include "PlayerCharacter.h"

#include "EnhancedInputSubsystems.h"
#include "EnhancedInputComponent.h"
#include "DrawDebugHelpers.h"
#include "InputAction.h"
#include "Components/CapsuleComponent.h"


// Sets default values
APlayerCharacter::APlayerCharacter()
{
	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
	CameraComponent->SetupAttachment(GetCapsuleComponent());
	CameraComponent->SetRelativeLocation(FVector(-10.f, 0.f, 80.f)); // Position the camera
	CameraComponent->bUsePawnControlRotation = true;
	
	
	GetCapsuleComponent()->InitCapsuleSize(40.0f, 90.0f);
	
	USkeletalMeshComponent* MeshComp = GetMesh();
	check(MeshComp);
	MeshComp->SetRelativeRotation(FRotator(0.0f, -90.0f, 0.0f));
	// Rotate mesh to be X forward since it is exported as Y forward.
	MeshComp->SetRelativeLocation(FVector(0.0f, 0.0f, -90.0f));  
	MeshComp->SetupAttachment(GetCapsuleComponent());
	MeshComp->SetCollisionProfileName(TEXT("Mesh"));
	MeshComp->bCastDynamicShadow = false;
	MeshComp->CastShadow = false;
	
	BaseEyeHeight = 80.0f;
	CrouchedEyeHeight = 50.0f;
}

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

// Called every frame
void APlayerCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	TObjectPtr<UWorld> world = GetWorld();
	if (world != nullptr)
	{
		
		FHitResult HitResult;
		const FVector Start = GetActorLocation();
		const FVector End = GetActorForwardVector() * 100 + Start;
		const FCollisionObjectQueryParams QueryParams(FCollisionObjectQueryParams::AllStaticObjects);
		
		DrawDebugLine(world, Start, End, FColor::Green, false, 1, 0, 1);
		world->LineTraceSingleByObjectType(HitResult, Start, End, QueryParams);

		if (HitResult.bBlockingHit)
		{
			if (GEngine != nullptr)
			{
				GEngine->AddOnScreenDebugMessage(
					-1,
					1.f,
					FColor::Red,
					FString::Printf(TEXT("You are hitting: %s"),
						*HitResult.GetActor()->GetName()
					));
			}
		}
	}
}

#pragma region Inputs


// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	// Get the player controller
	APlayerController* PC = Cast<APlayerController>(GetController());
 
	// Get the local player subsystem
	UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer());
	// Clear out existing mapping, and add our mapping
	Subsystem->ClearAllMappings();
	Subsystem->AddMappingContext(InputMapping, 0);

	// Get the EnhancedInputComponent
	UEnhancedInputComponent* PEI = Cast<UEnhancedInputComponent>(PlayerInputComponent);
	
	// Bind the actions
	PEI->BindAction(IA_Move, ETriggerEvent::Triggered, this, &APlayerCharacter::Move);
	PEI->BindAction(IA_Look, ETriggerEvent::Triggered, this, &APlayerCharacter::Look);
	PEI->BindAction(IA_Jump, ETriggerEvent::Triggered, this, &APlayerCharacter::ActivateJump);

}

void APlayerCharacter::Move(const FInputActionValue& Value)
{
	if (Controller != nullptr)
	{
		const FVector2D MoveValue = Value.Get<FVector2D>();
		const FRotator MovementRotation(0, Controller->GetControlRotation().Yaw, 0);
 
		// Forward/Backward direction
		if (MoveValue.Y != 0.f)
		{
			// Get forward vector
			const FVector Direction = MovementRotation.RotateVector(FVector::ForwardVector);
 
			AddMovementInput(Direction, MoveValue.Y);
		}
 
		// Right/Left direction
		if (MoveValue.X != 0.f)
		{
			// Get right vector
			const FVector Direction = MovementRotation.RotateVector(FVector::RightVector);
 
			AddMovementInput(Direction, MoveValue.X);
		}
	}
}

void APlayerCharacter::Look(const FInputActionValue& Value)
{
	if (Controller != nullptr)
	{
		const FVector2D LookValue = Value.Get<FVector2D>();
 
		if (LookValue.X != 0.f)
		{
			AddControllerYawInput(LookValue.X);
		}
 
		if (LookValue.Y != 0.f)
		{
			AddControllerPitchInput(LookValue.Y);
		}
	}
}

void APlayerCharacter::ActivateJump(const FInputActionValue& Value)
{
	if (Controller != nullptr)
	{
		const bool JumpValue = Value.Get<bool>();
		if (JumpValue)
		{
			Jump();
		}
		else
		{
			StopJumping();
		}
	}
}

#pragma endregion

