#pragma once

#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingBasics.h"
#include "WingFetcher.h"
#include "WingUtils.h"
#include "WingWidgets.h"
#include "WidgetBlueprint.h"
#include "Blueprint/WidgetTree.h"
#include "Components/PanelWidget.h"
#include "Widget_Reparent.generated.h"


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

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

public:
	UPROPERTY(EditAnywhere, meta=(Description="Path to the widget, eg /Game/Widgets/WB_Test,widget:MyButton"))
	FString WidgetPath;

	UPROPERTY(EditAnywhere, meta=(Description="Name of the new parent widget. Must be a panel."))
	FString Parent;

	virtual void Register() override
	{
		UWingServer::AddHandler(this,
			TEXT("Move a widget to a different parent in a Widget Blueprint's widget tree."));
	}
	virtual void Handle() override
	{
		// Walk to the widget.
		WingFetcher F(WingOut::Stdout);
		UWidget* TargetWidget = F.Walk(WidgetPath).Cast<UWidget>();
		if (!TargetWidget) return;

		// Get the widget blueprint from the widget's outer chain.
		UWidgetBlueprint* BP = TargetWidget->GetTypedOuter<UWidgetBlueprint>();
		if (!BP)
		{
			WingOut::Stdout.Printf(TEXT("ERROR: Could not find owning WidgetBlueprint\n"));
			return;
		}
		UWidgetTree* Tree = BP->WidgetTree;

		// Get all widgets for name lookup.
		TArray<UWidget*> AllWidgets;
		Tree->GetAllWidgets(AllWidgets);

		FString WidgetName = WingUtils::FormatName(TargetWidget);

		// Find the new parent and verify it's a panel with room.
		UWidget* ParentWidget = WingUtils::FindOneWithExternalID(Parent, AllWidgets, TEXT("Widget"), WingOut::Stdout);
		if (!ParentWidget) return;
		if (!WingWidgets::CheckCanBeParent(ParentWidget, WingOut::Stdout)) return;
		UPanelWidget* ParentPanel = Cast<UPanelWidget>(ParentWidget);

		// Check for circular reparenting.
		for (UPanelWidget* Ancestor = ParentPanel; Ancestor != nullptr; Ancestor = Ancestor->GetParent())
		{
			if (Ancestor == TargetWidget)
			{
				WingOut::Stdout.Printf(TEXT("ERROR: Cannot reparent '%s' under itself\n"), *WidgetName);
				return;
			}
		}

		// Remove from current location.
		Tree->RemoveWidget(TargetWidget);

		// Add to new parent.
		ParentPanel->AddChild(TargetWidget);

		WingOut::Stdout.Printf(TEXT("Reparented '%s' under '%s'\n"), *WidgetName, *Parent);
	}
};
