// Copyright HyperTwist, Inc. All Rights Reserved.

#include "Misc/AutomationTest.h"

#include "GameFramework/PlayerController.h"
#include "HyperTwistXR/HyperTwistXrPackageValidationLibrary.h"
#include "HyperTwistXR/HyperTwistXrTrainingGameMode.h"
#include "HyperTwistXR/HyperTwistXrTrainingPawn.h"

#if WITH_AUTOMATION_TESTS

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistXrPackagedValidationDefaultsTest,
	"HyperTwist.FirstParty.XR.PackagedValidationDefaults",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistXrPackagedValidationDefaultsTest::RunTest(const FString& Parameters)
{
	const FString DefaultCookMapPath =
		UHyperTwistXrPackageValidationLibrary::GetDefaultPackagedValidationCookMapPath();
	TestEqual(
		TEXT("The XR packaged-validation helper must keep the default cook map stable."),
		DefaultCookMapPath,
		FString(TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_FollowAlongTraining"))
	);
	TestEqual(
		TEXT("The XR packaged-validation launch surface id must stay stable."),
		UHyperTwistXrPackageValidationLibrary::GetValidationLaunchSurfaceId(),
		FString(TEXT("xr/openxr-desktop-training-packaged-validation-launch-surface"))
	);
	TestEqual(
		TEXT("The XR packaged-validation game mode class path must stay stable."),
		UHyperTwistXrPackageValidationLibrary::GetValidationGameModeClassPath(),
		FString(TEXT("/Script/UnrealHyperTwist.HyperTwistXrTrainingGameMode"))
	);
	TestEqual(
		TEXT("The XR packaged-validation map URL must stay game-mode overridden."),
		UHyperTwistXrPackageValidationLibrary::BuildPackagedValidationMapUrl(DefaultCookMapPath),
		FString(TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_FollowAlongTraining?game=/Script/UnrealHyperTwist.HyperTwistXrTrainingGameMode"))
	);

	const AHyperTwistXrTrainingGameMode* GameModeDefaults =
		GetDefault<AHyperTwistXrTrainingGameMode>();
	TestNotNull(TEXT("The XR training game mode defaults must exist."), GameModeDefaults);
	if (GameModeDefaults == nullptr)
	{
		return false;
	}

	TestTrue(
		TEXT("The XR training game mode must keep the bounded XR pawn as its default pawn."),
		GameModeDefaults->DefaultPawnClass.Get() == AHyperTwistXrTrainingPawn::StaticClass()
	);
	TestTrue(
		TEXT("The XR training game mode must keep the plain player controller by default."),
		GameModeDefaults->PlayerControllerClass.Get() == APlayerController::StaticClass()
	);
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistXrPackagedValidationReportProofStatesTest,
	"HyperTwist.FirstParty.XR.PackagedValidationReportProofStates",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistXrPackagedValidationReportProofStatesTest::RunTest(
	const FString& Parameters
)
{
	AHyperTwistXrTrainingPawn* Pawn =
		NewObject<AHyperTwistXrTrainingPawn>(GetTransientPackage());
	TestNotNull(
		TEXT("The XR packaged-validation report builder must construct a transient XR training pawn for proof-state checks."),
		Pawn
	);
	if (Pawn == nullptr)
	{
		return false;
	}

	const FString DefaultCookMapPath =
		UHyperTwistXrPackageValidationLibrary::GetDefaultPackagedValidationCookMapPath();
	const FString ReportPath = TEXT("C:/HyperTwist/validation/xr-proof.json");

	const FHyperTwistXrPackagedValidationReport PendingHmdReport =
		UHyperTwistXrPackageValidationLibrary::BuildPackagedValidationReport(
			Pawn,
			DefaultCookMapPath,
			ReportPath,
			8.0,
			false,
			false,
			0.0f
		);
	TestTrue(
		TEXT("The packaged XR validation report must stay structurally valid when no headset session has been observed yet."),
		PendingHmdReport.IsStructurallyValid()
	);
	TestEqual(
		TEXT("The packaged XR validation report must stay in the pending-HMD proof state until a headset session is observed."),
		PendingHmdReport.PackagedProofStatus,
		FString(TEXT("pending-hmd-session-observation"))
	);
	TestTrue(
		TEXT("The packaged XR validation report must retain both remaining packaged gates before any hardware observation exists."),
		PendingHmdReport.RemainingGateIds.Contains(
			TEXT("xr/windows-packaged-headset-session-observation"))
			&& PendingHmdReport.RemainingGateIds.Contains(
				TEXT("xr/windows-packaged-controller-input-observation"))
	);

	Pawn->bHeadMountedDisplayConnected = true;
	Pawn->bHeadMountedDisplayEnabled = true;
	const FHyperTwistXrPackagedValidationReport PendingControllerReport =
		UHyperTwistXrPackageValidationLibrary::BuildPackagedValidationReport(
			Pawn,
			DefaultCookMapPath,
			ReportPath,
			8.0,
			true,
			false,
			0.0f
		);
	TestEqual(
		TEXT("The packaged XR validation report must move to pending-controller proof once a headset session is observed without live controller input."),
		PendingControllerReport.PackagedProofStatus,
		FString(TEXT("pending-controller-input-observation"))
	);
	TestTrue(
		TEXT("The packaged XR validation report must retain only the controller-input gate once the headset session is observed."),
		PendingControllerReport.RemainingGateIds.Num() == 1
			&& PendingControllerReport.RemainingGateIds.Contains(
				TEXT("xr/windows-packaged-controller-input-observation"))
	);

	Pawn->LeftGripValue = 0.7f;
	TestTrue(
		TEXT("The XR training pawn helper must treat non-zero controller grip input as live controller activity."),
		Pawn->HasObservedControllerInputActivity()
			&& Pawn->GetControllerInputObservationMagnitude() >= 0.7f
	);
	const FHyperTwistXrPackagedValidationReport ObservedControllerReport =
		UHyperTwistXrPackageValidationLibrary::BuildPackagedValidationReport(
			Pawn,
			DefaultCookMapPath,
			ReportPath,
			8.0,
			true,
			true,
			Pawn->GetControllerInputObservationMagnitude()
		);
	TestEqual(
		TEXT("The packaged XR validation report must surface observed live controller input once both the headset session and controller activity were observed."),
		ObservedControllerReport.PackagedProofStatus,
		FString(TEXT("observed-live-controller-input"))
	);
	TestTrue(
		TEXT("The packaged XR validation report must clear remaining packaged hardware gates once live controller activity has been observed."),
		ObservedControllerReport.RemainingGateIds.Num() == 0
	);
	TestEqual(
		TEXT("The packaged XR validation report must preserve the stable controller settings ownership id."),
		ObservedControllerReport.ControllerSettingsOwnerId,
		FString(TEXT("xr-openxr-controller-settings-owner/v1"))
	);
	return true;
}

#endif
