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

#include "SourcifyGraphSchema.h"
#include "SSourcifyGraph.h"
#include "SourcifyEditorCommands.h"
//#include "AssetManagerEditorModule.h"
#include "ToolMenu.h"
#include "Toolkits/GlobalEditorCommonCommands.h"
#include "ConnectionDrawingPolicy.h"
#include "ToolMenuEntry.h"
#include "ToolMenuSection.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(SourcifyGraphSchema)

namespace UE
{
namespace DependencyPinCategory
{
	FName NamePassive(TEXT("Passive"));
	FName NameHardUsedInGame(TEXT("Hard"));
	FName NameHardEditorOnly(TEXT("HardEditorOnly"));
	FName NameSoftUsedInGame(TEXT("Soft"));
	FName NameSoftEditorOnly(TEXT("SoftEditorOnly"));
	const FLinearColor ColorPassive = FLinearColor(128, 128, 128);
	const FLinearColor ColorHardUsedInGame = FLinearColor(FColor(236, 252, 227)); // RiceFlower
	const FLinearColor ColorHardEditorOnly = FLinearColor(FColor(118, 126, 114));
	const FLinearColor ColorSoftUsedInGame = FLinearColor(FColor(145, 66, 117)); // CannonPink
	const FLinearColor ColorSoftEditorOnly = FLinearColor(FColor(73, 33, 58));

}
}

EDependencyPinCategory ParseDependencyPinCategory(FName PinCategory)
{
	if (PinCategory == UE::DependencyPinCategory::NameHardUsedInGame)
	{
		return EDependencyPinCategory::LinkEndActive | EDependencyPinCategory::LinkTypeHard | EDependencyPinCategory::LinkTypeUsedInGame;
	}
	else if (PinCategory == UE::DependencyPinCategory::NameHardEditorOnly)
	{
		return EDependencyPinCategory::LinkEndActive | EDependencyPinCategory::LinkTypeHard;
	}
	else if (PinCategory == UE::DependencyPinCategory::NameSoftUsedInGame)
	{
		return EDependencyPinCategory::LinkEndActive | EDependencyPinCategory::LinkTypeUsedInGame;
	}
	else if (PinCategory == UE::DependencyPinCategory::NameSoftEditorOnly)
	{
		return EDependencyPinCategory::LinkEndActive;
	}
	else
	{
		return EDependencyPinCategory::LinkEndPassive;
	}
}

FName GetName(EDependencyPinCategory Category)
{
	if ((Category & EDependencyPinCategory::LinkEndMask) == EDependencyPinCategory::LinkEndPassive)
	{
		return UE::DependencyPinCategory::NamePassive;
	}
	else
	{
		switch (Category & EDependencyPinCategory::LinkTypeMask)
		{
		case EDependencyPinCategory::LinkTypeHard | EDependencyPinCategory::LinkTypeUsedInGame:
			return UE::DependencyPinCategory::NameHardUsedInGame;
		case EDependencyPinCategory::LinkTypeHard:
			return UE::DependencyPinCategory::NameHardEditorOnly;
		case EDependencyPinCategory::LinkTypeUsedInGame:
			return UE::DependencyPinCategory::NameSoftUsedInGame;
		default:
			return UE::DependencyPinCategory::NameSoftEditorOnly;
		}
	}
}


FLinearColor GetColor(EDependencyPinCategory Category)
{
	if ((Category & EDependencyPinCategory::LinkEndMask) == EDependencyPinCategory::LinkEndPassive)
	{
		return UE::DependencyPinCategory::ColorPassive;
	}
	else
	{
		switch (Category & EDependencyPinCategory::LinkTypeMask)
		{
		case EDependencyPinCategory::LinkTypeHard | EDependencyPinCategory::LinkTypeUsedInGame:
			return UE::DependencyPinCategory::ColorHardUsedInGame;
		case EDependencyPinCategory::LinkTypeHard:
			return UE::DependencyPinCategory::ColorHardEditorOnly;
		case EDependencyPinCategory::LinkTypeUsedInGame:
			return UE::DependencyPinCategory::ColorSoftUsedInGame;
		default:
			return UE::DependencyPinCategory::ColorSoftEditorOnly;
		}
	}
}

