// Copyright (c) 2024 Codemongous LLC. All Rights Reserved.

#include "SCW_UEdGraphPin.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphPin.h"
#include "SourcifyCoreUEWrapperModule.h"
#include "SCW_UEdGraphNode.h"
#include "SCW_UObject.h"
#include "UObject/Package.h"

using namespace Sourcify;

SCW_UEdGraphPin::SCW_UEdGraphPin(UEdGraphPin* InEdGraphPin) : EdGraphPin(InEdGraphPin)
{

}

UEdGraphPin* SCW_UEdGraphPin::ToUEdGraphPin() const
{
	return EdGraphPin;
}

ISCW_UEdGraphPinPtr SCW_UEdGraphPin::ToUEdGraphPinPtr()
{
	return GetSharedThisAs<SCW_UEdGraphPin>();
}

ISCW_UEdGraphPinConstPtr SCW_UEdGraphPin::ToUEdGraphPinPtr() const
{
	return GetSharedThisAs<SCW_UEdGraphPin>();
}

SCW_EEdGraphPinDirection SCW_UEdGraphPin::GetPinDirection() const
{
	return static_cast<SCW_EEdGraphPinDirection>(EdGraphPin->Direction.GetIntValue());
}

void SCW_UEdGraphPin::BreakAllPinLinks(bool bNotifyNodes/* = false*/)
{
	EdGraphPin->BreakAllPinLinks(bNotifyNodes);
}

wstring SCW_UEdGraphPin::GetDefaultValue() const
{
	return *EdGraphPin->DefaultValue;
}

ISCW_UObjectPtr SCW_UEdGraphPin::GetDefaultObject() const
{
	return EdGraphPin->DefaultObject ? FSourcifyCoreUEWrapper::Get().Wrap(*EdGraphPin->DefaultObject.Get()) : nullptr;
}

wstring SCW_UEdGraphPin::GetDefaultTextValue() const
{
	return *EdGraphPin->DefaultTextValue.ToString();
}

bool SCW_UEdGraphPin::GetDefaultValueIsReadOnly() const
{
	return EdGraphPin->bDefaultValueIsReadOnly;
}

wstring SCW_UEdGraphPin::GetDisplayName() const
{
	return *EdGraphPin->GetDisplayName().ToString();
}

bool SCW_UEdGraphPin::GetIsOrphaned() const
{
	return EdGraphPin->bOrphanedPin;
}

vector<ISCW_UEdGraphPinPtr> SCW_UEdGraphPin::GetLinkedTo() const
{
	vector<ISCW_UEdGraphPinPtr> WrappedLinkedTo;
	for (UEdGraphPin* LinkedPin : EdGraphPin->LinkedTo)
	{
		WrappedLinkedTo.push_back(FSourcifyCoreUEWrapper::Get().Wrap(*LinkedPin));
	}
	return WrappedLinkedTo;
}

ISCW_UEdGraphNodePtr SCW_UEdGraphPin::GetOwningNode() const
{
	return IsValid(EdGraphPin->GetOwningNode()) ? FSourcifyCoreUEWrapper::Get().Wrap(*EdGraphPin->GetOwningNode()) : nullptr;
}

ISCW_UEdGraphNodePtr SCW_UEdGraphPin::GetOwningNodeUnchecked() const
{
	UEdGraphNode* OwningNode = EdGraphPin->GetOwningNodeUnchecked();

	if (IsValid(OwningNode))
	{
		return FSourcifyCoreUEWrapper::Get().Wrap(*OwningNode);
	}

	return nullptr;
}

bool SCW_UEdGraphPin::IsOwningNodeEqualToUnchecked(ISCW_UEdGraphNodePtr Node) const
{
	if (Node)
	{
		return EdGraphPin->GetOwningNodeUnchecked() == dynamic_cast<SCW_UEdGraphNode*>(Node.get())->ToUEdGraphNode();
	}

	check(EdGraphPin);
	return false;
}

ISCW_UEdGraphPinPtr SCW_UEdGraphPin::GetParentPin() const
{
	return EdGraphPin->ParentPin ? FSourcifyCoreUEWrapper::Get().Wrap(*EdGraphPin->ParentPin) : nullptr;
}

vector<ISCW_UEdGraphPinPtr> SCW_UEdGraphPin::GetSubPins() const
{
	vector<ISCW_UEdGraphPinPtr> WrappedSubPins;
	for (UEdGraphPin* SubPin : EdGraphPin->SubPins)
	{
		WrappedSubPins.push_back(FSourcifyCoreUEWrapper::Get().Wrap(*SubPin));
	}
	return WrappedSubPins;
}

wstring SCW_UEdGraphPin::GetPinFriendlyName() const
{
	return *EdGraphPin->GetDisplayName().ToString();
}

wstring SCW_UEdGraphPin::GetPinID() const
{
	return *EdGraphPin->PinId.ToString();
}

wstring SCW_UEdGraphPin::GetPinName() const
{
	return *EdGraphPin->PinName.ToString();
}

