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


#include "TurnBaseCombatV2.h"
#include "CoreMinimal.h"
#include "AIController.h"
#include "Blueprint/UserWidget.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Components/TextBlock.h"
#include "Components/ProgressBar.h"
#include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h"
#include "the_twilight_abyss/PlayerTemp/TempCharacter.h"

// Sets default values
ATurnBaseCombatV2::ATurnBaseCombatV2()
{
	if (HUDWidget == nullptr)
	{
		// Load the HUD widget from the specified path
		static ConstructorHelpers::FClassFinder<UUserWidget> HUDWidgetClass(TEXT("/Game/Blueprints/Combat_UI/Combat_UI"));
		HUDWidget = HUDWidgetClass.Class;
	}
}

void ATurnBaseCombatV2::StartCombat(AActor* Enemy)
{
	if (Enemy == nullptr) return;
	UBlackboardComponent* EnemyBlackboard = Cast<AAIController>(Enemy->GetInstigatorController())->GetBlackboardComponent();
	
	if (EnemyBlackboard->GetValueAsBool("IsInCombat")) return;
	EnemyBlackboard->SetValueAsBool("IsInCombat", true);
	FProperty* HealthProperty = Enemy->GetClass()->FindPropertyByName(FName("Health"));
	int32* EnemyHealthPtr = HealthProperty->ContainerPtrToValuePtr<int32>(Enemy);

	EnemyHealth = EnemyHealthPtr;

	if (HUD->IsInViewport()) return;
	HUD->AddToViewport();
	EnemyActor = Enemy;

	IronResource = 10;
	SulfurResource = 10;

	//Disable Character Movement
	if (ACharacter* PlayerCharacter = Cast<ACharacter>(GetWorld()->GetFirstPlayerController()->GetPawn()))
	{
		PlayerCharacter->DisableInput(GetWorld()->GetFirstPlayerController());
	}
	//Set to UI Mode Only
	APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
	PlayerController->SetInputMode(FInputModeUIOnly());
	PlayerController->bShowMouseCursor = true;
	
	CurrentComboString = "";
	UpdateComboString(CurrentComboString);
	RevertActionPoints();
	UpdateActionPoints();
	UpdateResourceBars();
	ClearBattleLog();
}

void ATurnBaseCombatV2::EndCombat()
{
	//Remove the HUD from the viewport
	HUD->RemoveFromParent();
	APawn* PlayerPawn = Cast<APawn>(GetWorld()->GetFirstPlayerController()->GetPawn());
	PlayerPawn->bUseControllerRotationYaw = true;
	PlayerPawn->bUseControllerRotationPitch = true;
	//Enable Character Movement
	if (ACharacter* PlayerCharacter = Cast<ACharacter>(GetWorld()->GetFirstPlayerController()->GetPawn()))
	{
		PlayerCharacter->EnableInput(GetWorld()->GetFirstPlayerController());
	}
	//Set to Game Mode Only
	APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
	PlayerController->SetInputMode(FInputModeGameOnly());
	PlayerController->bShowMouseCursor = false;
}

void ATurnBaseCombatV2::FKeyPressed()
{
	FButtonOnClick();
}

void ATurnBaseCombatV2::WKeyPressed()
{
	WButtonOnClick();
}

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;

	HUD = CreateWidget<UUserWidget>(GetWorld(), HUDWidget);

	TurnIndicatorTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("TurnIndicator"));
	CurrentComboTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("CurrentCombo"));
	ActionPointsTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("ActionPoints"));
	BattleLogTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("BattleLog"));
	PlayerHealthBar = Cast<UProgressBar>(HUD->GetWidgetFromName("PlayerHealthBar"));
	EnemyHealthBar = Cast<UProgressBar>(HUD->GetWidgetFromName("EnemyHealthBar"));
	IronResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("IronResourceBar"));
	SulfurResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("SulfurResourceBar"));
	CastButton = Cast<UButton>(HUD->GetWidgetFromName("CastButton"));
	FButton = Cast<UButton>(HUD->GetWidgetFromName("FButton"));
	WButton = Cast<UButton>(HUD->GetWidgetFromName("WButton"));
	BackspaceButton = Cast<UButton>(HUD->GetWidgetFromName("BackspaceButton"));
	RunButton = Cast<UButton>(HUD->GetWidgetFromName("RunButton"));
	CastButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::CastButtonOnClick);
	FButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::FButtonOnClick);
	WButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::WButtonOnClick);
	BackspaceButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::BackspaceButtonOnClick);
	RunButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::RunButtonOnClick);
}

