// Copyright Epic Games, Inc. All Rights Reserved.

#include "CorruptedMemoryCharacter.h"

#include "CMGameInstance.h"
#include "CM_GameState.h"
#include "CorruptedMemoryProjectile.h"
#include "Animation/AnimInstance.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"


//////////////////////////////////////////////////////////////////////////
// ACorruptedMemoryCharacter

ACorruptedMemoryCharacter::ACorruptedMemoryCharacter()
{
	// Character doesnt have a rifle at start
	bHasRifle = false;

	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(55.f, 96.0f);

	// Create a CameraComponent	
	FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
	FirstPersonCameraComponent->SetupAttachment(GetCapsuleComponent());
	FirstPersonCameraComponent->SetRelativeLocation(FVector(-10.f, 0.f, 60.f)); // Position the camera
	FirstPersonCameraComponent->bUsePawnControlRotation = true;

	// Create a mesh component that will be used when being viewed from a '1st person' view (when controlling this pawn)
	Mesh1P = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("CharacterMesh1P"));
	Mesh1P->SetOnlyOwnerSee(true);
	Mesh1P->SetupAttachment(FirstPersonCameraComponent);
	Mesh1P->bCastDynamicShadow = false;
	Mesh1P->CastShadow = false;
	//Mesh1P->SetRelativeRotation(FRotator(0.9f, -19.19f, 5.2f));
	Mesh1P->SetRelativeLocation(FVector(-30.f, 0.f, -150.f));
}

void ACorruptedMemoryCharacter::BeginPlay()
{
	// Call the base class  
	Super::BeginPlay();

	//Add Input Mapping Context
	if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			Subsystem->AddMappingContext(DefaultMappingContext, 0);
		}
	}

	if (GetWorld()->GetAuthGameMode()) return;
	if (!IsValid(GetPlayerState<ACM_PlayerState>())) return;
	if (GetPlayerState<ACM_PlayerState>()->bServerRequestUserInformation)
	{
		GetPlayerState<ACM_PlayerState>()->bServerRequestUserInformation = false;
		const UCMGameInstance* GameInstance = Cast<UCMGameInstance>(GetWorld()->GetGameInstance());
		ServerPlayerJoin(GameInstance->AccountUsername, GameInstance->PlayerIndex, GetPlayerState<ACM_PlayerState>()->GetUniqueId());
	}
}

//////////////////////////////////////////////////////////////////////////// Input

void ACorruptedMemoryCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	// Set up action bindings
	if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
	{
		//Jumping
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);

		//Moving
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ACorruptedMemoryCharacter::Move);

		//Looking
		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ACorruptedMemoryCharacter::Look);
	}
}


void ACorruptedMemoryCharacter::LogServerMessage_Implementation(const FString& Message)
{
	if (GetWorld()->GetAuthGameMode()) return;
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, Message);
}

void ACorruptedMemoryCharacter::Move(const FInputActionValue& Value)
{
	// input is a Vector2D
	FVector2D MovementVector = Value.Get<FVector2D>();

	if (Controller != nullptr)
	{
		// add movement 
		AddMovementInput(GetActorForwardVector(), MovementVector.Y);
		AddMovementInput(GetActorRightVector(), MovementVector.X);
	}
}

void ACorruptedMemoryCharacter::Look(const FInputActionValue& Value)
{
	// input is a Vector2D
	FVector2D LookAxisVector = Value.Get<FVector2D>();

	if (Controller != nullptr)
	{
		// add yaw and pitch input to controller
		AddControllerYawInput(LookAxisVector.X);
		AddControllerPitchInput(LookAxisVector.Y);
	}
}

void ACorruptedMemoryCharacter::SetHasRifle(bool bNewHasRifle)
{
	bHasRifle = bNewHasRifle;
}

bool ACorruptedMemoryCharacter::GetHasRifle()
{
	return bHasRifle;
}

void ACorruptedMemoryCharacter::ServerPlayerJoin_Implementation(const FString& PlayerName, const int32& PlayerIndex, const FUniqueNetIdRepl& UNetID)
{
	if (!GetWorld()->GetAuthGameMode()) return;
	if (const auto PlayerStateObjPtr = Cast<ACM_GameState>(GetWorld()->GetGameState())->PlayerArray.FindByPredicate([&](const APlayerState* Player)
	{
		return Player->GetUniqueId() == UNetID;
	}))
	{
		PlayerStateObjPtr->Get()->SetPlayerName(PlayerName);
		PlayerStateObjPtr->Get()->SetPlayerId(PlayerIndex);
	}
}
