#include "Misc/AutomationTest.h"

#include "HyperTwistBootstrap/HyperTwistContractLibrary.h"

namespace HyperTwistSkillPhaseS1CTestInternal
{
	const FHyperTwistSkillInvocationRecord* FindInvocationRecordBySkillId(
		const FHyperTwistSkillAuditLedgerState& AuditLedgerState,
		const FString& SkillId
	)
	{
		for (const FHyperTwistSkillInvocationRecord& Record : AuditLedgerState.InvocationRecords)
		{
			if (Record.SkillId == SkillId)
			{
				return &Record;
			}
		}

		return nullptr;
	}
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistSkillPhaseS1CInvocationProvenanceTest,
	"HyperTwist.FirstParty.Skill.PhaseS1C.InvocationProvenance",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistSkillPhaseS1CInvocationProvenanceTest::RunTest(const FString& Parameters)
{
	const FHyperTwistSkillAuditLedgerState AuditLedgerState =
		UHyperTwistContractLibrary::MakeSampleSkillAuditLedgerState();

	TestTrue(
		TEXT("Sample skill audit ledger state should be structurally valid."),
		AuditLedgerState.IsStructurallyValid()
	);
	TestEqual(
		TEXT("Sample skill audit ledger should record one invocation per enabled sample skill after S7-C lands."),
		AuditLedgerState.InvocationCount,
		37
	);
	TestEqual(
		TEXT("All sample invocations should remain traceable."),
		AuditLedgerState.TraceableInvocationCount,
		AuditLedgerState.InvocationCount
	);
	TestTrue(
		TEXT("No product-truth skill output should become untraceable."),
		AuditLedgerState.bNoUntraceableProductTruth
	);
	TestTrue(
		TEXT("Command/service provenance should stay visible for every skill invocation."),
		AuditLedgerState.bCommandServiceProvenanceVisible
	);

	const FHyperTwistSkillInvocationRecord* GovernanceRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/skillization-governance")
		);
	TestNotNull(
		TEXT("The governance skill invocation should be present in the sample audit ledger."),
		GovernanceRecord
	);
	if (GovernanceRecord != nullptr)
	{
		TestEqual(
			TEXT("The governance skill should succeed in the sample audit ledger."),
			GovernanceRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestTrue(
			TEXT("Successful governance output should be marked as product-truth and traceable."),
			GovernanceRecord->bOutputBecameProductTruth && GovernanceRecord->bOutputTraceable
		);
		TestEqual(
			TEXT("The governance skill should emit the declared registry-state artifact."),
			GovernanceRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/skill-registry-state"))
		);
	}

	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistSkillPhaseS1CFailureCancelRecordingTest,
	"HyperTwist.FirstParty.Skill.PhaseS1C.FailureCancelRecording",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistSkillPhaseS1CFailureCancelRecordingTest::RunTest(const FString& Parameters)
{
	const FHyperTwistSkillAuditLedgerState AuditLedgerState =
		UHyperTwistContractLibrary::MakeSampleSkillAuditLedgerState();

	TestTrue(
		TEXT("Sample skill audit ledger state should be structurally valid."),
		AuditLedgerState.IsStructurallyValid()
	);
	TestTrue(
		TEXT("Failure recording should be supported once the audit ledger lands."),
		AuditLedgerState.bFailureRecordingSupported
	);
	TestTrue(
		TEXT("Cancel recording should be supported once the audit ledger lands."),
		AuditLedgerState.bCancelRecordingSupported
	);
	TestEqual(
		TEXT("The sample audit ledger should contain the expected successful invocation count after S7-C lands."),
		AuditLedgerState.SuccessfulInvocationCount,
		35
	);
	TestEqual(
		TEXT("The sample audit ledger should contain the expected failed invocation count."),
		AuditLedgerState.FailedInvocationCount,
		1
	);
	TestEqual(
		TEXT("The sample audit ledger should contain the expected cancelled invocation count."),
		AuditLedgerState.CancelledInvocationCount,
		1
	);

	const FHyperTwistSkillInvocationRecord* ReviewRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/review-architecture")
		);
	TestNotNull(
		TEXT("The review skill invocation should be present in the sample audit ledger."),
		ReviewRecord
	);
	if (ReviewRecord != nullptr)
	{
		TestEqual(
			TEXT("The review skill should now record a success outcome."),
			ReviewRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestTrue(
			TEXT("Successful review invocations should emit traceable product output."),
			ReviewRecord->bOutputBecameProductTruth && ReviewRecord->bOutputTraceable
		);
		TestEqual(
			TEXT("The review wrapper should emit the architecture and policy scan artifacts."),
			ReviewRecord->ProducedArtifacts.Num(),
			2
		);
	}

	const FHyperTwistSkillInvocationRecord* ProviderRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/provider-routing-inspector")
		);
	TestNotNull(
		TEXT("The provider skill invocation should be present in the sample audit ledger."),
		ProviderRecord
	);
	if (ProviderRecord != nullptr)
	{
		TestEqual(
			TEXT("The provider skill should still exercise failure recording."),
			ProviderRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Failed
		);
		TestTrue(
			TEXT("Failed provider invocations should preserve a failure reason."),
			!ProviderRecord->FailureReason.IsEmpty()
		);
	}

	const FHyperTwistSkillInvocationRecord* MemoryRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/memory-resume-briefing")
		);
	TestNotNull(
		TEXT("The memory skill invocation should be present in the sample audit ledger."),
		MemoryRecord
	);
	if (MemoryRecord != nullptr)
	{
		TestEqual(
			TEXT("The memory skill should still record a cancelled outcome."),
			MemoryRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Cancelled
		);
		TestTrue(
			TEXT("Cancelled memory invocations should preserve a cancel reason."),
			!MemoryRecord->CancelReason.IsEmpty()
		);
	}

