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


#include "DialogueNPC.h"
#include "Blueprint/UserWidget.h"
#include "Components/TextBlock.h"
#include "GameFramework/Character.h"
#include "Kismet/KismetStringLibrary.h"
#include "Misc/OutputDeviceNull.h"
#include "the_twilight_abyss/Quest/QuestSystem.h"

// Sets default values for this component's properties
UDialogueNPC::UDialogueNPC()
{
	// 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> DialogueWidgetClass(TEXT("/Game/Dialogue/TextPrompt"));
	DialogueWidget = DialogueWidgetClass.Class;
}


// Called when the game starts
void UDialogueNPC::BeginPlay()
{
	Super::BeginPlay();

	DialogueWidgetInstance = CreateWidget<UUserWidget>(GetWorld(), DialogueWidget);

	NPCNameText = Cast<UTextBlock>(DialogueWidgetInstance->GetWidgetFromName("Text_Name"));
	DialogueText = Cast<UTextBlock>(DialogueWidgetInstance->GetWidgetFromName("Text_Dialogue"));
	NextButton = Cast<UButton>(DialogueWidgetInstance->GetWidgetFromName("Button_Next"));
	NextButton->OnClicked.AddDynamic(this, &UDialogueNPC::NextDialogue);
	NPCPortraitImage = Cast<UImage>(DialogueWidgetInstance->GetWidgetFromName("Image_Portrait"));
	if (IsValid(NPCPortrait)) NPCPortraitImage->SetBrushFromTexture(NPCPortrait);

	Choice1Button = Cast<UButton>(DialogueWidgetInstance->GetWidgetFromName("Button_Choice1"));
	Choice1Button->OnClicked.AddDynamic(this, &UDialogueNPC::Choice1);
	Choice2Button = Cast<UButton>(DialogueWidgetInstance->GetWidgetFromName("Button_Choice2"));
	Choice2Button->OnClicked.AddDynamic(this, &UDialogueNPC::Choice2);
	Choice3Button = Cast<UButton>(DialogueWidgetInstance->GetWidgetFromName("Button_Choice3"));
	Choice3Button->OnClicked.AddDynamic(this, &UDialogueNPC::Choice3);
	Choice1Text = Cast<UTextBlock>(DialogueWidgetInstance->GetWidgetFromName("Text_Choice1"));
	Choice2Text = Cast<UTextBlock>(DialogueWidgetInstance->GetWidgetFromName("Text_Choice2"));
	Choice3Text = Cast<UTextBlock>(DialogueWidgetInstance->GetWidgetFromName("Text_Choice3"));
	NextArrow = Cast<UTextBlock>(DialogueWidgetInstance->GetWidgetFromName("NextArrow"));
}


void UDialogueNPC::NextDialogue()
{
	if (NextArrow->GetVisibility() == ESlateVisibility::Hidden) return;
	//Dialogue Skip
	if (CurrentDialogue.Len() < CurrentDialogueStringPath[DialogueIndex].Len())
	{
		CurrentDialogue = CurrentDialogueStringPath[DialogueIndex];
		DialogueText->SetText(FText::FromString(CurrentDialogue));
		return;
	}
	if (CurrentDialogueStringPath[FMath::Clamp(DialogueIndex + 1, 0, CurrentDialogueStringPath.Num() - 1)].Mid(0, 2) == "##")
	{
		Cast<UQuestSystem>(GetWorld()->GetFirstPlayerController()->GetPawn()->GetComponentByClass(UQuestSystem::StaticClass()))->AddQuest(Quests[UKismetStringLibrary::Conv_StringToInt(CurrentDialogueStringPath[DialogueIndex].RightChop(3))]);
		DialogueIndex++;
	}

	DialogueIndex++;
	if (DialogueIndex >= CurrentDialogueStringPath.Num())
	{
		if (CurrentDialoguePath->Choices.IsEmpty())
		{
			EndDialogue();
			return;
		}
		GetWorld()->GetTimerManager().PauseTimer(TextAnimationTimerHandle);
		DialogueText->SetText(FText::FromString(""));
		Choice1Button->SetVisibility(ESlateVisibility::Visible);
		Choice2Button->SetVisibility(ESlateVisibility::Visible);
		if (Choice3Text->GetText().ToString() != "") Choice3Button->SetVisibility(ESlateVisibility::Visible);
		NextArrow->SetVisibility(ESlateVisibility::Hidden);
		return;
	}
	CurrentDialogue = "";
}

void UDialogueNPC::NextCharacter()
{
	if (DialogueIndex >= CurrentDialogueStringPath.Num()) return;

	if (CurrentDialogue.Len() < CurrentDialogueStringPath[DialogueIndex].Len())
	{
		CurrentDialogue.AppendChar(CurrentDialogueStringPath[DialogueIndex][CurrentDialogue.Len()]);
		DialogueText->SetText(FText::FromString(CurrentDialogue));
	}
}

