#pragma once

#include "CoreMinimal.h"
#include "WingBasics.h"
#include "WingFetcher.h"
#include "WingUtils.h"
#include "WingTypes.h"
#include "WingServer.h"
#include "WingComponent.h"
#include "Engine/Blueprint.h"
#include "Components/ActorComponent.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "ActorComponent_Add.generated.h"


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

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

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

	UPROPERTY(EditAnywhere, meta=(Description="Component class name (e.g. StaticMeshComponent, SceneComponent)"))
	FString Class;

	UPROPERTY(EditAnywhere, meta=(Description="Component name for the new component"))
	FString Component;

	UPROPERTY(EditAnywhere, meta=(Description="Name of the parent component to attach to"))
	FString Parent;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Add a component to a Blueprint's SimpleConstructionScript. "
			"Optionally attach it to an existing parent component."));
	}
	virtual void Handle() override
	{
		WingFetcher F(WingOut::Stdout);
		UBlueprint* BP = F.Asset(Blueprint).Cast<UBlueprint>();
		if (!BP) return;

		// Check that the proposed name is valid
		TSet<FName> InUse = WingUtils::GetAllInUseNames(BP);
		FName InternalID = WingUtils::CheckProposedName(Component, InUse, WingOut::Stdout);
		if (InternalID.IsNone()) return;

		// Resolve the component class by name
		UWingTypes::Requirements Req;
		Req.AllowContainer = false;
		Req.IsChildOf = UActorComponent::StaticClass();
		FEdGraphPinType PinType;
		if (!UWingTypes::TextToType(Class, PinType, Req, WingOut::Stdout)) return;
		UClass* ComponentClass = Cast<UClass>(PinType.PinSubCategoryObject.Get());
		check(ComponentClass);
		if (!UWingComponent::CheckValidComponentClass(ComponentClass, WingOut::Stdout)) return;

		// Find the specified parent component
		TArray<TStrongObjectPtr<UWingComponentRef>> AllComponents = UWingComponent::GetAll(BP);
		TStrongObjectPtr<UWingComponentRef> ParentComp = WingUtils::FindOneWithExternalID(Parent, AllComponents, TEXT("Component"), WingOut::Stdout);
		if (!ParentComp) return;

		// Create the SCS node
		if (!UWingComponent::AddComponent(BP, ComponentClass, ParentComp.Get(), InternalID, WingOut::Stdout)) return;

		WingOut::Stdout.Printf(TEXT("Component Added.\n"));
	}
};
