// Project Sword & Gun Copyright © 2021 Kevin Poretti


#include "Characters/SNGProtagonist.h"

#include "DrawDebugHelpers.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Kismet/KismetMathLibrary.h"

ASNGProtagonist::ASNGProtagonist()
{
	PrimaryActorTick.bCanEverTick = true;
	
	SpringArmComponent = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComponent"));
	SpringArmComponent->SetupAttachment(RootComponent);
	
	CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
	CameraComponent->SetupAttachment(SpringArmComponent);

	StateMachineComponent = CreateDefaultSubobject<USNGStateMachineComponent>(TEXT("StateMachineComponent"));
}

void ASNGProtagonist::MoveForward(const float Value)
{
	LastForwardAxis = Value;

	// If the protag starts moving when a recovery anim montage is playing we want to cancel out of it
	if(!IsMoveInputIgnored() && !FMath::IsNearlyZero(Value))
	{
		UAnimMontage* CurrMontage = GetMesh()->GetAnimInstance()->GetCurrentActiveMontage();
		if(CurrMontage)
		{
			GetMesh()->GetAnimInstance()->Montage_Stop(0.1f, CurrMontage);
		}
	}
	
	FRotator ViewRotation = GetController()->GetControlRotation();
	FRotator ViewRotationYaw(0.0f, ViewRotation.Yaw, 0.0f);
	AddMovementInput(UKismetMathLibrary::GetForwardVector(ViewRotationYaw), Value);
}

void ASNGProtagonist::MoveRight(const float Value)
{
	LastRightAxis = Value;

	// If the protag starts moving when a recovery anim montage is playing we want to cancel out of it
	if(!IsMoveInputIgnored() && !FMath::IsNearlyZero(Value))
	{
		UAnimMontage* CurrMontage = GetMesh()->GetAnimInstance()->GetCurrentActiveMontage();
		if(CurrMontage)
		{
			GetMesh()->GetAnimInstance()->Montage_Stop(0.1f, CurrMontage);
		}
	}
	
	FRotator ViewRotation = GetController()->GetControlRotation();
	FRotator ViewRotationYaw(0.0f, ViewRotation.Yaw, 0.0f);
	AddMovementInput(UKismetMathLibrary::GetRightVector(ViewRotationYaw), Value);
}

void ASNGProtagonist::DoJump()
{
	UAnimMontage* CurrMontage = GetMesh()->GetAnimInstance()->GetCurrentActiveMontage();
	if(CurrMontage)
	{
		GetMesh()->GetAnimInstance()->Montage_Stop(0.1f, CurrMontage);
	}
	
	Jump();
}

float ASNGProtagonist::Dash()
{
	float AnimationDuration = 0.0f;
	
	FVector InputDirection = GetInputAsWorldDirection();
	// is there is no movement input then roll forward, otherwise roll in the movement input direction 
	if(!InputDirection.IsNearlyZero())
	{
		SetActorRotation(UKismetMathLibrary::MakeRotFromX(InputDirection));
	}			

	if(DashMontage)
	{
		AnimationDuration = PlayAnimMontage(DashMontage);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("SNGProtagonist :: No dash animation montage set for character"));
	}

	SetIgnoreMovementInput(true);
	
	return AnimationDuration;
}

float ASNGProtagonist::MeleeAttack(FMeleeAttackData MeleeAttackData)
{
	float AnimationDuration = 0.0f;

	// probably want to do an assert here instead??
	if(MeleeAttackData.AttackMontage)
	{
		AnimationDuration = PlayAnimMontage(MeleeAttackData.AttackMontage);

		SetIgnoreMovementInput(true);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("SNGProtagonist :: No attack animation montage set for character"));
	}
	
	return AnimationDuration;
}

bool ASNGProtagonist::PushEvent_Implementation(FSNGEvent Event)
{
	if(StateMachineComponent)
	{
		return StateMachineComponent->PushEvent(Event);
	}
	return false;
}

FVector ASNGProtagonist::GetInputAsWorldDirection()
{
	AController* MyController = GetController();
	if(MyController == nullptr)
	{
		return FVector::ZeroVector;
	}
	
	FRotator ViewRotation = MyController->GetControlRotation();
	FRotator ViewRotationYaw(0.0f, ViewRotation.Yaw, 0.0f);

	float MoveForwardAxisValue = GetInputAxisValue("MoveForward");
	FVector ForwardInput = UKismetMathLibrary::GetForwardVector(ViewRotationYaw) * MoveForwardAxisValue;

	float MoveRightAxisValue = GetInputAxisValue("MoveRight"); 
	FVector RightInput = UKismetMathLibrary::GetRightVector(ViewRotationYaw) * MoveRightAxisValue;

	return ForwardInput + RightInput;
}

FVector ASNGProtagonist::GetInputAsWorldDirection(float ForwardAxisValue, float RightAxisValue)
{
	AController* MyController = GetController();
	if(MyController == nullptr)
	{
		return FVector::ZeroVector;
	}
	
	FRotator ViewRotation = MyController->GetControlRotation();
	FRotator ViewRotationYaw(0.0f, ViewRotation.Yaw, 0.0f);
	
	FVector ForwardInput = UKismetMathLibrary::GetForwardVector(ViewRotationYaw) * ForwardAxisValue;

	FVector RightInput = UKismetMathLibrary::GetRightVector(ViewRotationYaw) * RightAxisValue;

	return ForwardInput + RightInput;
}

void ASNGProtagonist::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);
	
	FVector ActorLocation = GetActorLocation();
	FVector ActorForward = UKismetMathLibrary::GetForwardVector(GetActorRotation());
	DrawDebugDirectionalArrow(GetWorld(), ActorLocation, ActorLocation + (ActorForward * 100.0f),
		10.0f, FColor::Cyan, false, -1.0f, 0, 2.0f);

	FVector InputDirection = GetInputAsWorldDirection(LastForwardAxis, LastRightAxis);
	InputDirection.Normalize();
	DrawDebugDirectionalArrow(GetWorld(), ActorLocation, ActorLocation + (InputDirection * 100.0f),
    10.0f, FColor::Magenta, false, -1.0f, 0, 2.0f);
}
