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


#include "TurnBaseCombatV2.h"
#include "CoreMinimal.h"
#include "AIController.h"
#include "StatusSystem.h"
#include "Blueprint/UserWidget.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Components/TextBlock.h"
#include "Components/ProgressBar.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "Misc/OutputDeviceNull.h"
#include "the_twilight_abyss/PlayerTemp/TempCharacter.h"
#include "the_twilight_abyss/Quest/QuestSystem.h"

// Sets default values
ATurnBaseCombatV2::ATurnBaseCombatV2()
{
	if (HUDWidget == nullptr)
	{
		static ConstructorHelpers::FClassFinder<UUserWidget> HUDWidgetClass(TEXT("/Game/Blueprints/Combat_UI/Combat_UI"));
		HUDWidget = HUDWidgetClass.Class;
		static ConstructorHelpers::FClassFinder<UStatusEffect> StatusEffectThornsClassFinder(TEXT("/Game/Blueprints/StatusEffects/BP_Thorns"));
		ThornsStatusEffect = StatusEffectThornsClassFinder.Class;
		static ConstructorHelpers::FClassFinder<UStatusEffect> StatusEffectDotClassFinder(TEXT("/Game/Blueprints/StatusEffects/BP_DamageOverTime"));
		DOTStatusEffect = StatusEffectDotClassFinder.Class;

		static ConstructorHelpers::FClassFinder<UUserWidget> DeathScreenWidgetClass(TEXT("/Game/Blueprints/Death_UI/Death_UI"));
		DeathScreenWidgetSubclass = DeathScreenWidgetClass.Class;

		static ConstructorHelpers::FClassFinder<UUserWidget> CombatTutorialWidgetClass(TEXT("/Game/Blueprints/Combat_UI/CombatTutorial"));
		CombatTutorialWidget = CombatTutorialWidgetClass.Class;
	}
}

void ATurnBaseCombatV2::StartCombat(AActor* Enemy, const bool bWasShot)
{
	if (Enemy == nullptr) return;
	EnemyActor = Enemy;
	if (bIsInCombat) return;
	BookHUD->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
	HUD->AddToViewport(-1);
	BookStaticMeshComponent->SetVisibility(true);
	EscapePercentage = CalculateEscapePercentage();
	EscapePercentageTextBlock->SetText(FText::Join(FText::FromString(""), FText::FromString(FString::FromInt(EscapePercentage * 100)), FText::FromString("%")));
	bIsInCombat = true;
	UBlackboardComponent* EnemyBlackboard = Cast<AAIController>(Enemy->GetInstigatorController())->GetBlackboardComponent();
	Cast<UQuestSystem>(PlayerActor->GetComponentByClass(UQuestSystem::StaticClass()))->QuestWidgetInstance->SetVisibility(ESlateVisibility::Hidden);
	HealingJellyAmountTextBlock->SetText(FText::FromString(FString::FromInt(FMath::Clamp(Cast<ATempCharacter>(PlayerActor)->Inventory->GetItemAmount(0), 0, 99))));

	//Disable Character Movement
	APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
	PlayerController->SetIgnoreMoveInput(true);
	PlayerController->SetIgnoreLookInput(true);
	PlayerController->SetInputMode(FInputModeGameAndUI());
	PlayerController->bShowMouseCursor = true;

	FProperty* IsBossProperty = FindFieldChecked<FProperty>(EnemyActor->GetClass(), "IsBoss");
	const FBoolProperty* IsBossBoolProperty = CastFieldChecked<FBoolProperty>(IsBossProperty);
	if (IsBossBoolProperty->GetPropertyValue_InContainer(EnemyActor))
	{
		FOutputDeviceNull AR;
		const FString Command = FString::Printf(TEXT("TriggerCombatAnimation true"));
		EnemyActor->CallFunctionByNameWithArguments(*Command, AR, nullptr, true);

		FVector Direction = Enemy->GetActorLocation() - PlayerActor->GetActorLocation();
		Direction.Normalize();
		FRotator LookAtRotation = FRotationMatrix::MakeFromX(Direction).Rotator();
		const FRotator NewRotation = UKismetMathLibrary::FindLookAtRotation(Cast<UCameraComponent>(PlayerActor->FindComponentByClass<UCameraComponent>())->GetComponentLocation(), EnemyActor->GetActorLocation());
		LookAtRotation.Pitch = NewRotation.Pitch - PlayerActor->GetActorRotation().Pitch;
		PlayerController->SetControlRotation(LookAtRotation);
	}
	else
	{
		FVector Direction = Enemy->GetActorLocation() - PlayerActor->GetActorLocation();
		Direction.Normalize();
		FRotator LookAtRotation = FRotationMatrix::MakeFromX(Direction).Rotator();
		const FRotator NewRotation = UKismetMathLibrary::FindLookAtRotation(Cast<UCameraComponent>(PlayerActor->FindComponentByClass<UCameraComponent>())->GetComponentLocation(), Cast<USkeletalMeshComponent>(EnemyActor->FindComponentByClass<USkeletalMeshComponent>())->GetComponentLocation());
		LookAtRotation.Pitch = NewRotation.Pitch - PlayerActor->GetActorRotation().Pitch;
		PlayerController->SetControlRotation(LookAtRotation);
	}

	FVector Direction = Enemy->GetActorLocation() - PlayerActor->GetActorLocation();
	Direction.Normalize();
	FRotator LookAtRotation = FRotationMatrix::MakeFromX(Direction).Rotator();
	const FRotator NewRotation = UKismetMathLibrary::FindLookAtRotation(Cast<UCameraComponent>(PlayerActor->FindComponentByClass<UCameraComponent>())->GetComponentLocation(), EnemyActor->GetActorLocation());
	LookAtRotation.Pitch = NewRotation.Pitch - PlayerActor->GetActorRotation().Pitch;
	PlayerController->SetControlRotation(LookAtRotation);

	if (EnemyBlackboard->GetValueAsBool("IsInCombat")) return;
	EnemyBlackboard->SetValueAsBool("IsInCombat", true);
	const FProperty* HealthProperty = Enemy->GetClass()->FindPropertyByName(FName("Health"));
	int32* EnemyHealthPtr = HealthProperty->ContainerPtrToValuePtr<int32>(Enemy);
	EnemyHealth = EnemyHealthPtr;

	if (IsValid(CombatTutorialWidgetInstance) && CombatTutorialWidgetInstance->IsInViewport()) return;
	if (!HasSeenTutorial)
	{
		DisableButtons();
		CombatTutorialWidgetInstance->AddToViewport();
		FProperty* Property = FindFieldChecked<FProperty>(CombatTutorialWidgetInstance->GetClass(), "WasShot");
		const FBoolProperty* WasShotProperty = CastFieldChecked<FBoolProperty>(Property);
		WasShotProperty->SetPropertyValue_InContainer(CombatTutorialWidgetInstance, bWasShot);
		HasSeenTutorial = true;
		return;
	}

	CombatCheck(bWasShot);
	//DrawDebugPoint(GetWorld(), Enemy->GetActorLocation(), 10, FColor::Red, false, 10);
}

