#pragma once

#include "CoreMinimal.h"
#include "WingBasics.h"
#include "WingFetcher.h"
#include "WingTypes.h"
#include "WingUtils.h"
#include "WingServer.h"
#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "BlueprintInterface_Add.generated.h"


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

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

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

	UPROPERTY(EditAnywhere, meta=(Description="Native UInterface class name or Blueprint Interface package path"))
	FString Interface;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Add an interface to a blueprint"));
	}
	virtual void Handle() override
	{
		WingFetcher F(WingOut::Stdout);
		UBlueprint* BP = F.Asset(Blueprint).Cast<UBlueprint>();
		if (!BP) return;

		// Resolve the interface class
		UWingTypes::Requirements Req;
		Req.AllowContainer = false;
		Req.IsChildOf = UInterface::StaticClass();
		FEdGraphPinType PinType;
		if (!UWingTypes::TextToType(Interface, PinType, Req, WingOut::Stdout)) return;
		UClass* InterfaceClass = Cast<UClass>(PinType.PinSubCategoryObject.Get());
		check(InterfaceClass);

		// Check for duplicates
		for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces)
		{
			if (IfaceDesc.Interface == InterfaceClass)
			{
				WingOut::Stdout.Printf(TEXT("ERROR: Interface '%s' is already implemented by this Blueprint.\n"),
					*WingUtils::FormatName(InterfaceClass));
				return;
			}
		}

		FTopLevelAssetPath InterfacePath = InterfaceClass->GetClassPathName();
		bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath);
		if (!bAdded)
		{
			WingOut::Stdout.Printf(TEXT("ERROR: ImplementNewInterface failed for '%s'.\n"),
				*WingUtils::FormatName(InterfaceClass));
			return;
		}

		// Collect stub function graph names from the newly added interface entry
		WingOut::Stdout.Printf(TEXT("Added interface %s\n"), *WingUtils::FormatName(InterfaceClass));
		for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces)
		{
			if (IfaceDesc.Interface != InterfaceClass) continue;
			for (const UEdGraph* Graph : IfaceDesc.Graphs)
			{
				WingOut::Stdout.Printf(TEXT("New Graph: %s\n"), *WingUtils::FormatName(Graph));
			}
			break;
		}
	}
};
