// Copyright CodeSpartan, 2022. All rights reserved.

#include "AsyncPreloadPrimaryAssets.h"
#include "Engine/AssetManager.h"

void UAsyncActionPreloadPrimaryAssetBase::Activate()
{
	if (UAssetManager* Manager = UAssetManager::GetIfInitialized())
	{
		LoadHandle = Manager->PreloadPrimaryAssets(AssetsToLoad, LoadBundles, true);

		if (LoadHandle.IsValid())
		{
			if (!LoadHandle->HasLoadCompleted())
			{
				LoadHandle->BindCompleteDelegate(FStreamableDelegate::CreateUObject(this, &UAsyncActionPreloadPrimaryAssetBase::HandleLoadCompleted));
				return;
			}
		}
	}

	// Either load already succeeded, or it failed
	HandleLoadCompleted();
}

void UAsyncActionPreloadPrimaryAssetBase::HandleLoadCompleted()
{
	LoadHandle.Reset();
	SetReadyToDestroy();
}

void UAsyncActionPreloadPrimaryAssetBase::GetCurrentlyLoadedAssets(TArray<UObject*>& AssetList)
{
	if (UAssetManager* Manager = UAssetManager::GetIfInitialized())
	{
		// The assets may have already been loaded but the handle was invalid, check the original list
		for (const FPrimaryAssetId& IdToLoad : AssetsToLoad)
		{
			UObject* LoadedObject = Manager->GetPrimaryAssetObject(IdToLoad);
			if (LoadedObject)
			{
				AssetList.Add(LoadedObject);
			}
		}
	}
}

UAsyncActionPreloadPrimaryAsset* UAsyncActionPreloadPrimaryAsset::AsyncPreloadPrimaryAsset(UObject* WorldContextObject, FPrimaryAssetId PrimaryAsset, const TArray<FName>& LoadBundles)
{
	UAsyncActionPreloadPrimaryAsset* Action = NewObject<UAsyncActionPreloadPrimaryAsset>();
	Action->AssetsToLoad.Add(PrimaryAsset);
	Action->LoadBundles = LoadBundles;
	Action->RegisterWithGameInstance(WorldContextObject);

	return Action;
}

void UAsyncActionPreloadPrimaryAsset::HandleLoadCompleted()
{
	UObject* AssetLoaded = nullptr;
	TArray<UObject*> AssetList;

	GetCurrentlyLoadedAssets(AssetList);

	if (AssetList.Num() > 0)
	{
		AssetLoaded = AssetList[0];
	}

	Completed.Broadcast(AssetLoaded);
	Super::HandleLoadCompleted();
}

UAsyncActionPreloadPrimaryAssetList* UAsyncActionPreloadPrimaryAssetList::AsyncPreloadPrimaryAssetList(UObject* WorldContextObject, const TArray<FPrimaryAssetId>& PrimaryAssetList, const TArray<FName>& LoadBundles)
{
	UAsyncActionPreloadPrimaryAssetList* Action = NewObject<UAsyncActionPreloadPrimaryAssetList>();
	Action->AssetsToLoad = PrimaryAssetList;
	Action->LoadBundles = LoadBundles;
	Action->RegisterWithGameInstance(WorldContextObject);

	return Action;
}

void UAsyncActionPreloadPrimaryAssetList::HandleLoadCompleted()
{
	TArray<UObject*> AssetList;

	GetCurrentlyLoadedAssets(AssetList);

	Completed.Broadcast(AssetList);
	Super::HandleLoadCompleted();
}

UAsyncActionPreloadPrimaryAssetClass* UAsyncActionPreloadPrimaryAssetClass::AsyncPreloadPrimaryAssetClass(UObject* WorldContextObject, FPrimaryAssetId PrimaryAsset, const TArray<FName>& LoadBundles)
{
	UAsyncActionPreloadPrimaryAssetClass* Action = NewObject<UAsyncActionPreloadPrimaryAssetClass>();
	Action->AssetsToLoad.Add(PrimaryAsset);
	Action->LoadBundles = LoadBundles;
	Action->RegisterWithGameInstance(WorldContextObject);

	return Action;
}

void UAsyncActionPreloadPrimaryAssetClass::HandleLoadCompleted()
{
	TSubclassOf<UObject> AssetLoaded = nullptr;
	TArray<UObject*> AssetList;

	GetCurrentlyLoadedAssets(AssetList);

	if (AssetList.Num() > 0)
	{
		AssetLoaded = Cast<UClass>(AssetList[0]);
	}

	Completed.Broadcast(AssetLoaded);
	Super::HandleLoadCompleted();
}

UAsyncActionPreloadPrimaryAssetClassList* UAsyncActionPreloadPrimaryAssetClassList::AsyncPreloadPrimaryAssetClassList(UObject* WorldContextObject, const TArray<FPrimaryAssetId>& PrimaryAssetList, const TArray<FName>& LoadBundles)
{
	UAsyncActionPreloadPrimaryAssetClassList* Action = NewObject<UAsyncActionPreloadPrimaryAssetClassList>();
	Action->AssetsToLoad = PrimaryAssetList;
	Action->LoadBundles = LoadBundles;
	Action->RegisterWithGameInstance(WorldContextObject);

	return Action;
}

void UAsyncActionPreloadPrimaryAssetClassList::HandleLoadCompleted()
{
	TArray<TSubclassOf<UObject>> AssetClassList;
	TArray<UObject*> AssetList;

	GetCurrentlyLoadedAssets(AssetList);

	for (UObject* LoadedAsset : AssetList)
	{
		UClass* LoadedClass = Cast<UClass>(LoadedAsset);

		if (LoadedClass)
		{
			AssetClassList.Add(LoadedClass);
		}
	}

	Completed.Broadcast(AssetClassList);
	Super::HandleLoadCompleted();
}