void ATurnBaseCombatV2::CombatCheck(const bool bWasShot)
{
	const UBlackboardComponent* EnemyBlackboard = Cast<AAIController>(EnemyActor->GetInstigatorController())->GetBlackboardComponent();

	ChainDamageMultiplier = 0;
	DamageMultiplierTextBlock->SetText(FText::FromString(""));

	const FProperty* ReactionSpeedProperty = EnemyActor->GetClass()->FindPropertyByName(FName("ReactionSpeed"));
	const float* EnemyReactionSpeedPtr = ReactionSpeedProperty->ContainerPtrToValuePtr<float>(EnemyActor);

	CurrentComboString = "";
	UpdateComboString(CurrentComboString);
	RevertActionPoints();
	UpdateActionPoints();
	UpdateResourceBars();
	UpdateProgressBars();
	ClearBattleLog();
	EnableButtons();

	if (EnemyBlackboard->GetValueAsBool("Sight") && !bWasShot)
	{
		//bEnemyHasExtraTurn = true;
		SwitchTurn();
		return;
	}
	else if (Cast<ATempCharacter>(PlayerActor)->ReactionSpeed > *EnemyReactionSpeedPtr && bWasShot)
	{
		TurnIndicatorTextBlock->SetText(FText::FromString("Player Turn\nExtra"));
		bPlayerHasExtraTurn = true;
		return;
	}
	TurnIndicatorTextBlock->SetText(FText::FromString("Player Turn"));
}

