// Aesir Interactive GmbH, (c) 2019

#include "ServiceLocator.h"



#if WITH_DEV_AUTOMATION_TESTS

#include "Components/ActorComponent.h"
#include "Components/SceneComponent.h"

static_assert(TModels<CHasStaticUClass, UActorComponent>::Value, "Actor component should have a static uclass");
static_assert(TModels<CHasStaticUClass, UObject>::Value);
static_assert(!TModels<CHasStaticUClass, IInterface_AssetUserData>::Value);

static_assert(TModels<CHasInterfaceUClass, IInterface_AssetUserData>::Value);
static_assert(TIsUInterface<IInterface_AssetUserData>::Value);
static_assert(TModels<CHasInterfaceUClass,UActorComponent>::Value);
static_assert(!TModels<CHasInterfaceUClass, UObject>::Value);
static_assert(!TIsUInterface<UActorComponent>::Value);
static_assert(!TIsUInterface<UObject>::Value);


class FServiceUser
{
public:
	USceneComponent* SceneComponent = nullptr;
	UActorComponent* ActorComponent = nullptr;
};

BEGIN_DEFINE_SPEC(TServiceLocatorSpec, "Workshop.ServiceLocator", EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)
	FServiceUser ServiceUser;
	FServiceLocator ServiceLocator;
	USceneComponent* SceneComponent = nullptr;
	UActorComponent* ActorComponent = nullptr;
END_DEFINE_SPEC(TServiceLocatorSpec)


void TServiceLocatorSpec::Define()
{
	BeforeEach([this]()
	{
		SceneComponent = NewObject<USceneComponent>();
		ActorComponent = NewObject<UActorComponent>();
	});

	Describe("ProvideService", [this]()
	{
		It("Should work for UObjects", [this]()
		{
			TestNull("GetService<UActorComponent>()", ServiceLocator.GetService<UActorComponent>());
			ServiceLocator.ProvideService<UActorComponent>(ActorComponent);

			TestEqual("GetService<UActorComponent>()", ServiceLocator.GetService<UActorComponent>(), ActorComponent);
		});

		It("Should work for UInterfaces", [this]()
		{
			TestNull("GetService<UActorComponent>()", ServiceLocator.GetService<IInterface_AssetUserData>().GetInterface());
			ServiceLocator.ProvideService<IInterface_AssetUserData>(ActorComponent);

			TestEqual("GetService<UInterface_AssetUserData>()",
				ServiceLocator.GetService<IInterface_AssetUserData>().GetInterface(),
				static_cast<IInterface_AssetUserData*>(ActorComponent));
		});
	});

	Describe("GetServices", [this]()
	{
		BeforeEach([this]()
		{
			ServiceLocator.ProvideService<UActorComponent>(ActorComponent);
			ServiceLocator.ProvideService<USceneComponent>(SceneComponent);
			ServiceLocator.ProvideService<IInterface_AssetUserData>(ActorComponent);
		});
		It("Should get all the services", [this]()
		{
			auto [InjectedActorComponent, InjectedSceneComponent, InjectedInterface] = ServiceLocator.GetServices<UActorComponent, USceneComponent, IInterface_AssetUserData>();
			TestEqual(TEXT("InjectedActorComponent"), InjectedActorComponent, ActorComponent);
			TestEqual(TEXT("InjectedSceneComponent"), InjectedSceneComponent, SceneComponent);
			TestEqual(TEXT("InjectedInterface"), InjectedInterface.GetInterface(), static_cast<IInterface_AssetUserData*>(ActorComponent));
		});
	});

}

#endif