/**
 * Copyright 2022-2025 Theai, Inc. dba Inworld AI
 */
#pragma once

#include "CoreMinimal.h"
#include "Graph/Assets/InworldEdgeAsset.h"
#include "Graph/Assets/InworldGraphAsset.h"
#include "Graph/Assets/InworldNodeAsset.h"
#include "EdGraph/EdGraphSchema.h"
#include "Runtime/Launch/Resources/Version.h"

#include "AssetGraphSchema_InworldGraph.generated.h"

class UEdNode_InworldGraphNode;
class UEdNode_InworldGraphEdge;
class UAutoLayoutStrategy;


USTRUCT()
struct INWORLDRUNTIMEEDITOR_API FAssetSchemaAction_InworldGraph_AddComment : public FEdGraphSchemaAction
{
	GENERATED_BODY()
	
	FAssetSchemaAction_InworldGraph_AddComment() : FEdGraphSchemaAction() {}
	FAssetSchemaAction_InworldGraph_AddComment(const FText& InNodeCategory, const FText& InMenuDesc, const FText& InToolTip, const int32 InGrouping)
		: FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping)
	{
	}

	// FEdGraphSchemaAction interface
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 6
	virtual UEdGraphNode* PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode = true) override ;
#else
	virtual UEdGraphNode* PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2f& Location, bool bSelectNewNode = true) override;
#endif
	// End of FEdGraphSchemaAction interface
};

/** Action to add a node to the graph */
USTRUCT()
struct INWORLDRUNTIMEEDITOR_API FAssetSchemaAction_InworldGraph_NewNode : public FEdGraphSchemaAction
{
	GENERATED_USTRUCT_BODY();

public:
	FAssetSchemaAction_InworldGraph_NewNode() : NodeTemplate(nullptr)
	{
	}

	FAssetSchemaAction_InworldGraph_NewNode(const FText& InNodeCategory, const FText& InMenuDesc, const FText& InToolTip, const int32 InGrouping)
		: FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr)
	{
	}

	virtual UEdGraphNode* PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode = true) override;
	virtual void AddReferencedObjects(FReferenceCollector& Collector) override;

	UPROPERTY()
	TObjectPtr<UEdNode_InworldGraphNode> NodeTemplate;

	UPROPERTY()
	TObjectPtr<UInworldGraphAsset> SubgraphAsset;
};

USTRUCT()
struct INWORLDRUNTIMEEDITOR_API FAssetSchemaAction_InworldGraph_NewEdge : public FEdGraphSchemaAction
{
	GENERATED_USTRUCT_BODY();

public:
	FAssetSchemaAction_InworldGraph_NewEdge() : NodeTemplate(nullptr)
	{
	}

	FAssetSchemaAction_InworldGraph_NewEdge(const FText& InNodeCategory, const FText& InMenuDesc, const FText& InToolTip, const int32 InGrouping)
		: FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr)
	{
	}

	// adding nodes
	virtual UEdGraphNode* PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode = true) override;
	virtual void AddReferencedObjects(FReferenceCollector& Collector) override;

	UPROPERTY()
	TObjectPtr<UEdNode_InworldGraphEdge> NodeTemplate;
};

UCLASS(MinimalAPI)
class UAssetGraphSchema_InworldGraph : public UEdGraphSchema
{
	GENERATED_BODY()

public:
	void GetBreakLinkToSubMenuActions(class UToolMenu* Menu, class UEdGraphPin* InGraphPin);
	void CopyNodeId(UEdNode_InworldGraphNode* Node);
	void SetNodeAsStart(UEdNode_InworldGraphNode* Node);
	void SetNodeAsEnd(UEdNode_InworldGraphNode* Node);
	void SetNodeAsStartEnd(UEdNode_InworldGraphNode* Node);
	void RebuildNode(UEdNode_InworldGraphNode* Node);

	void SetEdgeType(UEdGraphNode* Edge, UClass* EdgeType);

	virtual EGraphType GetGraphType(const UEdGraph* TestEdGraph) const override;

	// Get all actions that can be performed when right clicking on a graph or drag-releasing on a graph from a pin
	virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override;

	// Gets actions that should be added to the right-click context menu for a node or pin
	virtual void GetContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override;

	virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override;

	virtual bool TryCreateConnection(UEdGraphPin* A, UEdGraphPin* B) const override;
	virtual bool CreateAutomaticConversionNodeAndConnections(UEdGraphPin* A, UEdGraphPin* B) const override;

	virtual class FConnectionDrawingPolicy* CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID,
		float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements,
		class UEdGraph* InGraphObj) const override;

	virtual FLinearColor GetPinTypeColor(const FEdGraphPinType& PinType) const override;

	virtual void BreakNodeLinks(UEdGraphNode& TargetNode) const override;

	virtual void BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin) const override;

	virtual UEdGraphPin* DropPinOnNode(UEdGraphNode* InTargetNode, const FName& InSourcePinName,
		const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection) const override;

	virtual bool SupportsDropPinOnNode(UEdGraphNode* InTargetNode, const FEdGraphPinType& InSourcePinType,
		EEdGraphPinDirection InSourcePinDirection, FText& OutErrorMessage) const override;

	virtual bool IsCacheVisualizationOutOfDate(int32 InVisualizationCacheID) const override;

	virtual int32 GetCurrentVisualizationCacheID() const override;

	virtual void ForceVisualizationCacheClear() const override;

	virtual TSharedPtr<FEdGraphSchemaAction> GetCreateCommentAction() const override;

private:
	static int32 CurrentCacheRefreshID;
};
