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


#include "DefaultPlayerCharacter.h"
#include "DefaultPlayerState.h"
#include "../DefaultAIController.h"
#include "Engine/DamageEvents.h"
#include "Kismet/GameplayStatics.h"
#include "Components/CapsuleComponent.h"

ADefaultPlayerCharacter::ADefaultPlayerCharacter()
{
	// 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;
	SetCanBeDamaged(true);
	bUseControllerRotationYaw = false;

	AIControllerClass = ADefaultAIController::StaticClass();
	AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;

	CameraSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
	CameraSpringArm->SetRelativeLocationAndRotation(FVector(0.0f, 0.0f, 0.0f), FRotator(-45.0f, 0.0f, 0.0f));
	CameraSpringArm->SetAbsolute(false, true, true);
	CameraSpringArm->TargetArmLength = 2000.f;
	CameraSpringArm->bEnableCameraLag = true;
	CameraSpringArm->bDoCollisionTest = false;
	CameraSpringArm->CameraLagSpeed = 3.0f;
	CameraSpringArm->SetupAttachment(RootComponent);

	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
	Camera->SetupAttachment(CameraSpringArm, USpringArmComponent::SocketName);
	
	for (uint8 i = 0; i < (uint8)EStats::SIZE; i++)
		DefaultStats.Add((EStats)i, 0.0f);

	for (uint8 i = 0; i < (uint8)CooldownType::SIZE; i++)
		CooldownDuration.Add((CooldownType)i, 0.0f);
}

void ADefaultPlayerCharacter::Tick(float DeltaTime)
{
	/*
	if (GetPlayerState<ADefaultPlayerState>())
	{
		if (!GPlayInEditorID)
		{
			UE_LOG(LogTemp, Warning, TEXT("Server %s State : %d"), *GetName(), GetPlayerState<ADefaultPlayerState>()->GetState());
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("Client %d %s State : %d"), GPlayInEditorID, *GetName(), GetPlayerState<ADefaultPlayerState>()->GetState());
		}
	}
	*/
}

void ADefaultPlayerCharacter::Attack_Implementation()
{
	Client_Attack();
	BP_Attack();
}

void ADefaultPlayerCharacter::Client_Attack_Implementation()
{
	BP_Attack();
}

float ADefaultPlayerCharacter::TakeDamage_Implementation(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser)
{
	float ReturnValue = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);

	ADefaultPlayerState* State = GetPlayerState<ADefaultPlayerState>();
	if (!State) return ReturnValue;

	if (!Cast<APawn>(DamageCauser)) return ReturnValue;

	ADefaultPlayerState* AttackerState = Cast<APawn>(DamageCauser)->GetPlayerState<ADefaultPlayerState>();
	if (!AttackerState) return ReturnValue;

	float ADDamageMultiplier = 0;
	float APDamageMultiplier = 0;

	if (State->Stats[(uint8)EStats::Armor] >= 0)
		ADDamageMultiplier = 100 / (100 + State->Stats[(uint8)EStats::Armor]);
	else
		ADDamageMultiplier = 2 - 100 / (100 - State->Stats[(uint8)EStats::Armor]);

	if (State->Stats[(uint8)EStats::MagicResistance] >= 0)
		APDamageMultiplier = 100 / (100 + State->Stats[(uint8)EStats::MagicResistance]);
	else
		APDamageMultiplier = 2 - 100 / (100 - State->Stats[(uint8)EStats::MagicResistance]);


	UE_LOG(LogTemp, Warning, TEXT("%s : ADDamageMultiplier : %f CalculatedDamage : %f"), *DamageCauser->GetName(), ADDamageMultiplier, DamageAmount * ADDamageMultiplier);
	UE_LOG(LogTemp, Warning, TEXT("%s : APDamageMultiplier : %f CalculatedDamage : %f"), *DamageCauser->GetName(), APDamageMultiplier, DamageAmount * APDamageMultiplier);

	float UpdatedHealth = 0;

	if (Cast<UBaseAttack>(DamageEvent.DamageTypeClass->GetDefaultObject()))
	{
		UE_LOG(LogTemp, Warning, TEXT("DamageType : BaseAttack")); 

		UpdatedHealth = State->Stats[(uint8)EStats::Health] - AttackerState->Stats[(uint8)EStats::AttackDamage] * ADDamageMultiplier;
	}
	else if (Cast<UAPDamage>(DamageEvent.DamageTypeClass->GetDefaultObject()))
	{
		UE_LOG(LogTemp, Warning, TEXT("DamageType : APDamage"));

		UpdatedHealth = State->Stats[(uint8)EStats::Health] - AttackerState->Stats[(uint8)EStats::AbilityPower] * APDamageMultiplier;
	}

	if (UpdatedHealth < 0 || UpdatedHealth < 0.1 )
	{
		State->Stats[(uint8)EStats::Health] = 0;
		Server_PerformDead();
		Client_PerformDead();
	}
	else
	{
		State->Stats[(uint8)EStats::Health] = UpdatedHealth;
	}

	UE_LOG(LogTemp, Warning, TEXT("Current Health : %f"), State->Stats[(uint8)EStats::Health]);

	return ReturnValue;
}

void ADefaultPlayerCharacter::Skill1_Implementation()
{
	NetMulticast_Skill1();
}

void ADefaultPlayerCharacter::NetMulticast_Skill1_Implementation()
{
	BP_Skill1();
}

void ADefaultPlayerCharacter::Skill2_Implementation()
{
	NetMulticast_Skill2();
}

void ADefaultPlayerCharacter::NetMulticast_Skill2_Implementation()
{
	BP_Skill2();
}

void ADefaultPlayerCharacter::Skill3_Implementation()
{
	NetMulticast_Skill3();
}

void ADefaultPlayerCharacter::NetMulticast_Skill3_Implementation()
{
	BP_Skill3();
}

void ADefaultPlayerCharacter::Skill4_Implementation()
{
	NetMulticast_Skill4();
}

void ADefaultPlayerCharacter::NetMulticast_Skill4_Implementation()
{
	BP_Skill4();
}

void ADefaultPlayerCharacter::Skill4_End_Implementation()
{
	NetMulticast_Skill4_End();
}

void ADefaultPlayerCharacter::NetMulticast_Skill4_End_Implementation()
{
	BP_Skill4_End();
}

void ADefaultPlayerCharacter::Skill5_Implementation()
{
	NetMulticast_Skill5();
}

void ADefaultPlayerCharacter::NetMulticast_Skill5_Implementation()
{
	BP_Skill5();
}

void ADefaultPlayerCharacter::Skill6_Implementation()
{
	NetMulticast_Skill6();
}

void ADefaultPlayerCharacter::NetMulticast_Skill6_Implementation()
{
	BP_Skill6();
}

void ADefaultPlayerCharacter::Skill7_Implementation()
{
	NetMulticast_Skill7();
}

void ADefaultPlayerCharacter::NetMulticast_Skill7_Implementation()
{
	BP_Skill7();
}

void ADefaultPlayerCharacter::PerformDead()
{
	ADefaultPlayerState* State = GetPlayerState<ADefaultPlayerState>();
	if (!State) return;

	State->SetState(ECharacterState::Dead);
	GetCapsuleComponent()->SetGenerateOverlapEvents(false);
	GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}

void ADefaultPlayerCharacter::Server_PerformDead_Implementation()
{
	PerformDead();
}

void ADefaultPlayerCharacter::Client_PerformDead_Implementation()
{
	PerformDead();
}
