// Copyright HyperTwist, Inc. All Rights Reserved.

#include "Misc/AutomationTest.h"

#include "HyperTwistSimulation/HyperTwistClassicCubeGameMode.h"
#include "HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.h"
#include "HyperTwistSimulation/HyperTwistClassicCubePlayerController.h"
#include "HyperTwistSimulation/HyperTwistClassicCubeTypes.h"

#if WITH_AUTOMATION_TESTS

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeGameModeDefaultsTest,
	"HyperTwist.Simulation.ClassicCube.GameModeDefaults",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeGameModeDefaultsTest::RunTest(const FString& Parameters)
{
	AHyperTwistClassicCubeGameMode* GameMode = NewObject<AHyperTwistClassicCubeGameMode>();
	TestNotNull(TEXT("The classic cube game mode must be constructible."), GameMode);
	if (GameMode == nullptr)
	{
		return false;
	}

	TestEqual(
		TEXT("The classic cube game mode must default to the first-party classic cube player controller."),
		GameMode->PlayerControllerClass.Get(),
		AHyperTwistClassicCubePlayerController::StaticClass()
	);
	TestEqual(
		TEXT("The classic cube game mode must default to the first-party orbit camera pawn."),
		GameMode->DefaultPawnClass.Get(),
		AHyperTwistClassicCubeOrbitPawn::StaticClass()
	);
	TestTrue(TEXT("The classic cube game mode must still auto-create its HUD by default."), GameMode->bAutoCreateHud);
	TestTrue(TEXT("The classic cube game mode must still auto-spawn the cube actor by default."), GameMode->bAutoSpawnCubeActor);
	TestTrue(
		TEXT("The classic cube game mode must recover a playable orbit camera when map anchors are missing."),
		GameMode->bEnsurePlayableOrbitPawn
	);
	TestTrue(
		TEXT("The classic cube game mode must recover presentation lighting in sparse maps."),
		GameMode->bEnsureRuntimeLighting
	);
	TestTrue(
		TEXT("The classic cube game mode must keep its default cube spawn above the generic validation-map floor."),
		GameMode->CubeSpawnLocation.Z > 0.0f
	);
	TestEqual(
		TEXT("The default classic cube mode must boot in free-play mode unless a dedicated follow-along map overrides it."),
		GameMode->DefaultSessionMode,
		EHyperTwistClassicCubeSessionMode::FreePlay
	);
	TestTrue(
		TEXT("The Classic game mode must keep its runtime settlement loop tick-capable."),
		GameMode->PrimaryActorTick.bCanEverTick
	);
	TestTrue(
		TEXT("The Classic game mode must start with settlement processing enabled."),
		GameMode->PrimaryActorTick.bStartWithTickEnabled
	);
	TestTrue(
		TEXT("The Classic game mode must service wall-clock settlement diagnostics while the world is paused."),
		GameMode->PrimaryActorTick.bTickEvenWhenPaused
	);
	TestTrue(
		TEXT("The classic solver worker must have a positive time budget."),
		GameMode->SolverTimeLimitMs > 0
	);
	TestTrue(
		TEXT("The classic solver worker must accept at least one move."),
		GameMode->SolverMaximumMoveCount > 0
	);
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubePlayerControllerDefaultsTest,
	"HyperTwist.Simulation.ClassicCube.PlayerControllerDefaults",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubePlayerControllerDefaultsTest::RunTest(const FString& Parameters)
{
	AHyperTwistClassicCubePlayerController* PlayerController =
		NewObject<AHyperTwistClassicCubePlayerController>();
	TestNotNull(TEXT("The classic cube player controller must be constructible."), PlayerController);
	if (PlayerController == nullptr)
	{
		return false;
	}

	TestTrue(TEXT("The classic cube player controller must show the mouse cursor by default."), PlayerController->bShowMouseCursor);
	TestTrue(TEXT("The classic cube player controller must keep touch input enabled by default."), PlayerController->bEnableTouchTurnInput);
	TestTrue(
		TEXT("The classic cube player controller must bind a fresh-attempt shortcut by default."),
		PlayerController->bBindFreshAttemptShortcut
	);
	TestTrue(TEXT("The classic cube player controller must expose a solver hint shortcut."), PlayerController->bBindHintShortcut);
	TestNotNull(
		TEXT("Classic Cube must inherit the same global dictation route as every puzzle."),
		PlayerController->GlobalDictationCapture.Get());
	TestFalse(
		TEXT("The legacy Classic-only voice shortcut must remain opt-in to avoid a duplicate global binding."),
		PlayerController->bBindVoiceHoldShortcut);
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeOrbitPawnDefaultsTest,
	"HyperTwist.Simulation.ClassicCube.OrbitPawnDefaults",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeOrbitPawnDefaultsTest::RunTest(const FString& Parameters)
{
	AHyperTwistClassicCubeOrbitPawn* OrbitPawn = NewObject<AHyperTwistClassicCubeOrbitPawn>();
	TestNotNull(TEXT("The classic cube orbit pawn must be constructible."), OrbitPawn);
	if (OrbitPawn == nullptr)
	{
		return false;
	}

	TestNotNull(TEXT("The orbit pawn must allocate a spring arm component."), OrbitPawn->SpringArm.Get());
	TestNotNull(TEXT("The orbit pawn must allocate a camera component."), OrbitPawn->CameraComponent.Get());
	TestTrue(
		TEXT("The orbit pawn must expose a sane zoom range."),
		OrbitPawn->MinimumArmLength < OrbitPawn->InitialArmLength
			&& OrbitPawn->InitialArmLength < OrbitPawn->MaximumArmLength
	);
	TestTrue(
		TEXT("The default orbit framing must keep the 3x3 puzzle legible at desktop resolution."),
		OrbitPawn->InitialArmLength <= 125.0f
	);
	TestTrue(
		TEXT("The orbit pawn must follow the active cube actor by default."),
		OrbitPawn->bFollowActiveCubeActor
	);
	TestTrue(
		TEXT("The orbit pawn must support at least one mouse-orbit gesture by default."),
		OrbitPawn->bUseMiddleMouseOrbit || OrbitPawn->bUseRightMouseOrbitWithShift
	);
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeFollowAlongGameModeDefaultsTest,
	"HyperTwist.Simulation.ClassicCube.FollowAlongGameModeDefaults",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeFollowAlongGameModeDefaultsTest::RunTest(const FString& Parameters)
{
	AHyperTwistClassicCubeFollowAlongGameMode* GameMode =
		NewObject<AHyperTwistClassicCubeFollowAlongGameMode>();
	TestNotNull(TEXT("The follow-along classic cube game mode must be constructible."), GameMode);
	if (GameMode == nullptr)
	{
		return false;
	}

	TestEqual(
		TEXT("The follow-along mode must default its training session into follow-along playback."),
		GameMode->DefaultSessionMode,
		EHyperTwistClassicCubeSessionMode::FollowAlong
	);
	TestFalse(
		TEXT("The follow-along mode must ship with a deterministic scripted scramble for repeatable drills."),
		GameMode->FollowAlongScriptedScrambleNotation.IsEmpty()
	);
	return true;
}

#endif