void ATurnBaseCombatV2::EndCombat()
{
	BookHUD->SetVisibility(ESlateVisibility::Hidden);
	HUD->RemoveFromParent();
	BookStaticMeshComponent->SetVisibility(false);
	Cast<UQuestSystem>(PlayerActor->GetComponentByClass(UQuestSystem::StaticClass()))->QuestWidgetInstance->SetVisibility(ESlateVisibility::HitTestInvisible);
	Cast<ATempCharacter>(PlayerActor)->ResetWidgetPointer();
	TurnIndicatorTextBlock->SetText(FText::FromString(""));
	bEnemyHasExtraTurn = false;
	bPlayerHasExtraTurn = false;
	bIsInCombat = false;
	BaseDamageMultiplier -= ChainDamageMultiplier;
	PreviousComboString = "";
	for (UStatusEffect* StatusEffect : StatusEffects)
	{
		StatusEffect->OnExpiry(PlayerActor);
	}

	HUD->RemoveFromParent();
	APawn* PlayerPawn = Cast<APawn>(GetWorld()->GetFirstPlayerController()->GetPawn());
	PlayerPawn->bUseControllerRotationYaw = true;
	PlayerPawn->bUseControllerRotationPitch = true;
	//Enable Character Movement
	//Set to Game Mode Only
	APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
	PlayerController->SetIgnoreMoveInput(false);
	PlayerController->SetIgnoreLookInput(false);
	PlayerController->SetInputMode(FInputModeGameOnly());
	PlayerController->bShowMouseCursor = false;

	if (IsValid(EnemyActor))
	{
		FProperty* IsBossProperty = FindFieldChecked<FProperty>(EnemyActor->GetClass(), "IsBoss");
		const FBoolProperty* IsBossBoolProperty = CastFieldChecked<FBoolProperty>(IsBossProperty);
		if (IsBossBoolProperty->GetPropertyValue_InContainer(EnemyActor))
		{
			FOutputDeviceNull AR;
			const FString Command = FString::Printf(TEXT("TriggerCombatAnimation false"));
			EnemyActor->CallFunctionByNameWithArguments(*Command, AR, nullptr, true);
		}
	}
}

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

	TArray<AActor*> AllCharacterActorsInScene;

	UGameplayStatics::GetAllActorsOfClassWithTag(GetWorld(), AActor::StaticClass(), FName("Player"), AllCharacterActorsInScene);
	for (AActor* Actor : AllCharacterActorsInScene)
	{
		PlayerActor = Cast<AActor>(Actor);
	}
	PlayerHealth = &Cast<ATempCharacter>(PlayerActor)->Health;

	TArray<AActor*> AllActorsInScene;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), APostProcessVolume::StaticClass(), AllActorsInScene);
	if (ensureMsgf(AllActorsInScene.Num() > 0, TEXT("No Post Processing Volume in scene")))
	{
		PostProcessVolume = Cast<APostProcessVolume>(AllActorsInScene[0]);
	}

	if (IsValid(RedVignetteMaterialInstance))
	{
		FWeightedBlendable WeightedBlendable;
		WeightedBlendable.Object = RedVignetteMaterialInstance;
		WeightedBlendable.Weight = 1.0f;
		if (IsValid(PostProcessVolume)) PostProcessVolume->Settings.WeightedBlendables.Array.Add(WeightedBlendable);
	}

	TArray<UStaticMeshComponent*> StaticMeshComponents;
	PlayerActor->GetComponents<UStaticMeshComponent>(StaticMeshComponents);
	BookStaticMeshComponent = StaticMeshComponents[1];
	BookStaticMeshComponent->SetVisibility(false);

	CombatTutorialWidgetInstance = CreateWidget<UUserWidget>(GetWorld(), CombatTutorialWidget);
	HUD = CreateWidget<UUserWidget>(GetWorld(), HUDWidget);
	TArray<AActor*> PlayerChildActors;
	PlayerActor->GetAllChildActors(PlayerChildActors, false);
	PlayerWidget = Cast<UWidgetComponent>(PlayerChildActors[0]->GetComponentByClass(UWidgetComponent::StaticClass()));
	PlayerWidget->InitWidget();
	BookHUD = PlayerWidget->GetWidget();

	TurnIndicatorTextBlock = Cast<UTextBlock>(BookHUD->GetWidgetFromName("TurnIndicator"));
	CurrentComboTextBlock = Cast<UTextBlock>(BookHUD->GetWidgetFromName("CurrentCombo"));
	CurrentComboTextBlock1 = Cast<UTextBlock>(BookHUD->GetWidgetFromName("CurrentCombo_1"));
	CurrentComboTextBlock2 = Cast<UTextBlock>(BookHUD->GetWidgetFromName("CurrentCombo_2"));
	BattleLogTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("BattleLog"));
	EscapePercentageTextBlock = Cast<UTextBlock>(BookHUD->GetWidgetFromName("EscapePercentage_Text"));
	DamageMultiplierTextBlock = Cast<UTextBlock>(BookHUD->GetWidgetFromName("DamageMultiplier_Text"));
	HealingJellyAmountTextBlock = Cast<UTextBlock>(BookHUD->GetWidgetFromName("HealingAmount_Text"));
	DamageAmountEnemyTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("DamageAmountEnemy_Text"));
	DamageAmountPlayerTextBlock = Cast<UTextBlock>(BookHUD->GetWidgetFromName("DamageAmountPlayer_Text"));
	StatusTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("Status_Text"));
	PlayerHealthBar = Cast<UProgressBar>(BookHUD->GetWidgetFromName("PlayerHealthBar"));
	EnemyHealthBar = Cast<UProgressBar>(HUD->GetWidgetFromName("EnemyHealthBar"));
	ProbertiumResourceBar = Cast<UProgressBar>(BookHUD->GetWidgetFromName("ProbertiumResourceBar"));
	EisResourceBar = Cast<UProgressBar>(BookHUD->GetWidgetFromName("EisResourceBar"));
	AzosResourceBar = Cast<UProgressBar>(BookHUD->GetWidgetFromName("AzosResourceBar"));
	IroquoidResourceBar = Cast<UProgressBar>(BookHUD->GetWidgetFromName("IroquoidResourceBar"));
	CastButton = Cast<UButton>(BookHUD->GetWidgetFromName("Cast_Button"));
	PButton = Cast<UButton>(BookHUD->GetWidgetFromName("Probertium_Button"));
	EButton = Cast<UButton>(BookHUD->GetWidgetFromName("Eis_Button"));
	AButton = Cast<UButton>(BookHUD->GetWidgetFromName("Azos_Button"));
	IButton = Cast<UButton>(BookHUD->GetWidgetFromName("Iroquoid_Button"));
	BackspaceButton = Cast<UButton>(BookHUD->GetWidgetFromName("Clear_Button"));
	RunButton = Cast<UButton>(BookHUD->GetWidgetFromName("Escape_Button"));
	HealButton = Cast<UButton>(BookHUD->GetWidgetFromName("Heal_Button"));
	CastButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::CastButtonOnClick);
	PButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::PButtonOnClick);
	EButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::EButtonOnClick);
	AButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::AButtonOnClick);
	IButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::IButtonOnClick);
	BackspaceButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::BackspaceButtonOnClick);
	RunButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::RunButtonOnClick);
	HealButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::HealButtonOnClick);
}