// Overridden connection drawing policy to use less curvy lines between nodes
class FReferenceViewerConnectionDrawingPolicy : public FConnectionDrawingPolicy
{
public:
	FReferenceViewerConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements)
		: FConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements)
	{
	}

	virtual FVector2D ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const override
	{
		const int32 Tension = FMath::Abs<int32>(Start.X - End.X);
		return Tension * FVector2D(1.0f, 0);
	}

	virtual void DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*inout*/ FConnectionParams& Params) override
	{
		EDependencyPinCategory OutputCategory = ParseDependencyPinCategory(OutputPin->PinType.PinCategory);
		EDependencyPinCategory InputCategory = ParseDependencyPinCategory(InputPin->PinType.PinCategory);

		EDependencyPinCategory Category = !!(OutputCategory & EDependencyPinCategory::LinkEndActive) ? OutputCategory : InputCategory;
		Params.WireColor = GetColor(Category);
	}
};

//////////////////////////////////////////////////////////////////////////
// USourcifyGraphSchema

USourcifyGraphSchema::USourcifyGraphSchema(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

void USourcifyGraphSchema::GetContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const
{
	{
		FToolMenuSection& Section = Menu->AddSection(TEXT("Asset"), NSLOCTEXT("ReferenceViewerSchema", "AssetSectionLabel", "Asset"));
		Section.AddMenuEntry(FGlobalEditorCommonCommands::Get().FindInContentBrowser);
		Section.AddMenuEntry(FSourcifyEditorCommands::Get().OpenSelectedInAssetEditor);
	}

	{
		FToolMenuSection& Section = Menu->AddSection(TEXT("Misc"), NSLOCTEXT("ReferenceViewerSchema", "MiscSectionLabel", "Misc"));
		Section.AddMenuEntry(FSourcifyEditorCommands::Get().ZoomToFit);
	}

	{
		FToolMenuSection& Section = Menu->AddSection(TEXT("References"), NSLOCTEXT("ReferenceViewerSchema", "ReferencesSectionLabel", "References"));
		Section.AddMenuEntry(FSourcifyEditorCommands::Get().ShowReferenceTree);
	}
}

FLinearColor USourcifyGraphSchema::GetPinTypeColor(const FEdGraphPinType& PinType) const
{
	return GetColor(ParseDependencyPinCategory(PinType.PinCategory));
}

void USourcifyGraphSchema::ConstructBasicPinTooltip(const UEdGraphPin& Pin, FText const& PinDescription, FString& TooltipOut) const
{
	
}

void USourcifyGraphSchema::BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotifcation) const
{
	// Don't allow breaking any links
}

void USourcifyGraphSchema::BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin) const
{
	// Don't allow breaking any links
}

FPinConnectionResponse USourcifyGraphSchema::MovePinLinks(UEdGraphPin& MoveFromPin, UEdGraphPin& MoveToPin, bool bIsIntermediateMove, bool bNotifyLinkedNodes) const
{
	// Don't allow moving any links
	return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, FString());
}

FPinConnectionResponse USourcifyGraphSchema::CopyPinLinks(UEdGraphPin& CopyFromPin, UEdGraphPin& CopyToPin, bool bIsIntermediateCopy) const
{
	// Don't allow copying any links
	return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, FString());
}

FConnectionDrawingPolicy* USourcifyGraphSchema::CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const
{
	return new FReferenceViewerConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements);
}

void USourcifyGraphSchema::DroppedAssetsOnGraph(const TArray<FAssetData>& Assets, const FVector2D& GraphPosition, UEdGraph* Graph) const
{
	TArray<FAssetIdentifier> AssetIdentifiers;

	//IAssetManagerEditorModule::ExtractAssetIdentifiersFromAssetDataList(Assets, AssetIdentifiers);
	//IAssetManagerEditorModule::Get().OpenReferenceViewerUI(AssetIdentifiers);
}

void USourcifyGraphSchema::GetAssetsGraphHoverMessage(const TArray<FAssetData>& Assets, const UEdGraph* HoverGraph, FString& OutTooltipText, bool& OutOkIcon) const
{
	OutOkIcon = true;
}
