#include "ZMMOThemeSubsystem.h"

#include "ZMMOThemeDataAsset.h"
#include "Engine/DataTable.h"
#include "Engine/Texture2D.h"
#include "Sound/SoundBase.h"
#include "NiagaraSystem.h"
#include "Misc/DateTime.h"
#include "UI/ThemeCalendarRow.h"
#include "UI/UIStyleRow.h"

namespace
{
	/** Row Name da linha de estilo de fallback em DT_UI_Styles. */
	const FName GUIStyleDefaultRow(TEXT("Default"));
}

void UZMMOThemeSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);

	DefaultTheme = DefaultThemeAsset.LoadSynchronous();
	if (!DefaultTheme)
	{
		UE_LOG(LogTemp, Warning,
			TEXT("[ZMMOThemeSubsystem] DefaultThemeAsset is not set. UI will have no theme."));
	}

	ResolveActiveTheme();

	// Garantia: se ResolveActiveTheme não disparou ResolveActiveUIStyle (porque
	// ActiveTheme não mudou — caso comum quando DefaultTheme é nullptr e nada
	// resolveu), força a carga do DT_UI_Styles agora para não deixar
	// ActiveUIStyle como FUIStyle() default (brushes vazios → nada renderiza
	// em runtime). O fallback interno acha a linha "Default" do DT.
	ResolveActiveUIStyle(ActiveThemeId);
}

void UZMMOThemeSubsystem::Deinitialize()
{
	ActiveTheme = nullptr;
	DefaultTheme = nullptr;
	Super::Deinitialize();
}

void UZMMOThemeSubsystem::ApplyServerTheme(FName ThemeId)
{
	ServerThemeId = ThemeId;
	ResolveActiveTheme();
}

void UZMMOThemeSubsystem::ForceTheme(FName ThemeId)
{
	ForcedThemeId = ThemeId;
	ResolveActiveTheme();
}

void UZMMOThemeSubsystem::ClearForcedTheme()
{
	ForcedThemeId = NAME_None;
	ResolveActiveTheme();
}

void UZMMOThemeSubsystem::ResolveActiveTheme()
{
	FName Resolved = NAME_None;

	if (!ForcedThemeId.IsNone())
	{
		Resolved = ForcedThemeId;
	}
#if !UE_BUILD_SHIPPING
	else if (!DevThemeOverride.IsNone())
	{
		Resolved = DevThemeOverride;
	}
#endif
	else if (!ServerThemeId.IsNone())
	{
		Resolved = ServerThemeId;
	}
	else
	{
		Resolved = ResolveByCalendar();
	}

	UZMMOThemeDataAsset* NewActive = !Resolved.IsNone() ? LoadThemeById(Resolved) : nullptr;
	if (!NewActive)
	{
		NewActive = DefaultTheme;
		Resolved = DefaultTheme ? DefaultTheme->ThemeId : NAME_None;
	}

	if (NewActive != ActiveTheme || Resolved != ActiveThemeId)
	{
		ActiveTheme = NewActive;
		ActiveThemeId = Resolved;
		ResolveActiveUIStyle(ActiveThemeId);
		OnThemeChanged.Broadcast(ActiveThemeId);
	}
}

void UZMMOThemeSubsystem::ResolveActiveUIStyle(FName ThemeId)
{
	// Reset para os defaults do struct antes de aplicar a linha resolvida —
	// assim um tema sem linha cai num estado coerente (paleta Aurora Arcana).
	ActiveUIStyle = FUIStyle();

	UDataTable* Table = UIStyleTable.LoadSynchronous();
	if (!Table)
	{
		return;
	}

	const FUIStyleRow* Row = nullptr;
	if (!ThemeId.IsNone())
	{
		Row = Table->FindRow<FUIStyleRow>(ThemeId, TEXT("UIStyle"));
	}
	if (!Row)
	{
		// Fallback: linha "Default" (mesma política dos assets, §5).
		Row = Table->FindRow<FUIStyleRow>(GUIStyleDefaultRow, TEXT("UIStyle"));
	}
	if (Row)
	{
		ActiveUIStyle = Row->Style;
	}
}

FName UZMMOThemeSubsystem::ResolveByCalendar() const
{
	UDataTable* Table = CalendarTable.LoadSynchronous();
	if (!Table)
	{
		return NAME_None;
	}

	const FDateTime Now = FDateTime::Now();
	const int32 NowMonth = Now.GetMonth();
	const int32 NowDay = Now.GetDay();
	const int32 NowMD = NowMonth * 100 + NowDay;

	FName Best = NAME_None;
	int32 BestPriority = MIN_int32;

	TArray<FName> RowNames = Table->GetRowNames();
	for (const FName& RowName : RowNames)
	{
		const FThemeCalendarRow* Row = Table->FindRow<FThemeCalendarRow>(RowName, TEXT("ThemeCalendar"));
		if (!Row || Row->ThemeId.IsNone())
		{
			continue;
		}

		const int32 StartMD = Row->StartMonth * 100 + Row->StartDay;
		const int32 EndMD   = Row->EndMonth   * 100 + Row->EndDay;

		const bool bInRange = (StartMD <= EndMD)
			? (NowMD >= StartMD && NowMD <= EndMD)
			: (NowMD >= StartMD || NowMD <= EndMD); // wraps across year (e.g. 12-15 -> 01-05)

		if (bInRange && Row->Priority > BestPriority)
		{
			Best = Row->ThemeId;
			BestPriority = Row->Priority;
		}
	}

	return Best;
}

UZMMOThemeDataAsset* UZMMOThemeSubsystem::LoadThemeById(FName ThemeId) const
{
	if (const TSoftObjectPtr<UZMMOThemeDataAsset>* Soft = ThemeRegistry.Find(ThemeId))
	{
		return Soft->LoadSynchronous();
	}
	return nullptr;
}

const FThemeEntry* UZMMOThemeSubsystem::FindEntryWithFallback(EZMMOThemeKey Key) const
{
	if (ActiveTheme)
	{
		if (const FThemeEntry* Entry = ActiveTheme->FindEntry(Key))
		{
			return Entry;
		}
	}
	if (DefaultTheme && DefaultTheme != ActiveTheme)
	{
		if (const FThemeEntry* Entry = DefaultTheme->FindEntry(Key))
		{
			return Entry;
		}
	}
	return nullptr;
}

UTexture2D* UZMMOThemeSubsystem::GetTexture(EZMMOThemeKey Key) const
{
	const FThemeEntry* Entry = FindEntryWithFallback(Key);
	return Entry ? Entry->Texture.LoadSynchronous() : nullptr;
}

USoundBase* UZMMOThemeSubsystem::GetSound(EZMMOThemeKey Key) const
{
	const FThemeEntry* Entry = FindEntryWithFallback(Key);
	return Entry ? Entry->Sound.LoadSynchronous() : nullptr;
}

UNiagaraSystem* UZMMOThemeSubsystem::GetVFX(EZMMOThemeKey Key) const
{
	const FThemeEntry* Entry = FindEntryWithFallback(Key);
	return Entry ? Entry->VFX.LoadSynchronous() : nullptr;
}

UObject* UZMMOThemeSubsystem::GetGeneric(EZMMOThemeKey Key) const
{
	const FThemeEntry* Entry = FindEntryWithFallback(Key);
	return Entry ? Entry->Generic.LoadSynchronous() : nullptr;
}