void UDialogueNPC::ResetDialogueUI()
{
	DialogueIndex = 0;
	CurrentDialogue = "";
	CurrentDialogueStringPath = CurrentDialoguePath->Dialogue;
	GetWorld()->GetTimerManager().UnPauseTimer(TextAnimationTimerHandle);
	Choice1Button->SetVisibility(ESlateVisibility::Hidden);
	Choice2Button->SetVisibility(ESlateVisibility::Hidden);
	Choice3Button->SetVisibility(ESlateVisibility::Hidden);
	NextArrow->SetVisibility(ESlateVisibility::Visible);
}

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

	// ...
}

void UDialogueNPC::StartDialogue()
{
	Quests.Empty();
	FOutputDeviceNull AR;
	const FString Command = FString::Printf(TEXT("SetRootDialoguePath"));
	GetOwner()->CallFunctionByNameWithArguments(*Command, AR, nullptr, true);
	if (IsValid(RootDialoguePath)) CurrentDialogueStringPath = RootDialoguePath->Dialogue;
	if (CurrentDialogueStringPath.IsEmpty())
	{
		UE_LOG(LogTemp, Warning, TEXT("Dialogue Path is Empty"));
		return;
	}
	//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;

	Choice1Button->SetVisibility(ESlateVisibility::Hidden);
	Choice2Button->SetVisibility(ESlateVisibility::Hidden);
	Choice3Button->SetVisibility(ESlateVisibility::Hidden);
	DialogueText->SetText(FText::FromString(""));
	DialogueWidgetInstance->AddToViewport();
	NPCNameText->SetText(FText::FromString(NPCName));
	DialogueIndex = 0;
	CurrentDialogue = "";
	CurrentDialoguePath = RootDialoguePath;
	CurrentDialogueStringPath = RootDialoguePath->Dialogue;
	GetWorld()->GetTimerManager().SetTimer(TextAnimationTimerHandle, this, &UDialogueNPC::NextCharacter, TextAnimationSpeed, true);
}

void UDialogueNPC::EndDialogue()
{
	TextAnimationTimerHandle.Invalidate();
	DialogueWidgetInstance->RemoveFromParent();

	//Enable Character Movement
	if (ACharacter* PlayerCharacter = Cast<ACharacter>(GetWorld()->GetFirstPlayerController()->GetPawn()))
	{
		PlayerCharacter->EnableInput(GetWorld()->GetFirstPlayerController());
	}
	//Reset UI Mode
	APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
	PlayerController->SetInputMode(FInputModeGameOnly());
	PlayerController->bShowMouseCursor = false;
}

UDialoguePath* UDialogueNPC::CreateRootDialoguePath()
{
	return NewObject<UDialoguePath>();
}

UDialoguePath* UDialogueNPC::AddDialogue(UDialoguePath* DialoguePath, FText TextInput)
{
	if (TextInput.IsEmpty()) return DialoguePath;
	DialoguePath->Dialogue.Add(TextInput.ToString());
	return DialoguePath;
}

void UDialogueNPC::AddChoices(UDialoguePath* ParentPath, FText ChoiceText1, FText ChoiceText2, FText ChoiceText3, UDialoguePath*& Out_ChoicePath1, UDialoguePath*& Out_ChoicePath2, UDialoguePath*& Out_ChoicePath3)
{
	ParentPath->Choices.Add(NewObject<UDialoguePath>());
	ParentPath->Choices.Add(NewObject<UDialoguePath>());
	ParentPath->Choices.Add(NewObject<UDialoguePath>());
	Out_ChoicePath1 = ParentPath->Choices[0];
	Out_ChoicePath2 = ParentPath->Choices[1];
	Out_ChoicePath3 = ParentPath->Choices[2];
	Choice1Text->SetText(ChoiceText1);
	Choice2Text->SetText(ChoiceText2);
	Choice3Text->SetText(ChoiceText3);
}

UDialoguePath* UDialogueNPC::AddQuest(UDialoguePath* DialoguePath, UQuest* Quest)
{
	DialoguePath->Dialogue.Add(FText::FromString("## " + Quests.Num()).ToString());
	Quests.Add(Quests.Num(), Quest);
	return DialoguePath;
}

void UDialogueNPC::Choice1()
{
	CurrentDialoguePath = CurrentDialoguePath->Choices[0];
	ResetDialogueUI();
}

void UDialogueNPC::Choice2()
{
	CurrentDialoguePath = CurrentDialoguePath->Choices[1];
	ResetDialogueUI();
}

void UDialogueNPC::Choice3()
{
	CurrentDialoguePath = CurrentDialoguePath->Choices[2];
	ResetDialogueUI();
}