#include "UICommonText_Base.h"

#include "ZMMOThemeSubsystem.h"
#include "Engine/GameInstance.h"
#include "Engine/DataTable.h"
#include "Styling/CoreStyle.h"
#include "UI/UIStyleRow.h"

namespace
{
	const TCHAR* GStylesDT = TEXT("/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles");

	// Retorna POR VALOR (cópia fresca): nunca persiste ponteiro de FontObject
	// num static não-rastreado por GC (causa AV ao hashear a fonte no preview).
	FUIStyle ResolveTextStyle(const UWidget* Widget, const FUIStyle& Fallback)
	{
		if (Widget)
		{
			if (const UGameInstance* GI = Widget->GetGameInstance())
			{
				if (const UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
				{
					return Theme->GetActiveUIStyle();
				}
			}
		}
		// Design-time relê o DT a cada chamada. Local (não-static): a fonte
		// fica viva apenas durante o RefreshUIStyle (o UObject UFont é mantido
		// pelo DataTable carregado — sem ponteiro pendurado entre frames).
		FUIStyle DesignStyle;
		bool bHas = false;
		if (const UDataTable* DT = LoadObject<UDataTable>(nullptr, GStylesDT))
		{
			if (const FUIStyleRow* Row = DT->FindRow<FUIStyleRow>(
				FName(TEXT("Default")), TEXT("UITextDesign"), false))
			{
				DesignStyle = Row->Style;
				bHas = true;
			}
		}
		return bHas ? DesignStyle : Fallback;
	}

	// Fallback: categorias clássicas a partir de FUIStyle.Text (já configurado
	// com as FF_ fonts no DT) enquanto o mapa TextRoles não for preenchido.
	bool LegacyRole(const FUIStyle& AS, FName Role, FSlateFontInfo& OutFont,
		FLinearColor& OutColor, bool& bOutUpper)
	{
		const FUIStyleText& T = AS.Text;
		const FUIStylePalette& P = AS.Palette;
		const FString R = Role.ToString();
		bOutUpper = false;
		if (R.Equals(TEXT("Title"), ESearchCase::IgnoreCase))        { OutFont = T.TitleFont;   OutColor = P.Text;    return true; }
		if (R.Equals(TEXT("Section"), ESearchCase::IgnoreCase))      { OutFont = T.SectionFont; OutColor = P.Text;    return true; }
		if (R.Equals(TEXT("Button"), ESearchCase::IgnoreCase))       { OutFont = T.ButtonFont;  OutColor = P.Text;    return true; }
		if (R.Equals(TEXT("Label"), ESearchCase::IgnoreCase))        { OutFont = T.LabelFont;   OutColor = P.Text2;   bOutUpper = T.bLabelUppercase; return true; }
		if (R.Equals(TEXT("Dim"), ESearchCase::IgnoreCase))          { OutFont = T.BodyFont;    OutColor = P.TextDim; return true; }
		if (R.Equals(TEXT("Body"), ESearchCase::IgnoreCase))         { OutFont = T.BodyFont;    OutColor = P.Text;    return true; }
		return false;
	}
}

void UUICommonText_Base::RefreshUIStyle()
{
	const FUIStyle Fallback;
	const FUIStyle AS = ResolveTextStyle(this, Fallback);

	FSlateFontInfo RoleFont;
	FLinearColor RoleColor = AS.Palette.Text;
	bool bUpper = false;

	// 1) Mapa data-driven (autor define no DT_UI_Styles).
	if (const FUITextStyle* E = AS.TextRoles.Find(TextRole))
	{
		RoleFont  = E->Font;
		RoleColor = E->Color;
		bUpper    = E->bUppercase;
	}
	// 2) Fallback p/ categorias clássicas de FUIStyle.Text.
	else if (!LegacyRole(AS, TextRole, RoleFont, RoleColor, bUpper))
	{
		RoleFont  = AS.Text.BodyFont;
		RoleColor = AS.Palette.Text;
	}

	// Nunca deixa sem fonte (evita o "A BASIC LATIN" gigante/quebrado).
	if (RoleFont.FontObject == nullptr && RoleFont.CompositeFont == nullptr)
	{
		RoleFont = FCoreStyle::GetDefaultFontStyle("Regular", 14);
	}

	SetFont(RoleFont);
	SetColorAndOpacity(FSlateColor(RoleColor));

	if (bUpper)
	{
		const FText Cur = GetText();
		if (!Cur.IsEmpty())
		{
			SetText(FText::FromString(Cur.ToString().ToUpper()));
		}
	}
}

TArray<FString> UUICommonText_Base::GetTextRoleOptions() const
{
	return GetThemeTextRoleOptions();
}

TArray<FString> UUICommonText_Base::GetThemeTextRoleOptions()
{
	TArray<FString> Options;
	// Categorias clássicas sempre disponíveis (fallback garantido).
	for (const TCHAR* N : { TEXT("Title"), TEXT("Section"), TEXT("Body"),
		TEXT("Button"), TEXT("Label"), TEXT("Dim") })
	{
		Options.Add(N);
	}
	// + chaves definidas pelo autor no DT_UI_Styles (data-driven).
	if (const UDataTable* DT = LoadObject<UDataTable>(nullptr, GStylesDT))
	{
		if (const FUIStyleRow* Row = DT->FindRow<FUIStyleRow>(
			FName(TEXT("Default")), TEXT("UITextRoleOptions"), false))
		{
			for (const TPair<FName, FUITextStyle>& Pair : Row->Style.TextRoles)
			{
				Options.AddUnique(Pair.Key.ToString());
			}
		}
	}
	return Options;
}

void UUICommonText_Base::SynchronizeProperties()
{
	Super::SynchronizeProperties();
	RefreshUIStyle();
}
