#pragma once

#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingBasics.h"
#include "WingFetcher.h"
#include "WingUtils.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphSchema.h"
#include "EdGraph/EdGraphPin.h"
#include "GraphPin_Connect.generated.h"


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

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

	UPROPERTY(EditAnywhere, meta=(Description="Alternating source pin / target pin strings"))
	FWingRestOfArgv SourcePin_TargetPin;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Connect pins between nodes in a graph (Blueprint or Material). "
			     "Pin IDs use fetcher path syntax relative to the graph, eg: "
			     "node:K2Node_CallFunction_0,pin:ReturnValue"));
	}
	virtual void Handle() override
	{
		WingFetcher F(WingOut::Stdout);
		UEdGraph* G = F.Walk(GraphPath).Cast<UEdGraph>();
		if (!G) return;

		if ((SourcePin_TargetPin.Argv.Num() % 2) != 0)
		{
			WingOut::Stdout.Print(TEXT("ERROR: SourcePin_TargetPin must contain an even number of arguments.\n"));
			return;
		}

		int32 SuccessCount = 0;
		int32 TotalCount = SourcePin_TargetPin.Argv.Num() / 2;
		for (int32 I = 0; I < SourcePin_TargetPin.Argv.Num(); I += 2)
		{
			const FString& SourcePinPath = SourcePin_TargetPin.Argv[I];
			const FString& TargetPinPath = SourcePin_TargetPin.Argv[I + 1];

			WingFetcher FS(G, WingOut::Stdout);
			UWingGraphPinRef* SourcePinRef = FS.Walk(SourcePinPath).Cast<UWingGraphPinRef>();
			if (!SourcePinRef) continue;
			UEdGraphPin* SourcePin = WingUtils::CheckGetPin(SourcePinRef->Node, SourcePinRef->PinName, WingOut::Stdout);
			if (!SourcePin) continue;

			WingFetcher FT(G, WingOut::Stdout);
			UWingGraphPinRef* TargetPinRef = FT.Walk(TargetPinPath).Cast<UWingGraphPinRef>();
			if (!TargetPinRef) continue;
			UEdGraphPin* TargetPin = WingUtils::CheckGetPin(TargetPinRef->Node, TargetPinRef->PinName, WingOut::Stdout);
			if (!TargetPin) continue;

			const UEdGraphSchema* Schema = G->GetSchema();
			const FPinConnectionResponse Response = Schema->CanCreateConnection(SourcePin, TargetPin);
			if (Response.Response == CONNECT_RESPONSE_DISALLOW)
			{
				WingOut::Stdout.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++;
		}

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