#pragma once

#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingFetcher.h"
#include "WingUtils.h"
#include "WingVariables.h"
#include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h"
#include "EdGraphSchema_K2.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "BlueprintGraph_Create.generated.h"


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------

UCLASS()
class UWing_BlueprintGraph_Create : public UWingHandler
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, meta=(Description="Blueprint name or package path"))
	FString Blueprint;

	UPROPERTY(EditAnywhere, meta=(Description="Name for the new graph"))
	FString Graph;

	UPROPERTY(EditAnywhere, meta=(Description="Type of graph: function or macro"))
	FString GraphType;

	UPROPERTY(meta=(Optional, Description="Input variables, one per line"))
	FString InputVariables;

	UPROPERTY(meta=(Optional, Description="Output variables, one per line"))
	FString OutputVariables;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Create a new function or macro graph in a Blueprint."));
	}
	virtual void Handle() override
	{
		if (GraphType != TEXT("function") && GraphType != TEXT("macro"))
		{
			UWingServer::Printf(TEXT("ERROR: Invalid GraphType '%s'. Valid values: function, macro\n"), *GraphType);
			return;
		}

		WingFetcher F;
		UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
		if (!BP) return;

		// Check that this graph type is valid for this blueprint type
		if (BP->BlueprintType == BPTYPE_Interface)
		{
			UWingServer::Print(TEXT("ERROR: Cannot add graphs to interface blueprints.\n"));
			return;
		}
		if (BP->BlueprintType == BPTYPE_MacroLibrary && GraphType == TEXT("function"))
		{
			UWingServer::Print(TEXT("ERROR: Macro libraries cannot contain functions.\n"));
			return;
		}
		if (BP->BlueprintType == BPTYPE_FunctionLibrary && GraphType == TEXT("macro"))
		{
			UWingServer::Print(TEXT("ERROR: Function libraries cannot contain macros.\n"));
			return;
		}

		// Check graph name uniqueness and legality
		FName InternalID = WingUtils::CheckProposedName(Graph);
		if (InternalID.IsNone()) return;
		if (!WingUtils::FindNoneWithInternalID(InternalID, WingUtils::AllGraphs(BP), TEXT("Graph")))
			return;

		// Parse and validate variables before making changes
		WingVariables Vars;
		if (!Vars.InputVariables.ParseString(InputVariables)) return;
		if (!Vars.OutputVariables.ParseString(OutputVariables)) return;

		// Create the Graph
		UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(BP, InternalID,
				UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
		if (!NewGraph)
		{
			UWingServer::Print(TEXT("ERROR: Failed to create graph\n"));
			return;
		}

		if (GraphType == TEXT("function"))
		{
			FBlueprintEditorUtils::AddFunctionGraph(BP, NewGraph, /*bIsUserCreated=*/true, /*SignatureFromObject=*/static_cast<UClass*>(nullptr));
			FBlueprintEditorUtils::FindOrCreateFunctionResultNode(FBlueprintEditorUtils::GetEntryNode(NewGraph));
		}
		else if (GraphType == TEXT("macro"))
		{
			FBlueprintEditorUtils::AddMacroGraph(BP, NewGraph, /*bIsUserCreated=*/true, /*SignatureFromClass=*/nullptr);
		}

		// Create the variables on the new graph
		if (!Vars.SetBackingStore(NewGraph)) return;
		if (!Vars.Check()) return;
		if (!Vars.Create()) return;

		UWingServer::Printf(TEXT("Created %s graph: %s\n"), *GraphType, *WingUtils::FormatName(NewGraph));
	}
};
