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

#pragma once

#include "CoreMinimal.h"

#include "GameplayTagContainer.h"
#include "Decorators/ComboActionDecoratorBase.h"

#include "ComboActionGraph.generated.h"

DECLARE_LOG_CATEGORY_EXTERN(LogComboActionGraph, Log, All);


/**
 * Combo Action graph.
 * 
 * Can be manually created from Content Browser, using Combo Action category.
 * Comes with a node editor, which provides easy to follow visual way to create combo strings.
 */
UCLASS(BlueprintType, ClassGroup=("Combo Input|Action"), DisplayName="Combo Action Tree", HideCategories=("Hidden", "Private", "Base"), AutoExpandCategories=("Combo Input", "Action"))
class COMBOINPUT_API UComboActionGraph : public UObject
{
	GENERATED_BODY()

public:

	UComboActionGraph();

#pragma region Variables
	
protected:
	/**
	 * A set of gameplay tags associated with this dialogue graph.
	 */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Combo Input|Action")
		FGameplayTagContainer GraphTags;
	/**
	* GUID for this Mountea Dialogue Graph.
	*❗ Unique identifier for this Dialogue Graph instance.
	*❔ Can be used for debugging and tracing purposes.
	*/
	UPROPERTY(BlueprintReadOnly, Category="Combo Input")
		FGuid GraphGUID;

public:
	
	// Pointer to the starting node of the dialogue graph.
	UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
		class UComboActionGraphNode *StartNode = nullptr;
	/**
	 * The class of the dialogue node represented by this instance.
	 */
	UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
		TSubclassOf<UComboActionGraphNode> NodeType;
	/**
	 * The class of the dialogue edge represented by this instance.
	 */
	UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
		TSubclassOf<UComboActionGraphEdge> EdgeType;
	/**
	 * An array of root nodes in the dialogue graph. These are the nodes that do not have any incoming connections.
	 */
	UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
		TArray<UComboActionGraphNode*> RootNodes;
	/**
	 * Array containing all the nodes in the graph, including both root nodes and child nodes.
	 */
	UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
		TArray<UComboActionGraphNode*> AllNodes;
	// Flag indicating whether an edge is enabled
	UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action")
		bool bEdgeEnabled;

#pragma endregion

#pragma region Functions

public:
	/**
	 * Returns the GUID of the graph.
	 *
	 * @return The GUID of the graph.
	 */
	UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
		FGuid GetGraphGUID() const { return this->GraphGUID; }
	/**
	 * Returns an array containing all nodes in the dialogue graph.
	 * @return An array of all nodes in the dialogue graph.
	 */
	UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
		TArray<UComboActionGraphNode*> GetAllNodes() const { return this->AllNodes; }
	
	UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
		TArray<UComboActionGraphNode*> GetRootNodes() const { return this->RootNodes; }
	/**
	 * Returns the root nodes of the dialogue graph.
	 *
	 * @return An array of all root nodes.
	 */
	UFUNCTION(BlueprintCallable, Category="Combo Input|Action")
		UComboActionGraphNode *GetStartNode() const { return this->StartNode; }
	/**
	 * Determines whether the dialogue graph can be started.
	 * 
	 * @return true if the graph can be started, false otherwise.
	 */
	bool CanStartDialogueGraph() const;
	
public:
	void CreateGraph();
	void ClearGraph();

	FORCEINLINE bool IsEdgeEnabled() const { return bEdgeEnabled; }

	virtual void PostInitProperties() override;

#pragma endregion 

#if WITH_EDITORONLY_DATA

public:
	UPROPERTY()
		class UEdGraph *EdGraph;

	UPROPERTY(BlueprintReadOnly, Category="Combo Input|Action|Editor")
		bool bCanRenameNode;

#endif

#if WITH_EDITOR

	virtual bool ValidateGraph(TArray<FText> &ValidationErrors, bool RichTextFormat);
	virtual EDataValidationResult IsDataValid(TArray<FText> &ValidationErrors) override;

public:

	// Construct and initialize a node within this Dialogue.
	template<class T>
	T* ConstructActionNode(TSubclassOf<class UComboActionGraphNode> DialogueNodeClass = T::StaticClass())
	{
		// Set flag to be transactional so it registers with undo system
		T *ActionNode = NewObject<T>(this, DialogueNodeClass, NAME_None, EObjectFlags::RF_Transactional);
		ActionNode->OnCreatedInEditor();
		return ActionNode;
	}

#endif
};
