// Copyright HyperTwist, Inc. All Rights Reserved.

#include "Misc/AutomationTest.h"

#include "HyperTwistSimulation/HyperTwistClassicCubeCommandLibrary.h"

#if WITH_AUTOMATION_TESTS

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeVoiceCommandPrimeParseTest,
	"HyperTwist.Simulation.ClassicCube.VoiceCommand.ParsePrimeMove",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeVoiceCommandPrimeParseTest::RunTest(const FString& Parameters)
{
	FHyperTwistClassicCubeVoiceCommand VoiceCommand;
	TestTrue(
		TEXT("The classic cube command parser must recognize a spoken prime move transcript."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("R prime"), VoiceCommand)
	);
	TestEqual(
		TEXT("Prime move transcripts must parse into move commands."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::Move
	);
	TestEqual(TEXT("The parsed move must target the right face."), VoiceCommand.Move.Face, EHyperTwistClassicCubeFace::Right);
	TestEqual(
		TEXT("The parsed move must rotate counter-clockwise."),
		VoiceCommand.Move.Direction,
		EHyperTwistRotationDirection::CounterClockwise
	);
	TestEqual(TEXT("The notation should normalize into R'."), VoiceCommand.Move.Notation, FString(TEXT("R'")));
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeVoiceCommandUnsupportedSliceTest,
	"HyperTwist.Simulation.ClassicCube.VoiceCommand.UnsupportedSlice",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeVoiceCommandUnsupportedSliceTest::RunTest(const FString& Parameters)
{
	FHyperTwistClassicCubeVoiceCommand VoiceCommand;
	TestTrue(
		TEXT("The classic cube command parser must surface unsupported slice requests explicitly."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("slice M"), VoiceCommand)
	);
	TestEqual(
		TEXT("Unsupported slice requests must report the unsupported command kind."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::Unsupported
	);
	TestFalse(
		TEXT("Unsupported slice feedback must not be empty."),
		VoiceCommand.FeedbackLine.IsEmpty()
	);
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeVoiceCommandDoubleTurnWordsParseTest,
	"HyperTwist.Simulation.ClassicCube.VoiceCommand.ParseDoubleTurnWords",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeVoiceCommandDoubleTurnWordsParseTest::RunTest(const FString& Parameters)
{
	FHyperTwistClassicCubeVoiceCommand VoiceCommand;
	TestTrue(
		TEXT("The classic cube command parser must recognize spoken double-turn wording."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("right double"), VoiceCommand)
	);
	TestEqual(
		TEXT("Double-turn wording must still resolve to a move command."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::Move
	);
	TestEqual(
		TEXT("The parsed move must target the right face."),
		VoiceCommand.Move.Face,
		EHyperTwistClassicCubeFace::Right
	);
	TestEqual(
		TEXT("The parsed move must record a double turn."),
		VoiceCommand.Move.QuarterTurns,
		2
	);
	TestEqual(TEXT("The normalized notation must be R2."), VoiceCommand.Move.Notation, FString(TEXT("R2")));
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeVoiceCommandControlPhraseParseTest,
	"HyperTwist.Simulation.ClassicCube.VoiceCommand.ParseControlPhrases",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeVoiceCommandControlPhraseParseTest::RunTest(const FString& Parameters)
{
	FHyperTwistClassicCubeVoiceCommand VoiceCommand;
	TestTrue(
		TEXT("The classic cube command parser must recognize the submit-solve control phrase."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("submit solve"), VoiceCommand)
	);
	TestEqual(
		TEXT("Submit-solve phrasing must map to the submit command."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::SubmitSolve
	);

	TestTrue(
		TEXT("The classic cube command parser must recognize the follow-along control phrase."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("follow along"), VoiceCommand)
	);
	TestEqual(
		TEXT("Follow-along phrasing must map to the mode-toggle command."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::ToggleFollowAlong
	);

	TestTrue(
		TEXT("The classic cube command parser must recognize the voice-cycle control phrase."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("change voice"), VoiceCommand)
	);
	TestEqual(
		TEXT("Voice-cycle phrasing must map to the cycle-voice command."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::CycleVoiceProfile
	);
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeVoiceCommandControlPhrasePrecedenceTest,
	"HyperTwist.Simulation.ClassicCube.VoiceCommand.ControlPhrasePrecedence",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeVoiceCommandControlPhrasePrecedenceTest::RunTest(const FString& Parameters)
{
	FHyperTwistClassicCubeVoiceCommand VoiceCommand;
	TestTrue(
		TEXT("Hint phrasing must win over incidental directional words in the transcript."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("help me right now"), VoiceCommand)
	);
	TestEqual(
		TEXT("Incidental use of the word right must not be misread as a right-face turn."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::RequestHint
	);

	TestTrue(
		TEXT("New-scramble phrasing must win over incidental directional words in the transcript."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("start over right now"), VoiceCommand)
	);
	TestEqual(
		TEXT("The parser must preserve the reset intent instead of inventing a right-face move."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::NewScramble
	);
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeMoveSequenceExpansionTest,
	"HyperTwist.Simulation.ClassicCube.CommandLibrary.ExpandDoubleTurns",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeMoveSequenceExpansionTest::RunTest(const FString& Parameters)
{
	const TArray<FHyperTwistClassicCubeMoveDescriptor> ExpandedMoves =
		UHyperTwistClassicCubeCommandLibrary::ExpandMoveNotationSequence(
			{ TEXT("R2"), TEXT("U'") }
		);

	TestEqual(
		TEXT("Double turns must expand into two quarter-turn entries plus the remaining moves."),
		ExpandedMoves.Num(),
		3
	);
	if (ExpandedMoves.Num() == 3)
	{
		TestEqual(TEXT("The first expanded move must remain R."), ExpandedMoves[0].Notation, FString(TEXT("R")));
		TestEqual(TEXT("The second expanded move must remain R."), ExpandedMoves[1].Notation, FString(TEXT("R")));
		TestEqual(TEXT("The trailing prime move must remain U'."), ExpandedMoves[2].Notation, FString(TEXT("U'")));
	}

	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistClassicCubeVoiceCommandExplicitMovePhraseTest,
	"HyperTwist.Simulation.ClassicCube.VoiceCommand.ExplicitMovePhrase",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistClassicCubeVoiceCommandExplicitMovePhraseTest::RunTest(const FString& Parameters)
{
	FHyperTwistClassicCubeVoiceCommand VoiceCommand;
	TestTrue(
		TEXT("The parser must still accept an explicit spoken move phrase with modifiers."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("rotate the right face twice"), VoiceCommand)
	);
	TestEqual(
		TEXT("Explicit move phrasing must resolve to a move command."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::Move
	);
	TestEqual(TEXT("Explicit move phrasing must keep the right face target."), VoiceCommand.Move.Face, EHyperTwistClassicCubeFace::Right);
	TestEqual(TEXT("Explicit move phrasing must preserve the double-turn modifier."), VoiceCommand.Move.QuarterTurns, 2);

	TestTrue(
		TEXT("The parser must accept anti-clockwise phrasing after transcript normalization."),
		UHyperTwistClassicCubeCommandLibrary::TryParseVoiceCommand(TEXT("rotate the front face anti clockwise"), VoiceCommand)
	);
	TestEqual(
		TEXT("Normalized anti-clockwise phrasing must still resolve to a move command."),
		VoiceCommand.CommandKind,
		EHyperTwistClassicCubeVoiceCommandKind::Move
	);
	TestEqual(TEXT("Anti-clockwise phrasing must target the front face."), VoiceCommand.Move.Face, EHyperTwistClassicCubeFace::Front);
	TestEqual(
		TEXT("Anti-clockwise phrasing must resolve to the counter-clockwise direction."),
		VoiceCommand.Move.Direction,
		EHyperTwistRotationDirection::CounterClockwise
	);
	return true;
}

#endif
