#include "UIButton_Base.h"

#include "ZMMOThemeSubsystem.h"
#include "Engine/GameInstance.h"
#include "Engine/World.h"
#include "TimerManager.h"
#include "Components/Border.h"
#include "Styling/SlateBrush.h"
#include "Components/TextBlock.h"
#include "Components/Image.h"
#include "Components/SizeBox.h"
#include "Components/ScaleBox.h"
#include "Components/OverlaySlot.h"
#include "CommonTextBlock.h"
#include "CommonActionWidget.h"

namespace
{
	/** Resolve o FUIStyle ativo; fallback p/ defaults (preview de designer). */
	const FUIStyle& ResolveActiveStyle(const UUserWidget* Widget, const FUIStyle& Fallback)
	{
		if (Widget)
		{
			if (const UGameInstance* GI = Widget->GetGameInstance())
			{
				if (const UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
				{
					return Theme->GetActiveUIStyle();
				}
			}
		}
		return Fallback; // sem GameInstance (design-time): Aurora Arcana default
	}
}

FUIStyleButtonVariant UUIButton_Base::ResolveVariant(const FUIStyleButton& Button) const
{
	// Compõe FLAT a partir dos 3 sub-mapas do tema (Backgrounds/Strokes/Fonts).
	// Fallback inline → Defaults (constructor de FUIStyleButton popula
	// Primary/Secondary/Danger/Ghost com defaults Aurora Arcana — GC-safe).
	static const FUIStyleButton Defaults;
	FUIStyleButtonVariant V;

	const FUIStyleButtonBackground* BG = Button.Backgrounds.Find(Variant);
	if (!BG) { BG = Defaults.Backgrounds.Find(Variant); }
	if (!BG) { BG = Defaults.Backgrounds.Find(TEXT("Primary")); }
	if (BG)
	{
		V.BgNormal = BG->BgNormal;
		V.BgHover = BG->BgHover;
		V.BgPressed = BG->BgPressed;
		V.BgDisabled = BG->BgDisabled;
		V.BackgroundTexture = BG->BackgroundTexture;
		V.BackgroundMargin = BG->BackgroundMargin;
	}

	const FUIStyleButtonStroke* ST = Button.Strokes.Find(Variant);
	if (!ST) { ST = Defaults.Strokes.Find(Variant); }
	if (!ST) { ST = Defaults.Strokes.Find(TEXT("Primary")); }
	if (ST)
	{
		V.BorderNormal = ST->BorderNormal;
		V.BorderHover  = ST->BorderHover;
		V.BorderWidth  = ST->BorderWidth;
		V.CornerRadius = ST->CornerRadius;
	}

	const FUIStyleButtonFont* F = Button.Fonts.Find(Variant);
	if (!F) { F = Defaults.Fonts.Find(Variant); }
	if (!F) { F = Defaults.Fonts.Find(TEXT("Primary")); }
	if (F)
	{
		V.TextColor = F->TextColor;
		V.TextStyle = F->TextStyle;
	}
	return V;
}

TArray<FString> UUIButton_Base::GetVariantOptions() const
{
	TArray<FString> Options;
	for (const TCHAR* N : { TEXT("Primary"), TEXT("Secondary"), TEXT("Danger"), TEXT("Ghost") })
	{
		Options.Add(N);
	}
	if (const UDataTable* DT = LoadObject<UDataTable>(nullptr,
		TEXT("/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles")))
	{
		if (const FUIStyleRow* Row = DT->FindRow<FUIStyleRow>(
			FName(TEXT("Default")), TEXT("UIButtonVariantOptions"), false))
		{
			for (const TPair<FName, FUIStyleButtonBackground>& P : Row->Style.Button.Backgrounds) { Options.AddUnique(P.Key.ToString()); }
			for (const TPair<FName, FUIStyleButtonStroke>&     P : Row->Style.Button.Strokes)     { Options.AddUnique(P.Key.ToString()); }
			for (const TPair<FName, FUIStyleButtonFont>&       P : Row->Style.Button.Fonts)       { Options.AddUnique(P.Key.ToString()); }
		}
	}
	return Options;
}

// ---- Hyper "Set Button Text" ----
void UUIButton_Base::SetButtonText(FText InText)
{
	if (!ButtonText)
	{
		return;
	}
	const FText Final = bUppercaseText
		? FText::FromString(InText.ToString().ToUpper())
		: InText;
	ButtonText->SetText(Final);
}

// ---- Hyper "Set Number Text" ----
void UUIButton_Base::SetNumberText()
{
	if (!Number_Text)
	{
		return;
	}
	if (bShowNumberText)
	{
		Number_Text->SetText(FText::AsNumber(NumberTextAmount));
		Number_Text->SetVisibility(ESlateVisibility::Visible);
	}
	else
	{
		Number_Text->SetVisibility(ESlateVisibility::Hidden);
	}
}

// ---- Hyper "Set Icon" ----
void UUIButton_Base::SetIcon()
{
	if (bUseIconInsteadOfText)
	{
		if (Image_Icon)
		{
			if (IconImage)
			{
				Image_Icon->SetBrushResourceObject(IconImage);
			}
			Image_Icon->SetVisibility(ESlateVisibility::Visible);
		}
		if (ButtonText)
		{
			ButtonText->SetVisibility(ESlateVisibility::Collapsed);
		}
	}
	else
	{
		if (Image_Icon)
		{
			Image_Icon->SetVisibility(ESlateVisibility::Collapsed);
		}
		if (ButtonText)
		{
			ButtonText->SetVisibility(ESlateVisibility::Visible);
		}
	}
}

// ---- Hyper "Set Sizebox Master Dimmensions" ----
void UUIButton_Base::ApplySizeBox()
{
	if (bDoNotOverrideWithSizebox || !SizeBox_Master)
	{
		return;
	}
	SizeBox_Master->SetHeightOverride(InHeightOverride);
	SizeBox_Master->SetWidthOverride(InWidthOverride);
}

// ---- Hyper "Set InputAction Style" ----
void UUIButton_Base::ApplyInputActionStyle()
{
	// InputActionWidget é privado em UCommonButtonBase (bind interno). Pega por
	// nome — o widget do WBP chama-se "InputActionWidget" (bind do CommonUI).
	UCommonActionWidget* IAW = Cast<UCommonActionWidget>(
		GetWidgetFromName(TEXT("InputActionWidget")));
	if (!IAW)
	{
		return;
	}

	if (bShowInputActionWidget)
	{
		IAW->SetVisibility(ESlateVisibility::Visible);
		IAW->SetIsEnabled(true);
	}
	else
	{
		IAW->SetVisibility(ESlateVisibility::Collapsed);
		IAW->SetIsEnabled(false);
	}

	if (UOverlaySlot* OS = Cast<UOverlaySlot>(IAW->Slot))
	{
		OS->SetPadding(InputPadding);
		OS->SetHorizontalAlignment(InputHorzAlignment);
		OS->SetVerticalAlignment(InputVertAlignment);
	}
}

// ---- Hyper "Initialize Button" (orquestrador) ----
void UUIButton_Base::InitializeButton()
{
	SetButtonText(ButtonTextValue);
	SetNumberText();
	SetIcon();
	ApplySizeBox();
	RefreshUIStyle();
}

// ---- Hyper "Update Button Style" / "Set Brush" → nossa camada FUIStyle ----
void UUIButton_Base::RefreshUIStyle()
{
	const FUIStyle Fallback; // defaults do struct = paleta Aurora Arcana
	const FUIStyle& ActiveStyle = ResolveActiveStyle(this, Fallback);
	const FUIStyleButtonVariant& VariantStyle = ResolveVariant(ActiveStyle.Button);

	// Fundo + borda no estado Normal (hover/pressed/disabled via NativeOn*).
	ApplyVisualState(EUIButtonVisual::Normal);

	if (ButtonText)
	{
		// Tipografia: CommonTextStyle da variante (padrão Hyper/CommonUI).
		if (VariantStyle.TextStyle)
		{
			ButtonText->SetStyle(VariantStyle.TextStyle);
		}
		// Cor: FUIStyle manda na cor por tema (sobrepõe o CommonTextStyle).
		ButtonText->SetColorAndOpacity(FSlateColor(VariantStyle.TextColor));

		// Alinhamento L/C/R dentro da largura do botão.
		ButtonText->SetJustification(TextAlign);
	}

	// Texto adapta ao tamanho do botão (ScaleToFit) ou usa tamanho fixo.
	if (TextScaleBox)
	{
		TextScaleBox->SetStretch(bAutoSizeText ? EStretch::ScaleToFit : EStretch::None);

		// Posiciona o bloco de texto L/C/R dentro do botão (slot do Overlay).
		if (UOverlaySlot* OS = Cast<UOverlaySlot>(TextScaleBox->Slot))
		{
			EHorizontalAlignment H = HAlign_Center;
			switch (TextAlign)
			{
			case ETextJustify::Left:  H = HAlign_Left;  break;
			case ETextJustify::Right: H = HAlign_Right; break;
			default:                  H = HAlign_Center; break;
			}
			OS->SetHorizontalAlignment(H);
			OS->SetVerticalAlignment(VAlign_Center);
		}
	}

	BP_ApplyUIStyle(ActiveStyle.Button, VariantStyle);
}

void UUIButton_Base::ApplyVisualState(EUIButtonVisual State)
{
	if (!Background)
	{
		return;
	}
	const FUIStyle Fallback;
	const FUIStyle& AS = ResolveActiveStyle(this, Fallback);
	const FUIStyleButtonVariant& V = ResolveVariant(AS.Button);

	FLinearColor Fill, Outline;
	switch (State)
	{
	case EUIButtonVisual::Hovered:  Fill = V.BgHover;   Outline = V.BorderHover;  break;
	case EUIButtonVisual::Pressed:  Fill = V.BgPressed; Outline = V.BorderHover;  break;
	case EUIButtonVisual::Disabled: Fill = V.BgDisabled; Outline = V.BorderNormal; break;
	default:                        Fill = V.BgNormal;  Outline = V.BorderNormal; break;
	}

	FSlateBrush Brush = Background->Background;
	Brush.TintColor = FSlateColor(Fill);
	if (bRoundedBackground)
	{
		// CornerRadius/BorderWidth agora vêm da variante composta (Stroke).
		const float R = V.CornerRadius;
		Brush.DrawAs = ESlateBrushDrawType::RoundedBox;
		Brush.OutlineSettings = FSlateBrushOutlineSettings(
			FVector4(R, R, R, R), FSlateColor(Outline), V.BorderWidth);
		Brush.OutlineSettings.RoundingType = ESlateBrushRoundingType::FixedRadius;
	}
	else
	{
		Brush.DrawAs = ESlateBrushDrawType::Box;
		Brush.OutlineSettings = FSlateBrushOutlineSettings(
			FVector4(0, 0, 0, 0), FSlateColor(Outline), V.BorderWidth);
	}
	Background->SetBrush(Brush);
}

void UUIButton_Base::NativeOnHovered()
{
	Super::NativeOnHovered();
	ApplyVisualState(EUIButtonVisual::Hovered);
}

void UUIButton_Base::NativeOnUnhovered()
{
	Super::NativeOnUnhovered();
	ApplyVisualState(EUIButtonVisual::Normal);
}

void UUIButton_Base::NativeOnPressed()
{
	Super::NativeOnPressed();
	ApplyVisualState(EUIButtonVisual::Pressed);
}

void UUIButton_Base::NativeOnReleased()
{
	Super::NativeOnReleased();
	ApplyVisualState(IsHovered() ? EUIButtonVisual::Hovered : EUIButtonVisual::Normal);
}

void UUIButton_Base::NativeOnEnabled()
{
	Super::NativeOnEnabled();
	ApplyVisualState(EUIButtonVisual::Normal);
}

void UUIButton_Base::NativeOnDisabled()
{
	Super::NativeOnDisabled();
	ApplyVisualState(EUIButtonVisual::Disabled);
}

void UUIButton_Base::NativePreConstruct()
{
	Super::NativePreConstruct();
	InitializeButton();
	ApplyInputActionStyle();
}

void UUIButton_Base::NativeConstruct()
{
	Super::NativeConstruct();

	if (!bThemeBound)
	{
		if (const UGameInstance* GI = GetGameInstance())
		{
			if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
			{
				Theme->OnThemeChanged.AddDynamic(this, &UUIButton_Base::HandleThemeChanged);
				bThemeBound = true;
			}
		}
	}

	InitializeButton();
	ApplyInputActionStyle();

	if (bDeactivatedOnConstructWithTimeout && Timeout > 0.f)
	{
		StartDeactivateTimeout();
	}
}

void UUIButton_Base::NativeDestruct()
{
	if (UWorld* World = GetWorld())
	{
		World->GetTimerManager().ClearTimer(InactivityTimer);
		World->GetTimerManager().ClearTimer(TimerTickHandle);
	}

	if (bThemeBound)
	{
		if (const UGameInstance* GI = GetGameInstance())
		{
			if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
			{
				Theme->OnThemeChanged.RemoveDynamic(this, &UUIButton_Base::HandleThemeChanged);
			}
		}
		bThemeBound = false;
	}

	Super::NativeDestruct();
}

// ---- Hyper "Deactivate Button On Timeout" ----
void UUIButton_Base::StartDeactivateTimeout()
{
	UWorld* World = GetWorld();
	if (!World)
	{
		return;
	}

	SetIsEnabled(false);
	TimeRemaining = Timeout;

	World->GetTimerManager().SetTimer(
		InactivityTimer, this, &UUIButton_Base::HandleTimeoutFinished, Timeout, false);

	if (TimeUpdateFrequency > 0.f)
	{
		World->GetTimerManager().SetTimer(
			TimerTickHandle, this, &UUIButton_Base::HandleTimerTick,
			TimeUpdateFrequency, true);
	}
}

void UUIButton_Base::HandleTimeoutFinished()
{
	if (UWorld* World = GetWorld())
	{
		World->GetTimerManager().ClearTimer(TimerTickHandle);
	}
	TimeRemaining = 0.f;
	SetIsEnabled(true);
	OnButtonActivatedByTimeout.Broadcast();
}

void UUIButton_Base::HandleTimerTick()
{
	TimeRemaining = FMath::Max(0.f, TimeRemaining - TimeUpdateFrequency);
	OnButtonTimerUpdated.Broadcast(TimeRemaining);
}

void UUIButton_Base::HandleThemeChanged(FName /*NewThemeId*/)
{
	RefreshUIStyle();
}
