// Copyright (c) Microsoft Corporation. 
// Licensed under the MIT license.

#include "CoreMinimal.h"
#include "CoreGlobals.h"
#include "EngineGlobals.h"
#include "Misc/AutomationTest.h"
#include "Modules/ModuleManager.h"
//Automation
#include "Tests/AutomationCommon.h"
#include "Tests/AutomationEditorCommon.h"
#include "Interfaces/IPluginManager.h"
#include "SimplygonModule.h"
#include "SimplygonSettings.h"
#include "SimplygonPluginMeshReductionModule.h"

#include "AutomationDriverCommon.h"
#include "AutomationDriverTypeDefs.h"
#include "IMeshReductionManagerModule.h"
#include "SimplygonTestsHelper.h"
#include "SimplygonEditorModule.h"
#include "Engine/StaticMesh.h"
#include "Engine/SkeletalMesh.h"

#include "Algo/AnyOf.h"
#include "Algo/AllOf.h"
#include "Rendering/SkeletalMeshModel.h"


DEFINE_LOG_CATEGORY_STATIC(LogSimplygonTests, All, All);

/* Standard Reduction Interface Test*/
#if 0
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonHLODTest, "Simplygon.HLOD.Instanced.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonHLODTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/HLOD/HLOD_Instanced");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	if (!CurrentWorld->HierarchicalLODBuilder)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find HLOD Builder."));
		return false;
	}

	CurrentWorld->HierarchicalLODBuilder->BuildMeshesForLODActors(true);

	

	TestEqual("HLOD needs building", CurrentWorld->HierarchicalLODBuilder->NeedsBuild(), false);

	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonHLODLandscapeCullingTest, "Simplygon.HLOD.LandscapeCulling.GenerateLOD", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonHLODLandscapeCullingTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/HLOD/HLOD_Landscape");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	if (!CurrentWorld->HierarchicalLODBuilder)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find HLOD Builder."));
		return false;
	}

	CurrentWorld->HierarchicalLODBuilder->BuildMeshesForLODActors(true);



	TestEqual("HLOD needs building", CurrentWorld->HierarchicalLODBuilder->NeedsBuild(true), false);

	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonHLODClippingPlanesTest, "Simplygon.HLOD.ClippingPlanes.GenerateLOD", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonHLODClippingPlanesTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/HLOD/HLOD_ClippingPlanes");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	if (!CurrentWorld->HierarchicalLODBuilder)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find HLOD Builder."));
		return false;
	}

	
	CurrentWorld->HierarchicalLODBuilder->BuildMeshesForLODActors(true);
	
	
	//NOTE: Due to how the key is invalidate the check using  CurrentWorld->HierarchicalLODBuilder->NeedsBuild() usually fails.
	// Using an alternate approach to check any packages were generated. Note we still cannot 

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	CurrentWorld->HierarchicalLODBuilder->GetMeshesPackagesToSave(CurrentWorld->GetLevel(0), OutPackagesToSave);

	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);
	return sucess;
}


IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonHLODSplineComponentTest, "Simplygon.HLOD.SplineComponent.GenerateLOD", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonHLODSplineComponentTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/HLOD/HLOD_SplineComponent");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	if (!CurrentWorld->HierarchicalLODBuilder)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find HLOD Builder."));
		return false;
	}

	CurrentWorld->HierarchicalLODBuilder->BuildMeshesForLODActors(true);


	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	CurrentWorld->HierarchicalLODBuilder->GetMeshesPackagesToSave(CurrentWorld->GetLevel(0), OutPackagesToSave);

	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);
	return sucess;
}


IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonHLODTangentspaceTest, "Simplygon.HLOD.Tangentspace.GenerateLOD", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonHLODTangentspaceTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/HLOD/HLOD_Tangentspace");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	if (!CurrentWorld->HierarchicalLODBuilder)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find HLOD Builder."));
		return false;
	}

	CurrentWorld->HierarchicalLODBuilder->BuildMeshesForLODActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	CurrentWorld->HierarchicalLODBuilder->GetMeshesPackagesToSave(CurrentWorld->GetLevel(0), OutPackagesToSave);

	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);
	return sucess;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonHLODNavMeshVisibilityTest, "Simplygon.HLOD.NavMeshVisibility.GenerateLOD", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonHLODNavMeshVisibilityTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/HLOD/HLOD_Visibility");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	if (!CurrentWorld->HierarchicalLODBuilder)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find HLOD Builder."));
		return false;
	}

	CurrentWorld->HierarchicalLODBuilder->BuildMeshesForLODActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	CurrentWorld->HierarchicalLODBuilder->GetMeshesPackagesToSave(CurrentWorld->GetLevel(0), OutPackagesToSave);

	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);
	return sucess;
}


IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonHLODWPOffsetTest, "Simplygon.HLOD.WorldPosistionOffset.GenerateLOD", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonHLODWPOffsetTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/HLOD/HLOD_WPOffset");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	if (!CurrentWorld->HierarchicalLODBuilder)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find HLOD Builder."));
		return false;
	}

	CurrentWorld->HierarchicalLODBuilder->BuildMeshesForLODActors(true);
	
	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	CurrentWorld->HierarchicalLODBuilder->GetMeshesPackagesToSave(CurrentWorld->GetLevel(0), OutPackagesToSave);

	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);
	return sucess;
}


IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonNearStandinTest, "Simplygon.Standin.Near.SceneCollapse.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonNearStandinTest::RunTest(const FString& Parameters)
{

	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Near_Kitbash");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}


IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonNearStandinMaterialMergeTest, "Simplygon.Standin.Near.MaterialMerge.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonNearStandinMaterialMergeTest::RunTest(const FString& Parameters)
{

	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Near_Kitbash_MergeMaterial");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonNearStandinNearInstancedTest, "Simplygon.Standin.Near.Instanced.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonNearStandinNearInstancedTest::RunTest(const FString& Parameters)
{

	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Near_Instanced");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonNearGeometryCullingTest, "Simplygon.Standin.Near.GeometryCulling.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonNearGeometryCullingTest::RunTest(const FString& Parameters)
{

	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Near_GeometryCulling");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}


IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonFarStandinTest, "Simplygon.Standin.Far.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonFarStandinTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Far");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonFarClippingPlanesStandinTest, "Simplygon.Standin.Far.ClippingPlanes.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonFarClippingPlanesStandinTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Far_ClippingPlanes");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonFarGeometryCullingStandinTest, "Simplygon.Standin.Far.GeoemetryCulling.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonFarGeometryCullingStandinTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Far_GeometryCulling");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonFarInstancedTest, "Simplygon.Standin.Far.Instanced.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonFarInstancedTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Far_Instanced");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonFarLandscapeCullingTest, "Simplygon.Standin.Far.LandscapeCulling.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonFarLandscapeCullingTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Far_Landscape");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}


IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonFarOccluderTest, "Simplygon.Standin.Far.Occluder.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonFarOccluderTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Far_Occluder");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonFarVisibilityTest, "Simplygon.Standin.Far.Visibility.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FSimplygonFarVisibilityTest::RunTest(const FString& Parameters)
{
	FAutomationEditorCommonUtils::LoadMap("/Game/QA/Standin/Standin_Far_Visibility");
	UWorld* CurrentWorld = SimplygonTestsHelper::GetCurrentWorld();
	if (!CurrentWorld)
	{
		UE_LOG(LogSimplygonTests, Error, TEXT("Failed to find world."));
		return false;
	}

	IStandinUtilitiesModule& StandinModule = FModuleManager::LoadModuleChecked<IStandinUtilitiesModule>("StandinUtilities");
	StandinModule.BuildStandinMeshActors(true);

	bool sucess = true;
	TSet<UPackage*> OutPackagesToSave;
	StandinModule.GetListOfPackagesToSaveForStandins(CurrentWorld->GetLevel(0), OutPackagesToSave);
	sucess &= TestNotEqual<int32>(TEXT("NumOfPackagesToSave"), OutPackagesToSave.Num(), 0);

	return sucess;
}
#endif


//IMPLEMENT_SIMPLE_AUTOMATION_TEST(FSimplygonWorldCompostionTest, "Simplygon.WorldComposition.GenerateLODs", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
//bool FSimplygonWorldCompostionTest::RunTest(const FString& Parameters)
//{
//
//	return true;
//}
