#pragma once

#include "CoreMinimal.h"
#include "CommonActivatableWidget.h"
#include "UIDraggableWindow_Base.generated.h"

class UBorder;
class UZMMOUISaveGame;

/**
 *  Base de janelas in-game movel + persistente. Subclasse define WindowId
 *  (FName estavel) via override de GetWindowId(); a Base cuida do drag
 *  (RenderTransform.Translation) e da persistencia (UZMMOUISaveGame).
 *
 *  Convencao do WBP:
 *   - Bind opcional `Border_DragHandle` cobrindo a area arrastavel (header).
 *     Sem ele, a janela nao captura drag (vira static).
 *   - `Border_DragHandle->Visibility = Visible` (precisa receber HitTest).
 *
 *  Por que RenderTransform e nao Slot.Position?
 *   - Funciona em qualquer layout slot (Overlay, VBox, Canvas), nao so
 *     CanvasPanelSlot.
 *   - Nao polui o asset (translation e' transient/visual, nao layout-layout).
 *
 *  Persistencia: na primeira ativacao, carrega a posicao salva do WindowId;
 *  ao soltar o drag, grava e salva o slot.
 */
UCLASS(Abstract, Blueprintable)
class ZMMO_API UUIDraggableWindow_Base : public UCommonActivatableWidget
{
	GENERATED_BODY()

public:
	/**
	 *  Identificador estavel da janela (chave no save). Subclasse OBRIGADA
	 *  a sobrescrever — default NAME_None desativa persistencia.
	 */
	virtual FName GetWindowId() const { return NAME_None; }

protected:
	virtual void NativeOnActivated() override;
	virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
	virtual FReply NativeOnMouseMove(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
	virtual FReply NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override;
	virtual void NativeOnMouseLeave(const FPointerEvent& InMouseEvent) override;

	/**
	 *  Define se o ponto sob o cursor pertence a area de drag. Default: usa
	 *  Border_DragHandle (se bindado). Subclass pode override pra usar outro
	 *  widget (ex.: Container_Header ja' existente) sem precisar adicionar
	 *  um Border dedicado no WBP.
	 */
	virtual bool IsDragHandleHit(const FPointerEvent& MouseEvent) const;

	/** Aplica a posicao salva (se houver) como RenderTransform.Translation. */
	void ApplySavedPosition();

	/** Grava a posicao atual no save e persiste no slot. */
	void PersistCurrentPosition();

	/**
	 *  Se a janela ficou fora do viewport (ex.: usuario arrastou pra borda e
	 *  depois a resolucao mudou ou ele fechou e reabriu), reseta translation
	 *  pra (0,0). Chamado no proximo tick apos Activated — cached geometry
	 *  so' tem valor depois do primeiro layout pass.
	 */
	UFUNCTION()
	void ValidatePositionInViewport();

	/** Quanto da janela precisa ficar visivel pra contar como "no viewport". */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Drag")
	float MinVisiblePixels = 50.f;

	/**
	 *  Bind opcional do WBP. Apenas drags iniciados com o cursor SOBRE
	 *  este border sao aceitos — bloqueia drag por clicar nos rows/botoes.
	 */
	UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Drag")
	TObjectPtr<UBorder> Border_DragHandle;

	/** Distancia minima do mouse pra confirmar "drag iniciado" (anti-jitter). */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Drag")
	float DragStartThresholdPx = 4.f;

private:
	bool bMaybeDragging = false;	///< pressed mas ainda nao passou do threshold
	bool bDragging = false;			///< drag confirmado
	FVector2D DragStartScreenPos = FVector2D::ZeroVector;
	FVector2D WidgetStartTranslation = FVector2D::ZeroVector;
};
