#include "UIPanel_Base.h"

#include "ZMMOThemeSubsystem.h"
#include "Engine/GameInstance.h"
#include "Components/Border.h"
#include "Styling/SlateBrush.h"
#include "Engine/DataTable.h"
#include "UI/UIStyleRow.h"

namespace
{
	FUIStyle ResolvePanelStyle(const UUserWidget* Widget, const FUIStyle& Fallback)
	{
		if (Widget)
		{
			if (const UGameInstance* GI = Widget->GetGameInstance())
			{
				if (const UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
				{
					return Theme->GetActiveUIStyle();
				}
			}
		}
		// Design-time (sem GameInstance/subsystem): carrega o DT_UI_Styles
		// direto e usa a row "Default", para o Designer pintar/mostrar os
		// brushes igual ao runtime (caso contrário FUIStyle vem vazio).
		// Design-time relê o DT a cada chamada: editar o DT_UI_Styles e
		// RECOMPILAR o WBP já reflete (sem reiniciar o editor).
		FUIStyle DesignStyle;
		bool bHas = false;
		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("UIPanelDesign"), false))
			{
				DesignStyle = Row->Style;
				bHas = true;
			}
		}
		return bHas ? DesignStyle : Fallback;
	}
}

void UUIPanel_Base::RefreshUIStyle()
{
	if (!Background)
	{
		return;
	}
	const FUIStyle Fallback;
	const FUIStyle AS = ResolvePanelStyle(this, Fallback);
	const FUIStylePanel& P = AS.Panel;

	// ---- Modo TEXTURA (padrão Hyper): brush por EUIPanelTexture ----
	// Fiel ao UI_Panel_Master do Hyper: só faz SetBrush nos dois Borders
	// (Find no mapa por chave). Sem padding/visibility — a arte da textura
	// já traz a moldura; o conteúdo é injetado pelo WBP filho.
	// Seed dos mapas da instância a partir do tema quando vazios — assim o
	// Details mostra Panel Background/Outline preenchidos e editáveis (igual
	// ao Hyper, cujo `Panels` é alimentado pelo estilo). Edições do designer
	// têm prioridade; o tema (P) é fallback por chave.
	if (Panels.PanelBackground.Num() == 0) { Panels.PanelBackground = P.PanelBackground; }
	if (Panels.PanelOutline.Num() == 0)    { Panels.PanelOutline    = P.PanelOutline; }

	const FSlateBrush* BgTex = nullptr;
	if (PanelTexture != EUIPanelTexture::None)
	{
		BgTex = Panels.PanelBackground.Find(PanelTexture);
		if (!BgTex) { BgTex = P.PanelBackground.Find(PanelTexture); }
	}
	if (BgTex)
	{
		Background->SetBrush(*BgTex);
		if (Outline)
		{
			// Hyper: Find sempre seguido de SetBrush. No Hyper a entrada de
			// outline ausente é um brush TRANSPARENTE (alpha 0) — não some
			// widget, só não desenha. Um FSlateBrush default desenha um
			// retângulo BRANCO; o equivalente correto é DrawAs=NoDrawType.
			const FSlateBrush* OlTex = Panels.PanelOutline.Find(PanelTexture);
			if (!OlTex) { OlTex = P.PanelOutline.Find(PanelTexture); }
			static const FSlateBrush NoDrawBrush = []
			{
				FSlateBrush B;
				B.DrawAs = ESlateBrushDrawType::NoDrawType;
				return B;
			}();
			Outline->SetBrush(OlTex ? *OlTex : NoDrawBrush);
		}
		BP_ApplyPanelStyle(P);
		return;
	}

	// ---- Modo COR (RoundedBox) ----
	if (Outline)
	{
		Outline->SetVisibility(ESlateVisibility::Collapsed);
	}

	FLinearColor Fill;
	FLinearColor OutlineColor = P.BorderColor;
	switch (PanelType)
	{
	case EUIPanelType::Secondary: Fill = P.BgRaised; break;
	case EUIPanelType::Tertiary:  Fill = P.BgSunken; break;
	case EUIPanelType::Card:      Fill = P.CardSelectedBg; OutlineColor = P.CardSelectedBorder; break;
	case EUIPanelType::Primary:
	case EUIPanelType::None:
	default:                      Fill = P.Bg; break;
	}

	FSlateBrush Brush = Background->Background;
	Brush.TintColor = FSlateColor(Fill);
	if (bRoundedBackground)
	{
		const float R = bUseSmallPadding ? P.CornerRadiusSmall : P.CornerRadius;
		Brush.DrawAs = ESlateBrushDrawType::RoundedBox;
		Brush.OutlineSettings = FSlateBrushOutlineSettings(
			FVector4(R, R, R, R), FSlateColor(OutlineColor), P.BorderWidth);
		Brush.OutlineSettings.RoundingType = ESlateBrushRoundingType::FixedRadius;
	}
	else
	{
		Brush.DrawAs = ESlateBrushDrawType::Box;
		Brush.OutlineSettings = FSlateBrushOutlineSettings(
			FVector4(0, 0, 0, 0), FSlateColor(OutlineColor), P.BorderWidth);
	}
	Background->SetBrush(Brush);
	Background->SetPadding(bUseSmallPadding ? P.PaddingSmall : P.Padding);

	BP_ApplyPanelStyle(P);
}

void UUIPanel_Base::NativePreConstruct()
{
	Super::NativePreConstruct();
	RefreshUIStyle();
}

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

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

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

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