ISCW_FEdGraphPinTypePtr SCW_UEdGraphPin::GetPinType() const
{
	return FSourcifyCoreUEWrapper::Get().Wrap(EdGraphPin->PinType);
}

ISCW_UEdGraphSchemaConstPtr SCW_UEdGraphPin::GetSchema() const
{
	return EdGraphPin->GetSchema() ? FSourcifyCoreUEWrapper::Get().Wrap(*const_cast<UEdGraphSchema*>(EdGraphPin->GetSchema())) : nullptr;
}

bool SCW_UEdGraphPin::ISCW_Equals(const ISCW_UEdGraphPin& Other) const
{
	return EdGraphPin == dynamic_cast<const SCW_UEdGraphPin&>(Other).ToUEdGraphPin();
}

bool SCW_UEdGraphPin::ISCW_Equals(shared_ptr<const ISCW_UEdGraphPin> Other) const
{
	return Other ? EdGraphPin == dynamic_cast<const SCW_UEdGraphPin*>(Other.get())->ToUEdGraphPin() : false;
}

bool SCW_UEdGraphPin::Less(const ISCW_UEdGraphPin& Other) const
{
	return EdGraphPin < dynamic_cast<const SCW_UEdGraphPin*>(&Other)->ToUEdGraphPin();
}

bool SCW_UEdGraphPin::LinkedTo_IsEmpty() const
{
	return EdGraphPin->LinkedTo.Num() == 0;
}

void SCW_UEdGraphPin::MakeLinkTo(ISCW_UEdGraphPinPtr ToPin) const
{
	UEdGraphPin* Pin = dynamic_cast<SCW_UEdGraphPin*>(ToPin.get())->ToUEdGraphPin();
	check(Pin != EdGraphPin);

#if SOURCIFY_DEBUG
	UE_LOG(LogTemp, Warning, TEXT("Making link from %s to %s | %s to %s"), *EdGraphPin->PinName.ToString(), *Pin->PinName.ToString(), *EdGraphPin->PinId.ToString(), *Pin->PinId.ToString());
	UE_LOG(LogTemp, Warning, TEXT("\t%s -> %s"), *EdGraphPin->GetOwningNode()->GetNodeTitle(ENodeTitleType::ListView).ToString(), *Pin->GetOwningNode()->GetNodeTitle(ENodeTitleType::ListView).ToString());
	UE_LOG(LogTemp, Warning, TEXT("\t%s"), *EdGraphPin->GetOwningNode()->GetGraph()->GetPackage()->GetName());
#endif

	EdGraphPin->MakeLinkTo(Pin);

#if SOURCIFY_DEBUG
	for (UEdGraphPin* LinkedPin : EdGraphPin->LinkedTo)
	{
		UE_LOG(LogTemp, Warning, TEXT("\t\tLinked pin: %s - %s"), *LinkedPin->PinName.ToString(), *LinkedPin->PinId.ToString());
		if (!LinkedPin->GetOwningNode()->GetGraph()->Nodes.Contains(LinkedPin->GetOwningNode()))
		{
			UE_LOG(LogTemp, Warning, TEXT("\t\t\tDESTROYED_NODE%s"), Pin->PinId == LinkedPin->PinId ? TEXT(" - {NEWLY ADDED PIN}") : TEXT(""));
		}
	}
#endif
}

void SCW_UEdGraphPin::MovePersistentDataFromOldPin(ISCW_UEdGraphPinPtr SourcePinPtr)
{
	if (SourcePinPtr)
	{
		EdGraphPin->MovePersistentDataFromOldPin(*dynamic_cast<SCW_UEdGraphPin*>(SourcePinPtr.get())->ToUEdGraphPin());
	}
}

void SCW_UEdGraphPin::SetDefaultValue(wstring InDefaultValue) const
{
	EdGraphPin->DefaultValue = InDefaultValue.c_str();
}

void SCW_UEdGraphPin::SetDefaultObject(ISCW_UObjectPtr InObjectPtr) const
{
	EdGraphPin->DefaultObject = InObjectPtr ? dynamic_cast<SCW_UObject*>(InObjectPtr.get())->ToUObjectRawPtr() : nullptr;
}

void SCW_UEdGraphPin::SetDefaultTextValue(wstring InDefaultValue) const
{
	EdGraphPin->DefaultTextValue = FText::FromString(InDefaultValue.c_str());
}

void SCW_UEdGraphPin::SetPinDirection(SCW_EEdGraphPinDirection Direction) const
{
	EdGraphPin->Direction = static_cast<EEdGraphPinDirection>(Direction);
}

void SCW_UEdGraphPin::SetSavePinIfOrphaned(bool bShouldSave) const
{
	EdGraphPin->SetSavePinIfOrphaned(bShouldSave);
}

void SCW_UEdGraphPin::SetPinName(const wstring& Name) const
{
	EdGraphPin->PinName = FName(Name.c_str());
}

bool SCW_UEdGraphPin::WasTrashed() const
{
	return EdGraphPin->WasTrashed();
}