#include "UIDraggableWindow_Base.h"

#include "Components/Border.h"
#include "Engine/Engine.h"
#include "Engine/GameViewportClient.h"
#include "Input/Reply.h"
#include "UIWindowSaveGame.h"

void UUIDraggableWindow_Base::NativeOnActivated()
{
	Super::NativeOnActivated();
	ApplySavedPosition();
	// Validacao usa translation + viewport size, ambos disponiveis ja' aqui
	// (sem precisar do CachedGeometry/layout pass).
	ValidatePositionInViewport();
}

void UUIDraggableWindow_Base::ApplySavedPosition()
{
	const FName Id = GetWindowId();
	if (Id.IsNone()) return;

	UZMMOUISaveGame* Save = UZMMOUISaveGame::LoadOrCreate();
	FVector2D Pos;
	if (Save && Save->TryGetWindowPosition(Id, Pos))
	{
		SetRenderTranslation(Pos);
	}
}

void UUIDraggableWindow_Base::PersistCurrentPosition()
{
	const FName Id = GetWindowId();
	if (Id.IsNone()) return;

	UZMMOUISaveGame* Save = UZMMOUISaveGame::LoadOrCreate();
	if (!Save) return;
	Save->SetWindowPosition(Id, GetRenderTransform().Translation);
	UZMMOUISaveGame::SaveNow(Save);
}

bool UUIDraggableWindow_Base::IsDragHandleHit(const FPointerEvent& MouseEvent) const
{
	if (!Border_DragHandle) return false;
	const FGeometry HandleGeom = Border_DragHandle->GetCachedGeometry();
	return HandleGeom.IsUnderLocation(MouseEvent.GetScreenSpacePosition());
}

FReply UUIDraggableWindow_Base::NativeOnMouseButtonDown(const FGeometry& InGeometry,
                                                        const FPointerEvent& InMouseEvent)
{
	if (InMouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && IsDragHandleHit(InMouseEvent))
	{
		bMaybeDragging = true;
		bDragging = false;
		DragStartScreenPos = InMouseEvent.GetScreenSpacePosition();
		WidgetStartTranslation = GetRenderTransform().Translation;
		return FReply::Handled().CaptureMouse(TakeWidget());
	}
	return Super::NativeOnMouseButtonDown(InGeometry, InMouseEvent);
}

FReply UUIDraggableWindow_Base::NativeOnMouseMove(const FGeometry& InGeometry,
                                                  const FPointerEvent& InMouseEvent)
{
	if (!bMaybeDragging && !bDragging)
	{
		return Super::NativeOnMouseMove(InGeometry, InMouseEvent);
	}

	const FVector2D Delta = InMouseEvent.GetScreenSpacePosition() - DragStartScreenPos;
	if (!bDragging && Delta.SizeSquared() < DragStartThresholdPx * DragStartThresholdPx)
	{
		return FReply::Handled();
	}
	bDragging = true;
	SetRenderTranslation(WidgetStartTranslation + Delta);
	return FReply::Handled();
}

FReply UUIDraggableWindow_Base::NativeOnMouseButtonUp(const FGeometry& InGeometry,
                                                      const FPointerEvent& InMouseEvent)
{
	if (InMouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && (bMaybeDragging || bDragging))
	{
		const bool bWasRealDrag = bDragging;
		bMaybeDragging = false;
		bDragging = false;
		if (bWasRealDrag)
		{
			PersistCurrentPosition();
		}
		return FReply::Handled().ReleaseMouseCapture();
	}
	return Super::NativeOnMouseButtonUp(InGeometry, InMouseEvent);
}

void UUIDraggableWindow_Base::NativeOnMouseLeave(const FPointerEvent& InMouseEvent)
{
	Super::NativeOnMouseLeave(InMouseEvent);
}

void UUIDraggableWindow_Base::ValidatePositionInViewport()
{
	if (!GEngine || !GEngine->GameViewport) return;
	FVector2D ViewportSize;
	GEngine->GameViewport->GetViewportSize(ViewportSize);
	if (ViewportSize.IsNearlyZero()) return;

	// RenderTransform.Translation esta em coordenadas de viewport (pixels),
	// independente de DPI/offset do editor — comparacao direta funciona em
	// PIE e em build standalone. Assume slot centralizado (default UMG
	// stack); meio-viewport e' o quanto a translation pode crescer antes
	// da janela sair completamente.
	const FVector2D Tr = GetRenderTransform().Translation;
	const float HalfX = ViewportSize.X * 0.5f;
	const float HalfY = ViewportSize.Y * 0.5f;

	const bool bOutOfBounds =
		FMath::Abs(Tr.X) > HalfX - MinVisiblePixels ||
		FMath::Abs(Tr.Y) > HalfY - MinVisiblePixels;

	UE_LOG(LogTemp, Verbose, TEXT("DraggableWindow::Validate translation=(%.0f,%.0f) viewport=(%.0f,%.0f) outOfBounds=%d"),
		Tr.X, Tr.Y, ViewportSize.X, ViewportSize.Y, bOutOfBounds ? 1 : 0);

	if (bOutOfBounds)
	{
		SetRenderTranslation(FVector2D::ZeroVector);
		PersistCurrentPosition();
	}
}
