/**
 * Copyright 2022-2025 Theai, Inc. dba Inworld AI
 */

#include "K2Node_InworldWrapData.h"

#include "BlueprintActionDatabaseRegistrar.h"
#include "BlueprintNodeSpawner.h"
#include "EdGraphSchema_K2.h"
#include "InworldBlueprintFunctionLibrary.h"

void UK2Node_InworldWrapData::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{
	Super::GetMenuActions(ActionRegistrar);
	UClass* Action = GetClass();
	if (ActionRegistrar.IsOpenForRegistration(Action))
	{
		auto CustomizeLambda = [](UEdGraphNode* NewNode, bool bIsTemplateNode, const FName FunctionName)
		{
			UK2Node_InworldWrapData* Node = CastChecked<UK2Node_InworldWrapData>(NewNode);
			UFunction* Function = UInworldBlueprintFunctionLibrary::StaticClass()->FindFunctionByName(FunctionName);
			check(Function);
			Node->SetFromFunction(Function);
		};

		UBlueprintNodeSpawner* GetNodeSpawner = UBlueprintNodeSpawner::Create(GetClass());
		check(GetNodeSpawner != nullptr);
		GetNodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(
			CustomizeLambda, GET_FUNCTION_NAME_CHECKED(UInworldBlueprintFunctionLibrary, WrapInworldData));
		ActionRegistrar.AddBlueprintAction(Action, GetNodeSpawner);
	}
}

void UK2Node_InworldWrapData::AllocateDefaultPins()
{
	Super::AllocateDefaultPins();
	FindPinChecked(FName{"ScriptStruct"})->SafeSetHidden(true);
}

void UK2Node_InworldWrapData::NotifyPinConnectionListChanged(UEdGraphPin* Pin)
{
	Super::NotifyPinConnectionListChanged(Pin);

	if (Pin == FindPinChecked(FName{"Data"}))
	{
		if (Pin->LinkedTo.Num() == 0)
		{
			Pin->PinType = {};
			Pin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard;
			UEdGraphPin* ScriptStructPin = FindPinChecked(FName{"ScriptStruct"});
			ScriptStructPin->DefaultObject = nullptr;
		}
		else
		{
			Pin->PinType = Pin->LinkedTo[0]->PinType;
			UEdGraphPin* ScriptStructPin = FindPinChecked(FName{"ScriptStruct"});
			ScriptStructPin->DefaultObject = Pin->PinType.PinSubCategoryObject.Get();
		}
	}
}

bool UK2Node_InworldWrapData::IsConnectionDisallowed(
	const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
{
	if (MyPin == FindPinChecked(FName{"Data"}))
	{
		if (UScriptStruct* PinStruct = Cast<UScriptStruct>(OtherPin->PinType.PinSubCategoryObject.Get());
			OtherPin->PinType.PinCategory != UEdGraphSchema_K2::PC_Struct || PinStruct == nullptr ||
			PinStruct == (FindObject<UScriptStruct>(nullptr, TEXT("/Script/InworldRuntime.InworldDataHandle"))))
		{
			OutReason = TEXT("Pin type must be struct type that can be wrapped in FInworldDataHandle");
			return true;
		}
	}
	return Super::IsConnectionDisallowed(MyPin, OtherPin, OutReason);
}
