#pragma once

#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingFetcher.h"
#include "WingProperty.h"
#include "WingUtils.h"
#include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphPin.h"
#include "EdGraphSchema_K2.h"
#include "GraphPin_Connect.generated.h"


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

USTRUCT()
struct FConnectPinsEntry
{
	GENERATED_BODY()

	UPROPERTY()
	FString SourcePin;

	UPROPERTY()
	FString TargetPin;
};


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

public:
	UPROPERTY(EditAnywhere, meta=(Description="Target graph"))
	FString Graph;

	UPROPERTY(EditAnywhere, meta=(Description="Array of {sourcePin, targetPin} objects"))
	FWingJsonArray Connections;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Connect pins between nodes in a graph (Blueprint or Material)."));
	}
	virtual void Handle() override
	{
		WingFetcher F;
		UEdGraph* G = F.Walk(Graph).Cast<UEdGraph>();
		if (!G) return;

		int32 SuccessCount = 0;
		int32 TotalCount = Connections.Array.Num();

		for (const TSharedPtr<FJsonValue>& ConnVal : Connections.Array)
		{
			FConnectPinsEntry Entry;
			if (!FWingProperty::PopulateFromJson(FConnectPinsEntry::StaticStruct(), &Entry, ConnVal))
				continue;

			WingFetcher FS(G);
			UEdGraphPin* SourcePin = FS.Walk(Entry.SourcePin).Cast<UEdGraphPin>();
			if (!SourcePin) continue;

			WingFetcher FT(G);
			UEdGraphPin* TargetPin = FT.Walk(Entry.TargetPin).Cast<UEdGraphPin>();
			if (!TargetPin) continue;

			const UEdGraphSchema* Schema = G->GetSchema();
			const FPinConnectionResponse Response = Schema->CanCreateConnection(SourcePin, TargetPin);
			if (Response.Response == CONNECT_RESPONSE_DISALLOW)
			{
				UWingServer::Printf(TEXT("error: Cannot connect %s.%s to %s.%s: %s\n"),
					*WingUtils::FormatName(SourcePin->GetOwningNode()), *WingUtils::FormatName(SourcePin),
					*WingUtils::FormatName(TargetPin->GetOwningNode()), *WingUtils::FormatName(TargetPin),
					*Response.Message.ToString());
				continue;
			}

			Schema->TryCreateConnection(SourcePin, TargetPin);
			SuccessCount++;
		}

		UWingServer::Printf(TEXT("Connected %d/%d pins.\n"), SuccessCount, TotalCount);
	}
};