void ATurnBaseCombatV2::ExecuteCast(FString Combo)
{
	if (!IsValidCombo(Combo))
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Invalid Combo"));
		for (int i = 0; i < Combo.Len(); i++)
		{
			if (Combo[i] == 'P')
			{
				ProbertiumResource += 1;
			}
			else if (Combo[i] == 'E')
			{
				EisResource += 1;
			}
			else if (Combo[i] == 'A')
			{
				AzosResource += 1;
			}
			else if (Combo[i] == 'I')
			{
				IroquoidResource += 1;
			}
		}
		CurrentComboString = "";
		UpdateComboString(CurrentComboString);
		RevertActionPoints();
		UpdateActionPoints();
		UpdateResourceBars();
		return;
	}
	if (IsSpecialCombo(Combo))
	{
		UStatusSystem* StatusSystem = Cast<UStatusSystem>(PlayerActor->GetComponentByClass(UStatusSystem::StaticClass()));
		if (Combo == "PA")
		{
			UStatusEffect* TempThornsStatusEffect = NewObject<UStatusEffect>(PlayerActor, ThornsStatusEffect);
			StatusSystem->AddStatusEffect(TempThornsStatusEffect, 1, false);
			StatusEffects.Add(TempThornsStatusEffect);
			AddBattleLogMessage("Player Casted Thorns");
		}
		else if (Combo == "PI")
		{
			UStatusEffect* TempDOTStatusEffect = NewObject<UStatusEffect>(PlayerActor, DOTStatusEffect);
			StatusSystem->AddStatusEffect(TempDOTStatusEffect, 1, false);
			StatusEffects.Add(TempDOTStatusEffect);
			AddBattleLogMessage("Player Casted DOT");
		}
	}

	if (GunEffect)
	{
		const UStaticMeshComponent* GunComponent = Cast<UStaticMeshComponent>(PlayerActor->GetComponentsByTag(UPrimitiveComponent::StaticClass(), FName("Gun"))[0]);
		const FVector GunLocationOffset = GunComponent->GetSocketTransform("Muzzle").GetLocation();
		UNiagaraFunctionLibrary::SpawnSystemAtLocation(GetWorld(), GunEffect, GunLocationOffset, PlayerActor->GetActorRotation());
		FOutputDeviceNull AR;
		const FString Command = FString::Printf(TEXT("PlayCameraShakeShoot"));
		PlayerActor->CallFunctionByNameWithArguments(*Command, AR, nullptr, true);
	}

	if (ChainDamageMultiplier == 1) BaseDamageMultiplier = 1;
	if ((CurrentComboString == "II" || CurrentComboString == "PP" || CurrentComboString == "EE" || CurrentComboString == "AA") &&
		(PreviousComboString == "II" || PreviousComboString == "PP" || PreviousComboString == "EE" || PreviousComboString == "AA"))
	{
		ChainDamageMultiplier += ChainDamageMultiplierIncrease;
		DamageMultiplierTextBlock->SetText(FText::Join(FText::FromString(""), FText::FromString("x"), FText::FromString(FString::SanitizeFloat(ChainDamageMultiplier + BaseDamageMultiplier))));
	}
	else if (CurrentComboString == "EI")
	{
		BaseDamageMultiplier += ChainDamageMultiplier;
		DamageMultiplierTextBlock->SetText(FText::FromString(""));
	}

	PreviousComboString = CurrentComboString;

	CurrentComboString = "";
	UpdateComboString(CurrentComboString);
	RevertActionPoints();
	UpdateActionPoints();

	//Damage Calculation
	switch (bIsPlayerTurn)
	{
	case true:
		// Player Turn
		DamageEnemy(*ValidCombos.Find(Combo));
		OnPlayerTurn.Broadcast(PlayerActor, EnemyActor);
		break;
	case false:
		// Enemy Turn
		DamagePlayer(*ValidCombos.Find(Combo));
		OnEnemyTurn.Broadcast(EnemyActor, PlayerActor);
		break;
	}

	if (!bPlayerHasExtraTurn)
	{
		SwitchTurn();
	}
	else
	{
		TurnIndicatorTextBlock->SetText(FText::FromString("Player Turn"));
		bPlayerHasExtraTurn = false;
	}
}

