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


#include "QuestSystem.h"
#include "Misc/OutputDeviceNull.h"


// Sets default values for this component's properties
UQuestSystem::UQuestSystem()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;

	static ConstructorHelpers::FClassFinder<UUserWidget> QuestWidgetClass(TEXT("/Game/Blueprints/Quest_UI/Quest_UI"));
	QuestWidget = QuestWidgetClass.Class;
	static ConstructorHelpers::FClassFinder<UUserWidget> QuestCompletionWidgetClass(TEXT("/Game/Blueprints/Quest_UI/QuestCompletion_UI"));
	QuestCompletionWidget = QuestCompletionWidgetClass.Class;
}


// Called when the game starts
void UQuestSystem::BeginPlay()
{
	Super::BeginPlay();
	PlayerInventory = GetOwner()->FindComponentByClass<UInventoryComponent>();
	PlayerInventory->OnInventoryUpdated.AddDynamic(this, &UQuestSystem::CheckActiveQuestConditions);
	QuestWidgetInstance = CreateWidget<UUserWidget>(GetWorld(), QuestWidget);
	QuestWidgetInstance->AddToViewport();
	QuestCompletionWidgetInstance = CreateWidget<UUserWidget>(GetWorld(), QuestCompletionWidget);
	QuestCompletionWidgetInstance->AddToViewport();

	MainQuestBorder = Cast<UBorder>(QuestWidgetInstance->GetWidgetFromName("MainQuest"));
	SubQuestBorder = Cast<UBorder>(QuestWidgetInstance->GetWidgetFromName("SubQuest"));
	MainQuestTitle = Cast<UTextBlock>(QuestWidgetInstance->GetWidgetFromName("MainQuest_Text"));
	SubQuestTitle = Cast<UTextBlock>(QuestWidgetInstance->GetWidgetFromName("SubQuest_Text"));
	MainQuestGoals = Cast<URichTextBlock>(QuestWidgetInstance->GetWidgetFromName("MainGoals_Text"));
	SubQuestGoals = Cast<URichTextBlock>(QuestWidgetInstance->GetWidgetFromName("SubGoals_Text"));

	QuestCompletionTitle = Cast<UTextBlock>(QuestCompletionWidgetInstance->GetWidgetFromName("QuestTitle_Text"));
	if (!ActiveQuests.IsEmpty())
	{
		MainQuestTitle->SetText(ActiveQuests[0]->Title);
		UpdateQuestGoalsUI(ActiveQuests[0]);
	}
}


// Called every frame
void UQuestSystem::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}

void UQuestSystem::CheckActiveQuestConditions()
{
	TArray<UQuest*> JustCompletedQuests;
	for (UQuest* Quest : ActiveQuests)
	{
		if (Quest->CheckConditions(GetWorldState()))
		{
			CompletedQuests.Add(Quest);
			JustCompletedQuests.Add(Quest);
			for (TTuple<FString, bool> QuestFlag : Quest->QuestFlagsOnComplete)
			{
				QuestFlags.Add(QuestFlag.Key, QuestFlag.Value);
			}
			QuestCompletionTitle->SetText(Quest->Title);
			if (Quest->QuestLine == EQuestLine::Sub)
			{
				bHasSubQuest = false;
				SubQuestBorder->SetVisibility(ESlateVisibility::Hidden);
			}
			if (Quest->bShowQuestCompletedNotification)
			{
				FOutputDeviceNull AR;
				const FString Command = FString::Printf(TEXT("PlayCompletedQuestAnimation"));
				QuestCompletionWidgetInstance->CallFunctionByNameWithArguments(*Command, AR, nullptr, true);
			}
		}
		UpdateQuestGoalsUI(Quest);
	}
	for (UQuest* Quest : JustCompletedQuests)
	{
		ActiveQuests.Remove(Quest);
		Quest->ApplyRewards(PlayerInventory);
	}
}

UWorldState* UQuestSystem::GetWorldState() const
{
	UWorldState* WorldState = NewObject<UWorldState>();
	WorldState->Items = PlayerInventory->Items;
	WorldState->QuestFlags = QuestFlags;
	return WorldState;
}

bool UQuestSystem::AddQuest(UQuest* Quest)
{
	if (HasActiveQuest(Quest)) return false;
	if (!Quest->CheckPreConditions(GetWorldState())) return false;
	ActiveQuests.Add(Quest);
	for (TTuple<FString, bool> QuestFlag : Quest->QuestFlagsOnAdd)
	{
		QuestFlags.Add(QuestFlag.Key, QuestFlag.Value);
	}
	if (Quest->QuestLine == EQuestLine::Sub)
	{
		bHasSubQuest = true;
		SubQuestBorder->SetVisibility(ESlateVisibility::Visible);
		SubQuestTitle->SetText(Quest->Title);
		UpdateQuestGoalsUI(Quest);
	}
	else if (Quest->QuestLine == EQuestLine::Main)
	{
		MainQuestTitle->SetText(Quest->Title);
		UpdateQuestGoalsUI(Quest);
	}
	return true;
}

void UQuestSystem::AddQuestFlag(const FString FlagName, const bool FlagValue)
{
	if (HasQuestFlag(FlagName))
	{
		QuestFlags[FlagName] = FlagValue;
	}
	else
	{
		QuestFlags.Add(FlagName, FlagValue);
	}
	CheckActiveQuestConditions();
}

bool UQuestSystem::CheckPreConditions(UQuest* Quest) const
{
	if (Quest->CheckPreConditions(GetWorldState())) return true;
	return false;
}

bool UQuestSystem::HasActiveQuest(UQuest* Quest) const
{
	if (ActiveQuests.Contains(Quest)) return true;
	return false;
}

bool UQuestSystem::HasQuestFlag(FString FlagName) const
{
	if (QuestFlags.Contains(FlagName)) return true;
	return false;
}

void UQuestSystem::UpdateQuestGoalsUI(const UQuest* Quest) const
{
	FString GoalsText;
	if (!Quest->Goals->QuestFlags.IsEmpty())
	{
		for (TTuple<FString, bool> QuestFlag : Quest->Goals->QuestFlags)
		{
			if (Quest->FlagTrueMatch(GetWorldState(), QuestFlag.Key))
			{
				GoalsText += FString::Printf(TEXT("- <Strike>%s</>\n"), *QuestFlag.Key);
			}
			else
			{
				GoalsText += FString::Printf(TEXT("- %s\n"), *QuestFlag.Key);
			}
		}
	}
	if (!Quest->Goals->Items.IsEmpty())
	{
		for (UBaseItem* Item : Quest->Goals->Items)
		{
			FString Left, Right;
			Quest->GetItemCountAndGoalAmount(GetWorldState(), Item).Split("/", &Left, &Right);
			if (FCString::Atoi(*Left) >= FCString::Atoi(*Right))
			{
				GoalsText += FString::Printf(TEXT("- <Strike>%s %s</>\n"), *Quest->GetItemCountAndGoalAmount(GetWorldState(), Item), *Item->ItemDisplayName.ToString());
			}
			else
			{
				GoalsText += FString::Printf(TEXT("- %s %s\n"), *Quest->GetItemCountAndGoalAmount(GetWorldState(), Item), *Item->ItemDisplayName.ToString());
			}
		}
	}
	if (Quest->QuestLine == EQuestLine::Main) MainQuestGoals->SetText(FText::FromString(GoalsText));
	else if (Quest->QuestLine == EQuestLine::Sub) SubQuestGoals->SetText(FText::FromString(GoalsText));
}