#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
	}
}

const FUIStyleButtonVariant& UUIButton_Base::ResolveVariant(const FUIStyleButton& Button) const
{
	switch (Variant)
	{
	case EUIButtonVariant::Secondary: return Button.Secondary;
	case EUIButtonVariant::Danger:    return Button.Danger;
	case EUIButtonVariant::Ghost:     return Button.Ghost;
	case EUIButtonVariant::Primary:
	default:                          return Button.Primary;
	}
}

// ---- 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);

	if (Background)
	{
		// Fundo + borda na cor da variante. RoundedBox dá cantos arredondados
		// e a borda colorida (BorderNormal) — "só borda" = BgNormal transparente.
		FSlateBrush Brush = Background->Background;
		Brush.TintColor = FSlateColor(VariantStyle.BgNormal);
		if (bRoundedBackground)
		{
			const float R = ActiveStyle.Button.CornerRadius;
			Brush.DrawAs = ESlateBrushDrawType::RoundedBox;
			Brush.OutlineSettings = FSlateBrushOutlineSettings(
				FVector4(R, R, R, R),
				FSlateColor(VariantStyle.BorderNormal),
				ActiveStyle.Button.BorderWidth);
			Brush.OutlineSettings.RoundingType = ESlateBrushRoundingType::FixedRadius;
		}
		else
		{
			Brush.DrawAs = ESlateBrushDrawType::Box;
			Brush.OutlineSettings = FSlateBrushOutlineSettings(
				FVector4(0, 0, 0, 0),
				FSlateColor(VariantStyle.BorderNormal),
				ActiveStyle.Button.BorderWidth);
		}
		Background->SetBrush(Brush);
	}
	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::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();
}