void ATurnBaseCombatV2::UseActionPoint()
{
	ActiveActionPoints += 1;
	UpdateActionPoints();
}

void ATurnBaseCombatV2::ReuseActionPoint()
{
	ActiveActionPoints -= 1;
	UpdateActionPoints();
}

void ATurnBaseCombatV2::RevertActionPoints()
{
	ActiveActionPoints = 0;
	UpdateActionPoints();
}

void ATurnBaseCombatV2::DamagePlayer(int Damage, const FString& DamageType)
{
	FOutputDeviceNull AR;
	*PlayerHealth -= FMath::Clamp(Damage * BaseDefenseMultiplier, 0, 100);
	DamageAmountPlayerTextBlock->SetText(FText::FromString("-" + FString::FromInt(Damage * BaseDefenseMultiplier)));
	const FString Command3 = FString::Printf(TEXT("PlayDamagePlayerTextAnimation"));
	BookHUD->CallFunctionByNameWithArguments(*Command3, AR, nullptr, true);
	UpdateProgressBars();
	AddBattleLogMessage("Player was damaged for " + FString::FromInt(Damage * BaseDefenseMultiplier) + " HP by " + DamageType + ".");
	if (*EnemyHealth <= 0)
	{
		EndCombat();
		FProperty* IsBossProperty = FindFieldChecked<FProperty>(EnemyActor->GetClass(), "IsBoss");
		const FBoolProperty* IsBossBoolProperty = CastFieldChecked<FBoolProperty>(IsBossProperty);
		if (IsBossBoolProperty->GetPropertyValue_InContainer(EnemyActor))
		{
			const FString Command = FString::Printf(TEXT("TriggerDeathAnimation"));
			EnemyActor->CallFunctionByNameWithArguments(*Command, AR, nullptr, true);
			return;
		}
		EnemyActor->Destroy();
		return;
	}
	if (*PlayerHealth <= 0)
	{
		//EndCombat();
		DeathScreenWidget = CreateWidget<UUserWidget>(GetWorld(), DeathScreenWidgetSubclass);
		DeathScreenWidget->AddToViewport();
		return;
	}
	const FString Command = FString::Printf(TEXT("PlayCameraShakeShoot"));
	PlayerActor->CallFunctionByNameWithArguments(*Command, AR, nullptr, true);
	RedVignetteMaterialInstance->SetScalarParameterValue(FName("BlendWeight"), 1.0f);

	const FString Command2 = FString::Printf(TEXT("TriggerAttackAnimation"));
	EnemyActor->CallFunctionByNameWithArguments(*Command2, AR, nullptr, true);
}

