#pragma once

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


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

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

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

	UPROPERTY(EditAnywhere, meta=(Description="Name of the new event dispatcher"))
	FString Dispatcher;

	UPROPERTY(EditAnywhere, meta=(Description="Input Variables, one per line, expressed as: type var = value"))
	FString InputVariables;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Add a new event dispatcher to a Blueprint."));
	}
	virtual void Handle() override
	{
		WingFetcher F;
		UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
		if (!BP) return;

		// Check for valid proposed name
		FName InternalID = WingUtils::CheckProposedName(Dispatcher);
		if (InternalID.IsNone()) return;
		TSet<FName> Names;
		FBlueprintEditorUtils::GetClassVariableList(BP, Names);
		if (!WingUtils::FindNoDuplicateName(Names, InternalID, TEXT("variable or component"))) return;

		// Parse the arguments.
		WingVariables Vars;
		if (!Vars.InputVariables.ParseString(InputVariables)) return;

		// Add the delegate variable
		FEdGraphPinType DelegateType;
		DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate;
		if (!FBlueprintEditorUtils::AddMemberVariable(BP, InternalID, DelegateType))
		{
			UWingServer::Printf(TEXT("ERROR: Failed to add event dispatcher '%s' to %s\n"), *Dispatcher, *WingUtils::FormatName(BP));
			return;
		}

		// Create the signature graph
		const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
		UEdGraph* SigGraph = FBlueprintEditorUtils::CreateNewGraph(BP, InternalID,
			UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
		if (!SigGraph)
		{
			UWingServer::Printf(TEXT("ERROR: Failed to create signature graph for '%s'\n"), *Dispatcher);
			return;
		}

		SigGraph->bEditable = false;
		K2Schema->CreateDefaultNodesForGraph(*SigGraph);
		K2Schema->CreateFunctionGraphTerminators(*SigGraph, static_cast<UClass*>(nullptr));
		K2Schema->AddExtraFunctionFlags(SigGraph, FUNC_BlueprintCallable | FUNC_BlueprintEvent | FUNC_Public);
		K2Schema->MarkFunctionEntryAsEditable(SigGraph, true);
		BP->DelegateSignatureGraphs.Add(SigGraph);

		// Store the function arguments
		if (!Vars.SetBackingStore(SigGraph)) return;
		if (!Vars.Check()) return;
		if (!Vars.Create()) return;
		UWingServer::Printf(TEXT("Created event dispatcher %s in %s\n"), *Dispatcher, *WingUtils::FormatName(BP));
	}
};
