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


#include "DDICharacter.h"

// #include "DDIWeapon.h"
#include "Animation/AnimInstance.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "EnhancedInputComponent.h"
#include "InputActionValue.h"
#include "GameFramework/CharacterMovementComponent.h"

DEFINE_LOG_CATEGORY(LogTemplateCharacter);

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

	isPaused = false;

	GetCapsuleComponent()->InitCapsuleSize(55.f, 96.f);

	// Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));

	// Mesh->SetupAttachment(GetMesh());
	GetMesh()->SetOnlyOwnerSee(true);
	GetMesh()->FirstPersonPrimitiveType = EFirstPersonPrimitiveType::FirstPerson;
	GetMesh()->SetupAttachment(GetCapsuleComponent());
	// GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);

	FirstPersonCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("First Person Camera"));
	// FirstPersonCamera->SetupAttachment(FirstPersonMesh, FName("head"));
	FirstPersonCamera->SetupAttachment(GetMesh());
	FirstPersonCamera->SetRelativeLocationAndRotation(FVector(-2.8f, 5.89f, 0.0f), FRotator(0.0f, 90.0f, -90.0f));
	FirstPersonCamera->bUsePawnControlRotation = true;
	FirstPersonCamera->bEnableFirstPersonFieldOfView = true;
	FirstPersonCamera->bEnableFirstPersonScale = true;
	FirstPersonCamera->FirstPersonFieldOfView = 70.0f;
	FirstPersonCamera->FirstPersonScale = 0.6f;

	// GetMesh()->SetOwnerNoSee(true);
	// GetMesh()->FirstPersonPrimitiveType = EFirstPersonPrimitiveType::WorldSpaceRepresentation;

	GetCapsuleComponent()->SetCapsuleSize(34.f, 96.f);

	GetCharacterMovement()->BrakingDecelerationFalling = 1500.f;
	GetCharacterMovement()->AirControl = 0.5f;
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 600.0f, 0.0f);
}
ADDICharacter::~ADDICharacter()
{
	
}

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

	GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, GetController()->GetName());


	// SetupPlayerInputComponent( InputComponent);
}

// Called to bind functionality to input
void ADDICharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))
	{
		// Jumping
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ADDICharacter::DoJumpStart);
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ADDICharacter::DoJumpEnd);

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

		// Looking/Aiming
		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ADDICharacter::LookInput);
		EnhancedInputComponent->BindAction(MouseLookAction, ETriggerEvent::Triggered, this, &ADDICharacter::LookInput);
		
		// Firing
		// EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Started, this, &ADDICharacter::DoStartFiring);
		// EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Completed, this, &ADDICharacter::DoStopFiring);

		// Switch weapon
		// EnhancedInputComponent->BindAction(SwitchWeaponAction, ETriggerEvent::Triggered, this, &ADDICharacter::DoSwitchWeapon);
	GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, "SetupPlayerInputComponent");
	}
	else
	{
		UE_LOG(LogTemplateCharacter, Error, TEXT("'%s' Failed to find an Enhanced Input Component! This template is built to use the Enhanced Input system. If you intend to use the legacy system, then you will need to update this C++ file."), *GetNameSafe(this));
	}
}
float ADDICharacter::TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
	// ignore if already dead
	if (CurrentHP <= 0.0f)
	{
		return 0.0f;
	}

	// Reduce HP
	CurrentHP -= Damage;

	// Have we depleted HP?
	if (CurrentHP <= 0.0f)
	{
		// deactivate the weapon
		// if (IsValid(CurrentWeapon))
		// {
		// 	CurrentWeapon->DeactivateWeapon();
		// }
		

		// reset the bullet counter UI
		// OnBulletCountUpdated.Broadcast(0, 0);

		// destroy this character
		Destroy();
	}

	return Damage;
}

// void ADDICharacter::DoStartFiring()
// {
// 	// fire the current weapon
// 	if (CurrentWeapon)
// 	{
// 		CurrentWeapon->StartFiring();
// 	}
// }

// void ADDICharacter::DoStopFiring()
// {
// 	// stop firing the current weapon
// 	if (CurrentWeapon)
// 	{
// 		CurrentWeapon->StopFiring();
// 	}
// }

// void ADDICharacter::DoSwitchWeapon()
// {
// 	// ensure we have at least two weapons two switch between
// 	if (OwnedWeapons.Num() > 1)
// 	{
// 		// deactivate the old weapon
// 		CurrentWeapon->DeactivateWeapon();
//
// 		// find the index of the current weapon in the owned list
// 		int32 WeaponIndex = OwnedWeapons.Find(CurrentWeapon);
//
// 		// is this the last weapon?
// 		if (WeaponIndex == OwnedWeapons.Num() - 1)
// 		{
// 			// loop back to the beginning of the array
// 			WeaponIndex = 0;
// 		}
// 		else {
// 			// select the next weapon index
// 			++WeaponIndex;
// 		}
//
// 		// set the new weapon as current
// 		CurrentWeapon = OwnedWeapons[WeaponIndex];
//
// 		// activate the new weapon
// 		CurrentWeapon->ActivateWeapon();
// 	}
// }

void ADDICharacter::MoveInput(const FInputActionValue& Value)
{
	// get the Vector2D move axis
	FVector2D MovementVector = Value.Get<FVector2D>();
	// pass the axis values to the move input
	DoMove(MovementVector.X, MovementVector.Y);
}

void ADDICharacter::LookInput(const FInputActionValue& Value)
{
	// get the Vector2D look axis 
	FVector2D LookAxisVector = Value.Get<FVector2D>()*mouseSensitivity; //Added mouseSensitivity

	// pass the axis values to the aim input
	DoAim(LookAxisVector.X, LookAxisVector.Y);

}