void ATurnBaseCombatV2::DamageEnemy(int Damage, const FString& DamageType)
{
	*EnemyHealth -= FMath::Clamp(Damage * BaseDamageMultiplier, 0, 100);
	UpdateProgressBars();
	DamageAmountEnemyTextBlock->SetText(FText::FromString("-" + FString::FromInt(Damage * BaseDamageMultiplier)));
	FOutputDeviceNull AR;
	const FString Command = FString::Printf(TEXT("PlayDamageEnemyTextAnimation"));
	HUD->CallFunctionByNameWithArguments(*Command, AR, nullptr, true);
	AddBattleLogMessage("Enemy was damaged for " + FString::FromInt(Damage * BaseDamageMultiplier) + " HP by " + DamageType + ".");
	if (DamageMultiplierTextBlock->GetText().ToString() == "")
	{
		BaseDamageMultiplier -= ChainDamageMultiplier;
		ChainDamageMultiplier = 0;
	}

	FProperty* IsBossProperty = FindFieldChecked<FProperty>(EnemyActor->GetClass(), "IsBoss");
	const FBoolProperty* IsBossBoolProperty = CastFieldChecked<FBoolProperty>(IsBossProperty);
	if (IsBossBoolProperty->GetPropertyValue_InContainer(EnemyActor))
	{
		const FString Command2 = FString::Printf(TEXT("TriggerDamageAnimation"));
		EnemyActor->CallFunctionByNameWithArguments(*Command2, AR, nullptr, true);
	}

	//Ends Combat if either the player or enemy is dead
	if (*EnemyHealth <= 0)
	{
		EndCombat();
		if (IsBossBoolProperty->GetPropertyValue_InContainer(EnemyActor))
		{
			const FString Command2 = FString::Printf(TEXT("TriggerDeathAnimation"));
			EnemyActor->CallFunctionByNameWithArguments(*Command2, AR, nullptr, true);
			return;
		}
		EnemyActor->Destroy();
		return;
	}
	if (*PlayerHealth <= 0)
	{
		//EndCombat();
		DeathScreenWidget = CreateWidget<UUserWidget>(GetWorld(), DeathScreenWidgetSubclass);
		DeathScreenWidget->AddToViewport();
		return;
	}
}

void ATurnBaseCombatV2::UpdateProgressBars() const
{
	const FProperty* MaxHealthProperty = EnemyActor->GetClass()->FindPropertyByName(FName("MaxHealth"));
	const int32* EnemyMaxHealthPtr = MaxHealthProperty->ContainerPtrToValuePtr<int32>(EnemyActor);
	EnemyHealthBar->SetPercent(static_cast<float>(*EnemyHealth) / static_cast<float>(*EnemyMaxHealthPtr));
}

float ATurnBaseCombatV2::CalculateEscapePercentage() const
{
	return FMath::RandRange(0.1f, 0.9f);
}

bool ATurnBaseCombatV2::IsValidCombo(const FString& Combo) const
{
	return ValidCombos.Contains(Combo);
}

bool ATurnBaseCombatV2::IsSpecialCombo(const FString& Combo) const
{
	return SpecialCombos.Contains(Combo);
}

void ATurnBaseCombatV2::SwitchTurn()
{
	//TurnIndicatorTextBlock->SetText(FText::FromString(bIsPlayerTurn ? "Enemy Turn" : "Player Turn"));
	//bIsPlayerTurn = !bIsPlayerTurn;
	TurnIndicatorTextBlock->SetText(FText::FromString("Enemy Turn"));
	DisableButtons();

	FTimerHandle UnusedHandle;
	GetWorldTimerManager().SetTimer(UnusedHandle, this, &ATurnBaseCombatV2::EnemyTurn, 2.0f, false);

	//activeActor = bIsPlayerTurn ? enemyActor : playerActor;
}

void ATurnBaseCombatV2::CastButtonOnClick()
{
	ExecuteCast(CurrentComboString);
}

void ATurnBaseCombatV2::PButtonOnClick()
{
	if (ActiveActionPoints >= DefaultActionPoints)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
		return;
	}
	if (ProbertiumResource <= 0)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Probertium"));
		return;
	}
	UseActionPoint();
	CurrentComboString.AppendChar('P');
	UpdateComboString(CurrentComboString);
	ProbertiumResource -= 1;
	UpdateResourceBars();
}

