#pragma once

#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingBasics.h"
#include "WingFetcher.h"
#include "WingUtils.h"
#include "WingVariables.h"
#include "Engine/Blueprint.h"
#include "EdGraphSchema_K2.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "EventDispatcher_Add.generated.h"


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

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

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

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

	UPROPERTY(EditAnywhere, meta=(Description="Variables"))
	FWingRestOfArgv Variables;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Add a new event dispatcher to a Blueprint. "
				"Variables must be expressed as 'kind type name (flags) = default'. "
				"Kind can only be 'input'."));

	}
	virtual void Handle() override
	{
		WingFetcher F(WingOut::Stdout);
		UBlueprint* BP = F.Walk(BlueprintPath).Cast<UBlueprint>();
		if (!BP) return;

		// Check for valid proposed name
		TSet<FName> InUse = WingUtils::GetAllInUseNames(BP);
		FName InternalID = WingUtils::CheckProposedName(Dispatcher, InUse, WingOut::Stdout);
		if (InternalID.IsNone()) return;

		// Parse the arguments.
		WingVariables Vars;
		if (!Vars.Parse(Variables.Argv, false, WingOut::Stdout)) return;

		// Add the delegate variable
		FEdGraphPinType DelegateType;
		DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate;
		if (!FBlueprintEditorUtils::AddMemberVariable(BP, InternalID, DelegateType))
		{
			WingOut::Stdout.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)
		{
			WingOut::Stdout.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, WingOut::Stdout)) return;
		if (!Vars.Check(WingOut::Stdout)) return;
		if (!Vars.Create(WingOut::Stdout)) return;
		WingOut::Stdout.Printf(TEXT("Created event dispatcher %s in %s\n"), *Dispatcher, *WingUtils::FormatName(BP));
	}
};