	const FHyperTwistSkillInvocationRecord* WorkflowRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/capture-follow-up-routine")
		);
	TestNotNull(
		TEXT("The workflow follow-up skill invocation should be present in the sample audit ledger."),
		WorkflowRecord
	);
	if (WorkflowRecord != nullptr)
	{
		TestEqual(
			TEXT("The workflow follow-up skill should now record a success outcome."),
			WorkflowRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The workflow follow-up skill should emit the bounded follow-up capture artifact."),
			WorkflowRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/follow-up-routine-capture-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* DocsExtractionRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/extract-docs")
		);
	TestNotNull(
		TEXT("The docs-extraction skill invocation should be present in the sample audit ledger."),
		DocsExtractionRecord
	);
	if (DocsExtractionRecord != nullptr)
	{
		TestEqual(
			TEXT("The docs-extraction skill should record a success outcome."),
			DocsExtractionRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The docs-extraction skill should emit the bounded docs extraction artifact."),
			DocsExtractionRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/docs-extraction-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* ReplayExplainerRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/compose-replay-explainer-pack")
		);
	TestNotNull(
		TEXT("The compose-replay-explainer-pack invocation should be present in the sample audit ledger."),
		ReplayExplainerRecord
	);
	if (ReplayExplainerRecord != nullptr)
	{
		TestEqual(
			TEXT("The compose-replay-explainer-pack skill should record a success outcome."),
			ReplayExplainerRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The compose-replay-explainer-pack skill should emit the bounded replay-explainer artifact."),
			ReplayExplainerRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/replay-explainer-pack-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* BrowserTraceRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/capture-browser-trace")
		);
	TestNotNull(
		TEXT("The browser-trace skill invocation should be present in the sample audit ledger."),
		BrowserTraceRecord
	);
	if (BrowserTraceRecord != nullptr)
	{
		TestEqual(
			TEXT("The browser-trace skill should record a success outcome."),
			BrowserTraceRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The browser-trace skill should emit the bounded browser trace artifact."),
			BrowserTraceRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/browser-trace-capture-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* WorkflowWrapperRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/wrap-bounded-workflow")
		);
	TestNotNull(
		TEXT("The bounded workflow-wrapper skill invocation should be present in the sample audit ledger."),
		WorkflowWrapperRecord
	);
	if (WorkflowWrapperRecord != nullptr)
	{
		TestEqual(
			TEXT("The bounded workflow-wrapper skill should record a success outcome."),
			WorkflowWrapperRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The bounded workflow-wrapper skill should emit the bounded workflow wrapper artifact."),
			WorkflowWrapperRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/bounded-workflow-wrapper-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* DesignShellRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/translate-design-shell")
		);
	TestNotNull(
		TEXT("The design-shell translation skill invocation should be present in the sample audit ledger."),
		DesignShellRecord
	);
	if (DesignShellRecord != nullptr)
	{
		TestEqual(
			TEXT("The design-shell translation skill should record a success outcome."),
			DesignShellRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The design-shell translation skill should emit the bounded native design-shell translation artifact."),
			DesignShellRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/native-design-shell-translation-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* DelegationSpecRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/specify-bounded-delegation")
		);
	TestNotNull(
		TEXT("The bounded-delegation spec invocation should be present in the sample audit ledger."),
		DelegationSpecRecord
	);
	if (DelegationSpecRecord != nullptr)
	{
		TestEqual(
			TEXT("The bounded-delegation spec should record a success outcome."),
			DelegationSpecRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The bounded-delegation spec should emit the delegation-spec artifact."),
			DelegationSpecRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/bounded-delegation-spec-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* WorkflowChainRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/chain-bounded-workflow")
		);
	TestNotNull(
		TEXT("The bounded workflow-chain invocation should be present in the sample audit ledger."),
		WorkflowChainRecord
	);
	if (WorkflowChainRecord != nullptr)
	{
		TestEqual(
			TEXT("The bounded workflow-chain skill should record a success outcome."),
			WorkflowChainRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The bounded workflow-chain skill should emit the workflow-chain artifact."),
			WorkflowChainRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/bounded-workflow-chain-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* ProviderProfileRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/diagnose-provider-routing")
		);
	TestNotNull(
		TEXT("The diagnose-provider-routing skill invocation should be present in the sample audit ledger."),
		ProviderProfileRecord
	);
	if (ProviderProfileRecord != nullptr)
	{
		TestEqual(
			TEXT("The diagnose-provider-routing skill should record a success outcome."),
			ProviderProfileRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The diagnose-provider-routing skill should emit the bounded provider-routing diagnostic artifact."),
			ProviderProfileRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/provider-routing-diagnostic-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* UsageAuditRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/audit-provider-usage")
		);
	TestNotNull(
		TEXT("The audit-provider-usage skill invocation should be present in the sample audit ledger."),
		UsageAuditRecord
	);
	if (UsageAuditRecord != nullptr)
	{
		TestEqual(
			TEXT("The audit-provider-usage skill should record a success outcome."),
			UsageAuditRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The audit-provider-usage skill should emit the bounded provider-usage audit artifact."),
			UsageAuditRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/provider-usage-audit-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* DomainPackagingRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/specify-domain-packaging")
		);
	TestNotNull(
		TEXT("The specify-domain-packaging skill invocation should be present in the sample audit ledger."),
		DomainPackagingRecord
	);
	if (DomainPackagingRecord != nullptr)
	{
		TestEqual(
			TEXT("The specify-domain-packaging skill should record a success outcome."),
			DomainPackagingRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The specify-domain-packaging skill should emit the bounded domain-packaging artifact."),
			DomainPackagingRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/domain-packaging-rules-brief"))
		);
	}

	const FHyperTwistSkillInvocationRecord* TrainingReplayPackRecord =
		HyperTwistSkillPhaseS1CTestInternal::FindInvocationRecordBySkillId(
			AuditLedgerState,
			TEXT("skill/review-training-replay-pack")
		);
	TestNotNull(
		TEXT("The review-training-replay-pack skill invocation should be present in the sample audit ledger."),
		TrainingReplayPackRecord
	);
	if (TrainingReplayPackRecord != nullptr)
	{
		TestEqual(
			TEXT("The review-training-replay-pack skill should record a success outcome."),
			TrainingReplayPackRecord->Outcome,
			EHyperTwistSkillInvocationOutcome::Succeeded
		);
		TestEqual(
			TEXT("The review-training-replay-pack skill should emit the bounded retained training-replay artifact."),
			TrainingReplayPackRecord->ProducedArtifacts[0].ArtifactKind,
			FString(TEXT("artifact/training-replay-review-pack-brief"))
		);
	}

	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistSkillPhaseS1CSerializationRoundTripTest,
	"HyperTwist.FirstParty.Skill.PhaseS1C.SerializationRoundTrip",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistSkillPhaseS1CSerializationRoundTripTest::RunTest(const FString& Parameters)
{
	const FHyperTwistSkillAuditLedgerState AuditLedgerState =
		UHyperTwistContractLibrary::MakeSampleSkillAuditLedgerState();

	TestTrue(
		TEXT("Sample skill audit ledger state should be structurally valid before serialization."),
		AuditLedgerState.IsStructurallyValid()
	);

	const FString Json =
		UHyperTwistContractLibrary::SerializeSkillAuditLedgerStateToJson(AuditLedgerState);
	TestTrue(
		TEXT("Serialized skill audit ledger JSON should include the traceability guard field."),
		Json.Contains(TEXT("bNoUntraceableProductTruth"))
	);

	FHyperTwistSkillAuditLedgerState RoundTrippedState;
	TestTrue(
		TEXT("Deserializing the skill audit ledger JSON should succeed."),
		UHyperTwistContractLibrary::DeserializeSkillAuditLedgerStateFromJson(
			Json,
			RoundTrippedState
		)
	);
	TestTrue(
		TEXT("Round-tripped skill audit ledger state should remain structurally valid."),
		RoundTrippedState.IsStructurallyValid()
	);
	TestEqual(
		TEXT("Round-tripped invocation count should match the original sample."),
		RoundTrippedState.InvocationCount,
		AuditLedgerState.InvocationCount
	);
	TestEqual(
		TEXT("Round-tripped failed invocation count should match the original sample."),
		RoundTrippedState.FailedInvocationCount,
		AuditLedgerState.FailedInvocationCount
	);
	TestEqual(
		TEXT("Round-tripped traceable product-truth output count should match the original sample."),
		RoundTrippedState.TraceableProductTruthOutputCount,
		AuditLedgerState.TraceableProductTruthOutputCount
	);

	return true;
}