void ATurnBaseCombatV2::EButtonOnClick()
{
	if (ActiveActionPoints >= DefaultActionPoints)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
		return;
	}
	if (EisResource <= 0)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Eis"));
		return;
	}
	UseActionPoint();
	CurrentComboString.AppendChar('E');
	UpdateComboString(CurrentComboString);
	EisResource -= 1;
	UpdateResourceBars();
}

void ATurnBaseCombatV2::AButtonOnClick()
{
	if (ActiveActionPoints >= DefaultActionPoints)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
		return;
	}
	if (AzosResource <= 0)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Azos"));
		return;
	}
	UseActionPoint();
	CurrentComboString.AppendChar('A');
	UpdateComboString(CurrentComboString);
	AzosResource -= 1;
	UpdateResourceBars();
}

void ATurnBaseCombatV2::IButtonOnClick()
{
	if (ActiveActionPoints >= DefaultActionPoints)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
		return;
	}
	if (IroquoidResource <= 0)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Iroquoid"));
		return;
	}
	UseActionPoint();
	CurrentComboString.AppendChar('I');
	UpdateComboString(CurrentComboString);
	IroquoidResource -= 1;
	UpdateResourceBars();
}

void ATurnBaseCombatV2::BackspaceButtonOnClick()
{
	if (CurrentComboString.Len() <= 0)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Blank Combo"));
		return;
	}
	for (int i = 0; i < CurrentComboString.Len(); i++)
	{
		if (CurrentComboString[i] == 'P')
		{
			ProbertiumResource += 1;
		}
		else if (CurrentComboString[i] == 'E')
		{
			EisResource += 1;
		}
		else if (CurrentComboString[i] == 'A')
		{
			AzosResource += 1;
		}
		else if (CurrentComboString[i] == 'I')
		{
			IroquoidResource += 1;
		}
	}
	CurrentComboString = "";
	UpdateComboString(CurrentComboString);
	RevertActionPoints();
	UpdateActionPoints();
	UpdateResourceBars();
}

void ATurnBaseCombatV2::RunButtonOnClick()
{
	if (FMath::RandRange(0.0f, 1.0f) >= EscapePercentage)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Escape Failed"));
		StatusTextBlock->SetText(FText::FromString("Escape Failed"));
		FOutputDeviceNull AR;
		const FString Command3 = FString::Printf(TEXT("PlayStatusAnimation"));
		HUD->CallFunctionByNameWithArguments(*Command3, AR, nullptr, true);
		EscapePercentage = CalculateEscapePercentage();
		EscapePercentageTextBlock->SetText(FText::Join(FText::FromString(""), FText::FromString(FString::FromInt(EscapePercentage * 100)), FText::FromString("%")));
		SwitchTurn();
		return;
	}
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Escape Successful"));
	UBlackboardComponent* EnemyBlackboard = Cast<AAIController>(EnemyActor->GetInstigatorController())->GetBlackboardComponent();
	EscapePercentageTextBlock->SetText(FText::Join(FText::FromString(""), FText::FromString("--"), FText::FromString("%")));
	EnemyBlackboard->SetValueAsBool("IsInCombat", false);
	EnemyBlackboard->SetValueAsBool("WasInCombat", true);
	EndCombat();
}

void ATurnBaseCombatV2::HealButtonOnClick()
{
	if (Cast<ATempCharacter>(PlayerActor)->Inventory->GetItemAmount(0) >= 1)
	{
		Cast<ATempCharacter>(PlayerActor)->Inventory->GetItemByID(0)->Use(Cast<ATempCharacter>(PlayerActor));
		HealingJellyAmountTextBlock->SetText(FText::FromString(FString::FromInt(FMath::Clamp(Cast<ATempCharacter>(PlayerActor)->Inventory->GetItemAmount(0), 0, 99))));
		UpdateResourceBars();
		SwitchTurn();
	}
}

void ATurnBaseCombatV2::UpdateComboString(const FString& NewCombo) const
{
	CurrentComboTextBlock->SetText(FText::FromString("?"));
	CurrentComboTextBlock1->SetText(FText::FromString("?"));
	CurrentComboTextBlock2->SetText(FText::FromString("?"));

	if (NewCombo.Len() > 0) BackspaceButton->SetVisibility(ESlateVisibility::Visible);
	else BackspaceButton->SetVisibility(ESlateVisibility::Hidden);

	if (IsValidCombo(NewCombo))
	{
		CurrentComboTextBlock->SetText(FText::FromString(NewCombo));
		CastButton->SetVisibility(ESlateVisibility::Visible);
	}
	else
	{
		CastButton->SetVisibility(ESlateVisibility::Hidden);
	}
	if (NewCombo.Len() == 1)
	{
		CurrentComboTextBlock1->SetText(FText::FromString(NewCombo));
	}
	else if (NewCombo.Len() == 2)
	{
		CurrentComboTextBlock1->SetText(FText::FromString(NewCombo.LeftChop(1)));
		CurrentComboTextBlock2->SetText(FText::FromString(NewCombo.RightChop(1)));
	}
}