void ADDICharacter::DoAim(float Yaw, float Pitch)
{
	if (GetController())
	{
		// pass the rotation inputs
		AddControllerYawInput(Yaw);
		AddControllerPitchInput(Pitch);
	}
}

void ADDICharacter::DoMove(float Right, float Forward)
{
	GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, FString::Printf(TEXT("Right: %f, Forward: %f"), Right, Forward));
	const FRotator CurrentRotation = GetController()->GetControlRotation();
	if (GetController())
	{
		
		GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, "Past controller");
		// pass the move inputs
		AddMovementInput(GetActorRightVector(), Right);
		AddMovementInput(GetActorForwardVector(), Forward);
		
		// AddMovementInput(CurrentRotation.RotateVector(FVector::RightVector), Right);
		// AddMovementInput(CurrentRotation.RotateVector(FVector::ForwardVector), Forward);
	}
}

void ADDICharacter::DoJumpStart()
{
	// pass Jump to the character
	Jump();
}

void ADDICharacter::DoJumpEnd()
{
	// pass StopJumping to the character
	StopJumping();
}

// void ADDICharacter::AttachWeaponMeshes(ADDIWeapon* Weapon)
// {
// 	const FAttachmentTransformRules AttachmentRule(EAttachmentRule::SnapToTarget, false);
//
// 	// attach the weapon actor
// 	Weapon->AttachToActor(this, AttachmentRule);
//
// 	// attach the weapon meshes
// 	Weapon->GetFirstPersonMesh()->AttachToComponent(GetFirstPersonMesh(), AttachmentRule, FirstPersonWeaponSocket);
// 	Weapon->GetThirdPersonMesh()->AttachToComponent(GetMesh(), AttachmentRule, FirstPersonWeaponSocket);
// 	
// }

// void ADDICharacter::PlayFiringMontage(UAnimMontage* Montage)
// {
// 	
// }

// void ADDICharacter::AddWeaponRecoil(float Recoil)
// {
// 	// apply the recoil as pitch input
// 	AddControllerPitchInput(Recoil);
// }

// void ADDICharacter::UpdateWeaponHUD(int32 CurrentAmmo, int32 MagazineSize)
// {
// 	OnBulletCountUpdated.Broadcast(MagazineSize, CurrentAmmo);
// }

// FVector ADDICharacter::GetWeaponTargetLocation()
// {
// 	// trace ahead from the camera viewpoint
// 	FHitResult OutHit;
//
// 	const FVector Start = GetFirstPersonCameraComponent()->GetComponentLocation();
// 	const FVector End = Start + (GetFirstPersonCameraComponent()->GetForwardVector() * MaxAimDistance);
//
// 	FCollisionQueryParams QueryParams;
// 	QueryParams.AddIgnoredActor(this);
//
// 	GetWorld()->LineTraceSingleByChannel(OutHit, Start, End, ECC_Visibility, QueryParams);
//
// 	// return either the impact point or the trace end
// 	return OutHit.bBlockingHit ? OutHit.ImpactPoint : OutHit.TraceEnd;
// }

// void ADDICharacter::AddWeaponClass(const TSubclassOf<ADDIWeapon>& WeaponClass)
// {
// 	// do we already own this weapon?
// 	ADDIWeapon* OwnedWeapon = FindWeaponOfType(WeaponClass);
//
// 	if (!OwnedWeapon)
// 	{
// 		// spawn the new weapon
// 		FActorSpawnParameters SpawnParams;
// 		SpawnParams.Owner = this;
// 		SpawnParams.Instigator = this;
// 		SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
// 		SpawnParams.TransformScaleMethod = ESpawnActorScaleMethod::MultiplyWithRoot;
//
// 		ADDIWeapon* AddedWeapon = GetWorld()->SpawnActor<ADDIWeapon>(WeaponClass, GetActorTransform(), SpawnParams);
//
// 		if (AddedWeapon)
// 		{
// 			// add the weapon to the owned list
// 			OwnedWeapons.Add(AddedWeapon);
//
// 			// if we have an existing weapon, deactivate it
// 			if (CurrentWeapon)
// 			{
// 				CurrentWeapon->DeactivateWeapon();
// 			}
//
// 			// switch to the new weapon
// 			CurrentWeapon = AddedWeapon;
// 			CurrentWeapon->ActivateWeapon();
// 		}
// 	}
// }

// void ADDICharacter::OnWeaponActivated(ADDIWeapon* Weapon)
// {
// 	// update the bullet counter
// 	OnBulletCountUpdated.Broadcast(Weapon->GetMagazineSize(), Weapon->GetMagCount());
//
// 	// set the character mesh AnimInstances
// 	GetFirstPersonMesh()->SetAnimInstanceClass(Weapon->GetFirstPersonAnimInstanceClass());
// 	GetMesh()->SetAnimInstanceClass(Weapon->GetThirdPersonAnimInstanceClass());
// }

// void ADDICharacter::OnWeaponDeactivated(ADDIWeapon* Weapon)
// {
// 	// unused
// }

// void ADDICharacter::OnSemiWeaponRefire()
// {
// 	// unused
// }

// ADDIWeapon* ADDICharacter::FindWeaponOfType(TSubclassOf<ADDIWeapon> WeaponClass) const
// {
// 	// check each owned weapon
// 	for (ADDIWeapon* Weapon : OwnedWeapons)
// 	{
// 		if (Weapon->IsA(WeaponClass))
// 		{
// 			return Weapon;
// 		}
// 	}
//
// 	// weapon not found
// 	return nullptr;
//
// }
