// Copyright HyperTwist, Inc. All Rights Reserved.

#include "Misc/AutomationTest.h"

#include "HyperTwistBootstrap/HyperTwistContractLibrary.h"
#include "HyperTwistRecognition/HyperTwistVoiceClient.h"
#include "HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.h"

#if WITH_AUTOMATION_TESTS

namespace HyperTwistPiperPhase6RGTestInternal
{
	UHyperTwistMockVoiceClient* MakeMockVoiceClient()
	{
		return NewObject<UHyperTwistMockVoiceClient>();
	}
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistPiperPhase6RGNarrationRequestTest,
	"HyperTwist.Permissive.Piper.Phase6R.G.NarrationRequest",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistPiperPhase6RGNarrationRequestTest::RunTest(const FString& Parameters)
{
	FHyperTwistTrainingCompanionNarrationContract NarrationContract;
	TestTrue(
		TEXT("The bundled embodied companion narration contract must be available."),
		UHyperTwistTrainingRuntimeLibrary::TryGetBundledEmbodiedCompanionNarrationContract(
			TEXT("embodied-companion-narration"),
			NarrationContract
		)
	);
	TestTrue(TEXT("The bundled narration contract must be structurally valid."), NarrationContract.IsStructurallyValid());
	TestTrue(
		TEXT("The narration contract must preserve subtitle synchronization in the output surface tags."),
		NarrationContract.OutputSurfaceTags.Contains(TEXT("subtitle-sync"))
	);

	UHyperTwistMockVoiceClient* VoiceClient = HyperTwistPiperPhase6RGTestInternal::MakeMockVoiceClient();
	TestNotNull(TEXT("The mock voice client must be constructed for Phase 6R-G."), VoiceClient);
	if (VoiceClient == nullptr)
	{
		return false;
	}

	const TArray<FHyperTwistVoiceProfileSummary> Profiles = VoiceClient->ListVoiceProfiles();
	TestTrue(TEXT("The bounded piper route must expose a non-empty local voice catalog."), Profiles.Num() >= 3);
	TestTrue(
		TEXT("The local voice catalog must contain the bounded Lessac profile."),
		Profiles.ContainsByPredicate([](const FHyperTwistVoiceProfileSummary& Profile)
		{
			return Profile.VoiceProfileId == TEXT("en_US-lessac-medium");
		})
	);

	const FHyperTwistNarrationSynthesisRequest Request = UHyperTwistContractLibrary::MakeSampleNarrationSynthesisRequest();
	TestTrue(TEXT("The sample narration request must be structurally valid."), Request.IsStructurallyValid());
	TestEqual(
		TEXT("The request must anchor on the bundled embodied companion narration contract."),
		Request.NarrationContractId,
		TEXT("embodied-companion-narration")
	);
	TestEqual(TEXT("The bounded first slice must stay on the local voice sidecar lane."), Request.ServiceLaneId, TEXT("voice/local-sidecar"));
	TestEqual(TEXT("The bounded first slice must keep the local companion narration route."), Request.OutputRouteId, TEXT("companion/narration/local"));
	TestEqual(TEXT("The bounded first slice must use WAV mono output."), Request.AudioEncodingHint, TEXT("wav-pcm16-mono"));
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistPiperPhase6RGSynthesisResultTest,
	"HyperTwist.Permissive.Piper.Phase6R.G.SynthesisResult",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistPiperPhase6RGSynthesisResultTest::RunTest(const FString& Parameters)
{
	UHyperTwistMockVoiceClient* VoiceClient = HyperTwistPiperPhase6RGTestInternal::MakeMockVoiceClient();
	TestNotNull(TEXT("The mock voice client must be constructed for Phase 6R-G."), VoiceClient);
	if (VoiceClient == nullptr)
	{
		return false;
	}

	const FHyperTwistNarrationSynthesisRequest Request = UHyperTwistContractLibrary::MakeSampleNarrationSynthesisRequest();
	const FHyperTwistNarrationSynthesisResult Result = VoiceClient->SynthesizeNarration(Request);

	TestTrue(TEXT("The bounded narration synthesis result must be structurally valid."), Result.IsStructurallyValid());
	TestEqual(TEXT("The result must preserve the request id."), Result.RequestId, Request.RequestId);
	TestEqual(TEXT("The result must preserve the voice profile id."), Result.VoiceProfileId, Request.VoiceProfileId);
	TestEqual(
		TEXT("The result must preserve the subtitle seed text for the local narration sidecar."),
		Result.SubtitleText,
		Request.SubtitleSeedText
	);
	TestEqual(TEXT("The result must stay WAV mono."), Result.AudioEncoding, TEXT("wav-pcm16-mono"));
	TestEqual(TEXT("The bounded local sidecar must keep the donor-grounded sample rate."), Result.SampleRateHz, 16000);
	TestEqual(TEXT("The bounded local sidecar must keep mono output."), Result.ChannelCount, 1);
	TestTrue(TEXT("The bounded local sidecar must return synthesized audio bytes."), Result.AudioBytes.Num() > 44);
	TestTrue(TEXT("The bounded local sidecar must report positive duration."), Result.DurationMs > 0);
	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistPiperPhase6RGServiceHealthTest,
	"HyperTwist.Permissive.Piper.Phase6R.G.ServiceHealth",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistPiperPhase6RGServiceHealthTest::RunTest(const FString& Parameters)
{
	UHyperTwistMockVoiceClient* VoiceClient = HyperTwistPiperPhase6RGTestInternal::MakeMockVoiceClient();
	TestNotNull(TEXT("The mock voice client must be constructed for Phase 6R-G."), VoiceClient);
	if (VoiceClient == nullptr)
	{
		return false;
	}

	const FHyperTwistVoiceServiceHealth Health = VoiceClient->GetVoiceServiceHealth();
	TestTrue(TEXT("The bounded voice service health must be structurally valid."), Health.IsStructurallyValid());
	TestTrue(TEXT("The bounded voice service health must report ready."), Health.bReady);
	TestTrue(TEXT("The bounded voice service must expose voice catalog capability."), Health.Capabilities.Contains(TEXT("voiceCatalog")));
	TestTrue(TEXT("The bounded voice service must expose offline narration capability."), Health.Capabilities.Contains(TEXT("offlineNarration")));
	TestTrue(TEXT("The bounded voice service must expose WAV output capability."), Health.Capabilities.Contains(TEXT("wavOutput")));
	TestTrue(TEXT("The bounded voice service must expose subtitle-seed capability."), Health.Capabilities.Contains(TEXT("subtitleSeed")));
	TestTrue(
		TEXT("The bounded voice service must advertise the retained Lessac voice profile."),
		Health.SupportedVoiceProfileIds.Contains(TEXT("en_US-lessac-medium"))
	);
	return true;
}

#endif
