// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.

#include "Nodes/ComboActionGraphNode.h"

#include "ComboActionGraph.h"
#include "ComboInputAssets.h"
#include "ComboInputTriggers.h"

#include "Data/ComboActionContext.h"
#include "Decorators/ComboActionDecoratorBase.h"
#include "Interfaces/ComboActionGraphManagerInterface.h"

DEFINE_LOG_CATEGORY(LogComboActionGraphNode);

#define LOCTEXT_NAMESPACE "ComboActionGraphNode"


UComboActionGraphNode::UComboActionGraphNode()
{
	this->NodeGUID = FGuid::NewGuid();

#if WITH_EDITORONLY_DATA
	this->CompatibleGraphType = UComboActionGraph::StaticClass();

	this->BackgroundColor = FLinearColor::Black;

	this->bAllowInputNodes = true;
	this->bAllowOutputNodes = true;

	this->bAllowCopy = true;
	this->bAllowCut = true;
	this->bAllowDelete = true;
	this->bAllowPaste = true;
	this->bAllowManualCreate = true;

	this->NodeTypeName = LOCTEXT("ComboActionGraphNode_InternalName", "ComboActionGraphNode");
	this->NodeTooltipText = LOCTEXT("ComboActionGraphNode_Tooltip", "Combo action graph base node. Child nodes provide more information.");
#endif
}

void UComboActionGraphNode::SetNewWorld(UWorld *NewWorld)
{
	if (!NewWorld) return;
	if (NewWorld == this->OwningWorld) return;

	this->OwningWorld = NewWorld;
}

void UComboActionGraphNode::InitializeNode_Implementation(UWorld *InWorld)
{
	this->SetNewWorld(InWorld);

	if (this->Graph)
	{
		this->SetNodeIndex(this->Graph->AllNodes.Find(this));
	}
}

void UComboActionGraphNode::ProcessNode(const TScriptInterface<IComboActionGraphManagerInterface> &Manager)
{
	if (!this->GetWorld())
	{
		UE_LOG(LogComboActionGraphNode, Error, TEXT("[ProcessNode] Cannot find World!"));
		return;
	}

	if (!this->GetGraph())
	{
		UE_LOG(LogComboActionGraphNode, Error, TEXT("[ProcessNode] Invalid owning Graph!!"));
		return;
	}
	
	//UComboActionContext *Context = Manager->GetDialogueContext();
	//if (!Context || !UComboActionSystemBFC::IsContextValid(Context))
	//{
	//	Manager->GetDialogueFailedEventHandle().Broadcast(TEXT("[ProcessNode] Invalid Dialogue Context!!"));
	//	return;
	//}
	//
	//UComboActionSystemBFC::ExecuteDecorators(this, Context);
	//
	//Manager->GetDialogueNodeStartedEventHandle().Broadcast(Context);
}

void UComboActionGraphNode::SetNodeIndex(const int32 NewIndex)
{
	check(NewIndex>INDEX_NONE);
	this->NodeIndex = NewIndex;
}

#if WITH_EDITOR

FText UComboActionGraphNode::GetDescription_Implementation() const
{
	return LOCTEXT("NodeDesc", "Mountea Dialogue Graph Node");
}

FText UComboActionGraphNode::GetNodeCategory_Implementation() const
{
	return LOCTEXT("NodeCategory", "Mountea Dialogue Tree Node");
}

FString UComboActionGraphNode::GetNodeDocumentationLink_Implementation() const
{
	return TEXT("A link to the documentation for this plugin will go here.");
}

FText UComboActionGraphNode::GetNodeTooltipText_Implementation() const
{
	return FText::Format(LOCTEXT("ComboActionGraphNode_FinalTooltip", "{0}\n\n{1}"), this->GetDefaultTooltipBody(), this->NodeTooltipText);
}

bool UComboActionGraphNode::CanCreateConnection(UComboActionGraphNode *Other, enum EEdGraphPinDirection Direction, FText &ErrorMessage)
{
	if (Other == nullptr)
	{
		ErrorMessage = FText::FromString("Invalid Other Node!");
	}

	if (Other->GetMaxChildNodes() > -1 && Other->ChildrenNodes.Num() >= Other->GetMaxChildNodes())
	{
		const FString TextReturn =
		FString(Other->GetNodeTitle().ToString()).
		Append(": Cannot have more than ").Append(FString::FromInt(Other->GetMaxChildNodes())).Append(" Children Nodes!");

		ErrorMessage = FText::FromString(TextReturn);
		return false;
	}

	if (Direction == EEdGraphPinDirection::EGPD_Output)
	{
		
		// Fast checking for native classes
		if ( AllowedInputClasses.Contains(Other->GetClass()) )
		{
			return true;
		}

		// Slower iterative checking for child classes
		for (auto Itr : AllowedInputClasses)
		{
			if (Other->GetClass()->IsChildOf(Itr))
			{
				return true;
			}
		}
		
		ErrorMessage = FText::FromString("Invalid Node Connection!");
		return false;
	}

	return true;
}

bool UComboActionGraphNode::ValidateNode(TArray<FText> &ValidationsMessages, const bool RichFormat)
{
	bool bResult = true;

	if (this->ParentNodes.Num() == 0 && this->ChildrenNodes.Num() == 0)
	{
		bResult = false;
		
		const FString RichTextReturn =
			FString("* ")
			.Append("<RichTextBlock.Bold>")
			.Append(this->NodeTitle.ToString())
			.Append("</>")
			.Append(": This Node has no Connections!");

		const FString TextReturn =
			FString(this->NodeTitle.ToString())
			.Append(": This Node has no Connections!");
		
		ValidationsMessages.Add(FText::FromString(RichFormat ? RichTextReturn : TextReturn));
	}

	if (this->bAllowInputNodes && this->ParentNodes.Num() == 0)
	{
		bResult = false;
		
		const FString RichTextReturn =
			FString("* ")
			.Append("<RichTextBlock.Bold>")
			.Append(this->NodeTitle.ToString())
			.Append("</>")
			.Append(": This node requires inputs, however none are found!");
		
		const FString TextReturn =
			FString(this->NodeTitle.ToString())
			.Append(": This node requires inputs, however none are found!");
		
		ValidationsMessages.Add(FText::FromString(RichFormat ? RichTextReturn : TextReturn));
	}
	
	return bResult;
}

void UComboActionGraphNode::OnPasted()
{
	this->NodeGUID = FGuid::NewGuid();

	this->ParentNodes.Empty();
	this->ChildrenNodes.Empty();
	this->Edges.Empty();
}

FText UComboActionGraphNode::GetDefaultTooltipBody() const
{
	//const FText Inherits = FText::Format(LOCTEXT("UComboActionGraphNode_InheritsTooltip", "Inherits Graph Decorators: {0}"), InheritsValue);
	//const FText Implements = FText::Format(LOCTEXT("UComboActionGraphNode_ImplementsTooltip", "Implements Decorators: {0}"), ImplementsNumber);
	return FText::Format(LOCTEXT("UComboActionGraphNode_BaseTooltip", "{0}\n\n{1}\n{2}"), this->NodeTypeName, this->NodeTypeName, this->NodeTypeName);
}

#endif

#undef LOCTEXT_NAMESPACE