void ATurnBaseCombatV2::UpdateActionPoints()
{
	return;
}

void ATurnBaseCombatV2::AddBattleLogMessage(const FString& Message)
{
	BattleLog.Append(Message + "\n");
	UpdateBattleLog();
}

void ATurnBaseCombatV2::ClearBattleLog()
{
	BattleLog = "";
}

void ATurnBaseCombatV2::UpdateBattleLog()
{
	TArray<FString> TempArray;
	if (const int32 LineCount = BattleLog.ParseIntoArray(TempArray, TEXT("\n"), true); LineCount > 10)
	{
		ClearBattleLog();
	}
	BattleLogTextBlock->SetText(FText::FromString(BattleLog));
}

void ATurnBaseCombatV2::UpdateResourceBars() const
{
	ProbertiumResourceBar->SetPercent(ProbertiumResource / 10.0f);
	EisResourceBar->SetPercent(EisResource / 10.0f);
	AzosResourceBar->SetPercent(AzosResource / 10.0f);
	IroquoidResourceBar->SetPercent(IroquoidResource / 10.0f);
	ToggleButtonIfResourceAvailable();
}

void ATurnBaseCombatV2::DisableButtons() const
{
	PButton->SetIsEnabled(false);
	EButton->SetIsEnabled(false);
	AButton->SetIsEnabled(false);
	IButton->SetIsEnabled(false);
	BackspaceButton->SetIsEnabled(false);
	CastButton->SetIsEnabled(false);
	RunButton->SetIsEnabled(false);
	HealButton->SetIsEnabled(false);
}

void ATurnBaseCombatV2::EnableButtons() const
{
	ToggleButtonIfResourceAvailable();
	BackspaceButton->SetIsEnabled(true);
	CastButton->SetIsEnabled(true);
	RunButton->SetIsEnabled(true);
}

void ATurnBaseCombatV2::EnemyTurn()
{
	int ChanceToMiss;
	FProperty* IsBossProperty = FindFieldChecked<FProperty>(EnemyActor->GetClass(), "IsBoss");
	const FBoolProperty* IsBossBoolProperty = CastFieldChecked<FBoolProperty>(IsBossProperty);
	if (IsBossBoolProperty->GetPropertyValue_InContainer(EnemyActor)) ChanceToMiss = 5;
	else ChanceToMiss = 30;
	if (FMath::RandRange(1, 100) > ChanceToMiss)
	{
		const FProperty* EnemyBaseDamageProperty = EnemyActor->GetClass()->FindPropertyByName(FName("BaseDamage"));
		const int* EnemyBaseDamageSpeedPtr = EnemyBaseDamageProperty->ContainerPtrToValuePtr<int>(EnemyActor);
		DamagePlayer(*EnemyBaseDamageSpeedPtr);
	}
	else
	{
		StatusTextBlock->SetText(FText::FromString("Missed"));
		FOutputDeviceNull AR;
		const FString Command3 = FString::Printf(TEXT("PlayStatusAnimation"));
		HUD->CallFunctionByNameWithArguments(*Command3, AR, nullptr, true);
		const FString Command2 = FString::Printf(TEXT("TriggerAttackAnimation"));
		EnemyActor->CallFunctionByNameWithArguments(*Command2, AR, nullptr, true);
	}

	OnEnemyTurn.Broadcast(EnemyActor, PlayerActor);
	TurnIndicatorTextBlock->SetText(FText::FromString("Player Turn"));
	EnableButtons();
}

void ATurnBaseCombatV2::ToggleButtonIfResourceAvailable() const
{
	if (ProbertiumResource >= 1) PButton->SetIsEnabled(true);
	else PButton->SetIsEnabled(false);
	if (EisResource >= 1) EButton->SetIsEnabled(true);
	else EButton->SetIsEnabled(false);
	if (AzosResource >= 1) AButton->SetIsEnabled(true);
	else AButton->SetIsEnabled(false);
	if (IroquoidResource >= 1) IButton->SetIsEnabled(true);
	else IButton->SetIsEnabled(false);
	if (Cast<ATempCharacter>(PlayerActor)->Inventory->GetItemAmount(0) >= 1) HealButton->SetIsEnabled(true);
	else HealButton->SetIsEnabled(false);
}