void ATurnBaseCombatV2::ExecuteCast(FString Combo)
{
	if (!IsValidCombo(Combo))
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Invalid Combo"));
		//For each character in the current combo add back the resource
		for (int i = 0; i < Combo.Len(); i++)
		{
			if (Combo[i] == 'F')
			{
				IronResource += 1;
			}
			else if (Combo[i] == 'W')
			{
				SulfurResource += 1;
			}
		}
		CurrentComboString = "";
		UpdateComboString(CurrentComboString);
		RevertActionPoints();
		UpdateActionPoints();
		UpdateResourceBars();
		return;
	}

	if (GunEffect)
	{
		//Get Static Mesh Location on the player actor
		const UStaticMeshComponent* GunComponent = Cast<UStaticMeshComponent>(PlayerActor->GetComponentsByTag(UPrimitiveComponent::StaticClass(), FName("Gun"))[0]);
		const FVector GunLocationOffset = GunComponent->GetSocketTransform("Muzzle").TransformPosition(FVector(-100, 0, 0));
		UNiagaraFunctionLibrary::SpawnSystemAtLocation(GetWorld(), GunEffect, GunLocationOffset, PlayerActor->GetActorRotation());
	}

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

	switch (bIsPlayerTurn)
	{
	case true:
		// Player Turn
		DamageEnemy(*ValidCombos.Find(Combo));
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("Enemy Damaged %d"), *ValidCombos.Find(Combo)));
		break;
	case false:
		// Enemy Turn
		DamagePlayer(*ValidCombos.Find(Combo));
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("Player Damaged %d"), *ValidCombos.Find(Combo)));
		break;
	}
	//End Combat if either the player or enemy is dead
	if (*EnemyHealth <= 0)
	{
		EndCombat();
		EnemyActor->Destroy();
		return;
	}
	if (*PlayerHealth <= 0)
	{
		EndCombat();
		return;
	}

	SwitchTurn();
}

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

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

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

void ATurnBaseCombatV2::DamagePlayer(int Damage)
{
	*PlayerHealth -= FMath::Clamp(Damage, 0, 100);
	UpdateProgressBars();
	AddBattleLogMessage("Player was damaged for " + FString::FromInt(Damage) + " damage.");
}

void ATurnBaseCombatV2::DamageEnemy(int Damage)
{
	*EnemyHealth -= FMath::Clamp(Damage, 0, 100);
	UpdateProgressBars();
	AddBattleLogMessage("Enemy was damaged for " + FString::FromInt(Damage) + " damage.");
}

void ATurnBaseCombatV2::UpdateProgressBars() const
{
	PlayerHealthBar->SetPercent(*PlayerHealth / 100.0f);
	EnemyHealthBar->SetPercent(*EnemyHealth / 100.0f);
}

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

void ATurnBaseCombatV2::SwitchTurn()
{
	//TurnIndicatorTextBlock->SetText(FText::FromString(bIsPlayerTurn ? "Enemy Turn" : "Player Turn"));
	//bIsPlayerTurn = !bIsPlayerTurn;
	TurnIndicatorTextBlock->SetText(FText::FromString("Enemy Turn"));
	ToggleButtons();
	//wait for 2 seconds
	FTimerHandle UnusedHandle;
	GetWorldTimerManager().SetTimer(UnusedHandle, this, &ATurnBaseCombatV2::EnemyTurn, 2.0f, false);

	//activeActor = bIsPlayerTurn ? enemyActor : playerActor;
}

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

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

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

void ATurnBaseCombatV2::BackspaceButtonOnClick()
{
	if (CurrentComboString.Len() <= 0)
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Blank Combo"));
		return;
	}
	ReuseActionPoint();
	if (CurrentComboString.Right(1) == "F")
	{
		IronResource += 1;
	}
	else if (CurrentComboString.Right(1) == "W")
	{
		SulfurResource += 1;
	}
	CurrentComboString.RemoveAt(CurrentComboString.Len() - 1);
	UpdateComboString(CurrentComboString);
	UpdateResourceBars();
}

void ATurnBaseCombatV2::RunButtonOnClick()
{
	UBlackboardComponent* EnemyBlackboard = Cast<AAIController>(EnemyActor->GetInstigatorController())->GetBlackboardComponent();
	
	EnemyBlackboard->SetValueAsBool("IsInCombat", false);
	EndCombat();
}

void ATurnBaseCombatV2::UpdateComboString(FString NewCombo) const
{
	CurrentComboTextBlock->SetText(FText::FromString(NewCombo));
}

void ATurnBaseCombatV2::UpdateActionPoints() const
{
	ActionPointsTextBlock->SetText(FText::FromString(FString::FromInt(DefaultActionPoints - ActiveActionPoints)));
}

void ATurnBaseCombatV2::AddBattleLogMessage(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
{
	IronResourceBar->SetPercent(IronResource / 10.0f);
	SulfurResourceBar->SetPercent(SulfurResource / 10.0f);
}

void ATurnBaseCombatV2::ToggleButtons() const
{
	FButton->SetIsEnabled(!FButton->GetIsEnabled());
	WButton->SetIsEnabled(!WButton->GetIsEnabled());
	BackspaceButton->SetIsEnabled(!BackspaceButton->GetIsEnabled());
	CastButton->SetIsEnabled(!CastButton->GetIsEnabled());
	RunButton->SetIsEnabled(!RunButton->GetIsEnabled());
}

void ATurnBaseCombatV2::EnemyTurn()
{
	DamagePlayer(10);
	TurnIndicatorTextBlock->SetText(FText::FromString("Player Turn"));
	ToggleButtons();
}