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

#pragma once

#include "CoreMinimal.h"

#include "Ed/EdComboActionGraph.h"
#include "Ed/EdComboActionGraphNode.h"
#include "Widgets/Views/STreeView.h"

#define LOCTEXT_NAMESPACE "ComboActionSearchResult"


/**
 * Template Tree Item Node class.
 */
template <class SelfType>
class FComboActionTreeItemNode : public TSharedFromThis<SelfType>
{
	
public:
	FComboActionTreeItemNode(const FText &InDisplayText, const TSharedPtr<SelfType> &InParent) : Parent(InParent), DisplayText(InDisplayText){};
	virtual ~FComboActionTreeItemNode(){};

#pragma region Click_Functions
	
	virtual FReply OnClick(TWeakPtr<FAssetEditor_ComboActionGraph> DialogueEditorPtr)
	{
		// If there is a parent, handle it using the parent's functionality
		if (Parent.IsValid())
		{
			return Parent.Pin()->OnClick(DialogueEditorPtr);
		}

		return FReply::Unhandled();
	}

#pragma endregion

#pragma region DisplayText_Functions

	FText GetDisplayText() const { return this->DisplayText; }
	FName GetDisplayTextAsFName() const { return FName(*this->DisplayText.ToString()); }
	void SetDisplayText(const FText &InText) { this->DisplayText = InText; }
	bool DoesDisplayTextContains(const FString &InSearch, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) const
	{
		return this->DisplayText.ToString().Contains(InSearch, SearchCase);
	}

#pragma endregion

#pragma region Parent_Functions

	bool HasParent() const { return this->Parent.IsValid(); }
	TWeakPtr<SelfType> GetParent() const { return this->Parent; }
	void SetParent(TWeakPtr<SelfType> InParentNode) { this->Parent = InParentNode; }
	void ClearParent() { this->Parent.Reset(); }

#pragma endregion

#pragma region Children_Functions

public:
	
	bool HasChildren() const { return this->Children.Num() > 0; }
	const TArray<TSharedPtr<SelfType>> &GetChildren() const { return this->Children; }
	void GetVisibleChildren(TArray<TSharedPtr<SelfType>> &OutChildren)
	{
		for (const TSharedPtr<SelfType> &Child : this->Children)
		{
			if (Child->IsVisible())
			{
				OutChildren.Add(Child);
			}
		}
	}
	virtual void AddChild(const TSharedPtr<SelfType> &ChildNode)
	{
		ensure(!ChildNode->IsRoot());
		ChildNode->SetParent(this->AsShared());
		this->Children.Add(ChildNode);
	}
	virtual void SetChildren(const TArray<TSharedPtr<SelfType>> &InChildren)
	{
		this->Children = InChildren;
		for (const TSharedPtr<SelfType> &Child : this->Children)
		{
			ensure(!Child->IsRoot());
			Child->SetParent(this->AsShared());
		}
	}
	virtual void ClearChildren()
	{
		this->Children.Empty();
	}

	void ExpandAllChildren(const TSharedPtr<STreeView<TSharedPtr<SelfType>>> &TreeView, bool bRecursive = true)
	{
		static constexpr bool bShouldExpandItem = true;
		if (!HasChildren())
		{
			return;
		}

		TreeView->SetItemExpansion(this->AsShared(), bShouldExpandItem);
		for (const TSharedPtr<SelfType> &ChildNode : this->Children)
		{
			if (bRecursive)
			{
				// recursive on all children.
				ChildNode->ExpandAllChildren(TreeView, bRecursive);
			}
			else
			{
				// Only direct children
				TreeView->SetItemExpansion(ChildNode, bShouldExpandItem);
			}
		}
	}

#pragma endregion

#pragma region Helper_Functions

public:
	bool IsRoot() const { return !this->Parent.IsValid(); }

#pragma endregion 

protected:
	/** Any children listed under this node. */
	TArray<TSharedPtr<SelfType>> Children;

	/** The node that this is a direct child of (empty if this is a root node)  */
	TWeakPtr<SelfType> Parent;

	/** The displayed text for this item. */
	FText DisplayText;

	/** Is this node displayed? */
	bool bIsVisible = true;
};


class FComboActionSearchResult : public FComboActionTreeItemNode<FComboActionSearchResult>
{
public:
	FComboActionSearchResult(const FText &InDisplayText, const TSharedPtr<FComboActionSearchResult> &InParent) : FComboActionTreeItemNode(InDisplayText, InParent){}

public:
	// Create an icon to represent the result
	virtual TSharedRef<SWidget>	CreateIcon() const;

	// Gets the Dialogue housing all these search results. Aka the Dialogue this search result belongs to.
	virtual TWeakObjectPtr<const UComboActionGraph> GetParentDialogue() const;

	// Category:
	FText GetCategory() const { return this->Category; }
	void SetCategory(const FText &InCategory) { this->Category = InCategory; }

	// CommentString
	FString GetCommentString() const { return this->CommentString; }
	void SetCommentString(const FString &InCommentString) { this->CommentString = InCommentString; }

protected:
	// The category of this node.
	FText Category;

	// Display text for comment information
	FString CommentString;
};

// Root Node, should not be displayed.
class FComboActionSearchResult_RootNode : public FComboActionSearchResult
{
public:
	FComboActionSearchResult_RootNode() : FComboActionSearchResult(FText::FromString(TEXT("INVALID")), nullptr) { this->Category = LOCTEXT("ComboActionSearchResult_RootNodeCategory", "Root"); }
};

// Tree Node result that represents the Node
class FComboActionSearchResult_ActionNode : public FComboActionSearchResult
{
public:
	FComboActionSearchResult_ActionNode(const FText &InDisplayText, const TSharedPtr<FComboActionSearchResult> &InParent) : FComboActionSearchResult(InDisplayText, InParent) { this->Category = LOCTEXT("ComboAcitonSearchResult_ActionNodeCategory", "Action Node"); }

	virtual FReply OnClick(TWeakPtr<class FAssetEditor_ComboActionGraph> DialogueEditorPtr) override { return FReply::Unhandled(); }
	virtual TSharedRef<SWidget> CreateIcon() const override { return FComboActionSearchResult::CreateIcon(); }
	virtual TWeakObjectPtr<const UComboActionGraph> GetParentDialogue() const override;
	
	void SetActionGraph(TWeakObjectPtr<const UEdComboActionGraph> InDialogueGraph) { this->ComboActionGraph = InDialogueGraph->GetComboActionGraph(); }

protected:
	TWeakObjectPtr<const UComboActionGraph> ComboActionGraph;
};

// Tree Node result that represents the GraphNode
class FComboActionSearchResult_GraphNode : public FComboActionSearchResult
{
public:
	FComboActionSearchResult_GraphNode(const FText &InDisplayText, const TSharedPtr<FComboActionSearchResult> &InParent) : FComboActionSearchResult(InDisplayText, InParent){}

	virtual FReply OnClick(TWeakPtr<FAssetEditor_ComboActionGraph> ComboActionEditorPtr) override;
	virtual TSharedRef<SWidget> CreateIcon() const override;
	
	void SetGraphNode(TWeakObjectPtr<const UEdComboActionGraphNode> InGraphNode) { this->GraphNode = InGraphNode; }

protected:
	TWeakObjectPtr<const UEdComboActionGraphNode> GraphNode;
};

#undef LOCTEXT_NAMESPACE
