#include "ZMMOJobsSubsystem.h"

#include "AssetRegistry/AssetRegistryModule.h"
#include "Modules/ModuleManager.h"
#include "ZMMOJobDataAsset.h"

DEFINE_LOG_CATEGORY_STATIC(LogZMMOJobs, Log, All);

void UZMMOJobsSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	LoadJobsFromAssetRegistry();
	UE_LOG(LogZMMOJobs, Log, TEXT("[ZMMOJobsSubsystem] Initialize: %d job(s) carregados"), CachedJobs.Num());
}

void UZMMOJobsSubsystem::Deinitialize()
{
	CachedJobs.Empty();
	Super::Deinitialize();
}

void UZMMOJobsSubsystem::LoadJobsFromAssetRegistry()
{
	FAssetRegistryModule& AssetRegistryModule =
		FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
	IAssetRegistry& AR = AssetRegistryModule.Get();

	// Editor pode chamar antes de scan inicial. Standalone/PIE scan ja' rodou.
	// SearchAllAssets(false) = nao-blocking; assume cache populado em runtime.
#if WITH_EDITOR
	AR.SearchAllAssets(true);  // bloqueia editor; ok em Initialize
#endif

	TArray<FAssetData> Assets;
	const FTopLevelAssetPath ClassPath(UZMMOJobDataAsset::StaticClass()->GetClassPathName());
	AR.GetAssetsByClass(ClassPath, Assets, /*bSearchSubClasses*/ true);

	for (const FAssetData& AssetData : Assets)
	{
		UZMMOJobDataAsset* Job = Cast<UZMMOJobDataAsset>(AssetData.GetAsset());
		if (Job == nullptr) { continue; }

		if (CachedJobs.Contains(Job->ClassId))
		{
			UE_LOG(LogZMMOJobs, Warning,
				TEXT("[ZMMOJobsSubsystem] Duplicate ClassId=%d (existing=%s, new=%s) — ignorando segundo"),
				Job->ClassId,
				*CachedJobs[Job->ClassId]->GetName(),
				*Job->GetName());
			continue;
		}

		CachedJobs.Add(Job->ClassId, Job);
		UE_LOG(LogZMMOJobs, Verbose,
			TEXT("[ZMMOJobsSubsystem] Cached classId=%d name=%s display=%s"),
			Job->ClassId, *Job->TechnicalName, *Job->DisplayName.ToString());
	}
}

UZMMOJobDataAsset* UZMMOJobsSubsystem::GetJobData(int32 ClassId) const
{
	if (const TObjectPtr<UZMMOJobDataAsset>* Found = CachedJobs.Find(ClassId))
	{
		return Found->Get();
	}
	return nullptr;
}

TArray<UZMMOJobDataAsset*> UZMMOJobsSubsystem::GetJobsByTier(EZMMOJobTier Tier) const
{
	TArray<UZMMOJobDataAsset*> Out;
	Out.Reserve(CachedJobs.Num());
	for (const TPair<int32, TObjectPtr<UZMMOJobDataAsset>>& Pair : CachedJobs)
	{
		if (Pair.Value && Pair.Value->Tier == Tier)
		{
			Out.Add(Pair.Value.Get());
		}
	}
	return Out;
}

TArray<UZMMOJobDataAsset*> UZMMOJobsSubsystem::GetEligibleNextJobs(int32 CurrentClassId) const
{
	TArray<UZMMOJobDataAsset*> Out;
	Out.Reserve(4);  // tipico: 2-6 destinos
	for (const TPair<int32, TObjectPtr<UZMMOJobDataAsset>>& Pair : CachedJobs)
	{
		if (Pair.Value && Pair.Value->ParentClassId == CurrentClassId
		    && Pair.Value->ClassId != CurrentClassId)
		{
			Out.Add(Pair.Value.Get());
		}
	}
	return Out;
}
