// Copyright HyperTwist, Inc. All Rights Reserved.

#include "Misc/AutomationTest.h"

#include "HyperTwistBootstrap/HyperTwistContractLibrary.h"

#if WITH_AUTOMATION_TESTS

namespace HyperTwistSkillPhaseS1BTestInternal
{
	const FHyperTwistSkillControlStateEntry* FindSkillStateById(
		const FHyperTwistSkillControlState& ControlState,
		const FString& SkillId
	)
	{
		for (const FHyperTwistSkillControlStateEntry& SkillState : ControlState.SkillStates)
		{
			if (SkillState.SkillId == SkillId)
			{
				return &SkillState;
			}
		}

		return nullptr;
	}

	const FHyperTwistSkillVisibilityGroupState* FindVisibilityGroupById(
		const FHyperTwistSkillControlState& ControlState,
		const FString& GroupId
	)
	{
		for (const FHyperTwistSkillVisibilityGroupState& Group : ControlState.VisibilityGroups)
		{
			if (Group.GroupId == GroupId)
			{
				return &Group;
			}
		}

		return nullptr;
	}
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistSkillPhaseS1BSettingsVisibilityTest,
	"HyperTwist.FirstParty.Skill.PhaseS1B.SettingsVisibility",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistSkillPhaseS1BSettingsVisibilityTest::RunTest(
	const FString& Parameters
)
{
	const FHyperTwistSkillControlState ControlState =
		UHyperTwistContractLibrary::MakeSampleSkillControlState();

	TestTrue(
		TEXT("The Phase S1-B skill-control state must be structurally valid."),
		ControlState.IsStructurallyValid()
	);
	TestTrue(
		TEXT("The master switch must be enabled in the default control profile."),
		ControlState.MasterSwitch.bEnabled
	);
	TestTrue(
		TEXT("The S1-B control state must expose durable settings."),
		ControlState.MasterSwitch.bDurableSettingExposed
	);
	TestTrue(
		TEXT("The S1-B control state must expose immediate menu control."),
		ControlState.MasterSwitch.bImmediateMenuControlExposed
	);
	TestEqual(
		TEXT("The sample S1-B control state must preserve all forty installed skills after S7-C lands."),
		ControlState.SkillCount,
		40
	);
	TestEqual(
		TEXT("The default S1-B control state must keep one effective enabled skill."),
		ControlState.EffectiveEnabledSkillCount,
		1
	);
	TestTrue(
		TEXT("The S1-B control state must keep visible family groupings."),
		ControlState.VisibilityGroups.Num() > 0
	);

	const FHyperTwistSkillControlStateEntry* GovernanceState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/skillization-governance")
		);
	TestNotNull(
		TEXT("The governance skill state must exist."),
		GovernanceState
	);
	if (GovernanceState != nullptr)
	{
		TestTrue(
			TEXT("The governance skill must remain effectively enabled by default."),
			GovernanceState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The governance skill must remain visible by default."),
			GovernanceState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The governance skill must use the substrate visibility group."),
			GovernanceState->VisibilityGroupId,
			TEXT("skill-group/substrate-governance")
		);
	}

	const FHyperTwistSkillVisibilityGroupState* GovernanceGroup =
		HyperTwistSkillPhaseS1BTestInternal::FindVisibilityGroupById(
			ControlState,
			TEXT("skill-group/substrate-governance")
		);
	TestNotNull(
		TEXT("The substrate-governance visibility group must exist."),
		GovernanceGroup
	);
	if (GovernanceGroup != nullptr)
	{
		TestEqual(
			TEXT("The governance visibility group must contain one skill."),
			GovernanceGroup->SkillIds.Num(),
			1
		);
		TestEqual(
			TEXT("The governance visibility group must expose one visible skill."),
			GovernanceGroup->VisibleSkillCount,
			1
		);
	}

	const FHyperTwistSkillControlStateEntry* DocsExtractionState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/extract-docs")
		);
	TestNotNull(
		TEXT("The extract-docs skill state must exist."),
		DocsExtractionState
	);
	if (DocsExtractionState != nullptr)
	{
		TestFalse(
			TEXT("The extract-docs skill must remain opt-in by default."),
			DocsExtractionState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The extract-docs skill must remain visible by default."),
			DocsExtractionState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The extract-docs skill must use the browser/docs/design visibility group."),
			DocsExtractionState->VisibilityGroupId,
			TEXT("skill-group/browser-docs-design")
		);
	}

	const FHyperTwistSkillControlStateEntry* BrowserTraceState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/capture-browser-trace")
		);
	TestNotNull(
		TEXT("The capture-browser-trace skill state must exist."),
		BrowserTraceState
	);
	if (BrowserTraceState != nullptr)
	{
		TestFalse(
			TEXT("The capture-browser-trace skill must remain opt-in by default."),
			BrowserTraceState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The capture-browser-trace skill must remain visible by default."),
			BrowserTraceState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The capture-browser-trace skill must use the browser/docs/design visibility group."),
			BrowserTraceState->VisibilityGroupId,
			TEXT("skill-group/browser-docs-design")
		);
	}

	const FHyperTwistSkillControlStateEntry* DesignShellState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/translate-design-shell")
		);
	TestNotNull(
		TEXT("The translate-design-shell skill state must exist."),
		DesignShellState
	);
	if (DesignShellState != nullptr)
	{
		TestFalse(
			TEXT("The translate-design-shell skill must remain opt-in by default."),
			DesignShellState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The translate-design-shell skill must remain visible by default."),
			DesignShellState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The translate-design-shell skill must use the browser/docs/design visibility group."),
			DesignShellState->VisibilityGroupId,
			TEXT("skill-group/browser-docs-design")
		);
	}

	const FHyperTwistSkillControlStateEntry* WorkflowReviewState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/review-proposal")
		);
	TestNotNull(
		TEXT("The review-proposal skill state must exist."),
		WorkflowReviewState
	);
	if (WorkflowReviewState != nullptr)
	{
		TestFalse(
			TEXT("The review-proposal skill must remain opt-in by default."),
			WorkflowReviewState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The review-proposal skill must remain visible by default."),
			WorkflowReviewState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The review-proposal skill must use the analysis/review visibility group."),
			WorkflowReviewState->VisibilityGroupId,
			TEXT("skill-group/analysis-review")
		);
	}

	const FHyperTwistSkillControlStateEntry* ReplayExplainerState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/compose-replay-explainer-pack")
		);
	TestNotNull(
		TEXT("The compose-replay-explainer-pack skill state must exist."),
		ReplayExplainerState
	);
	if (ReplayExplainerState != nullptr)
	{
		TestFalse(
			TEXT("The compose-replay-explainer-pack skill must remain opt-in by default."),
			ReplayExplainerState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The compose-replay-explainer-pack skill must remain visible by default."),
			ReplayExplainerState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The compose-replay-explainer-pack skill must use the domain/creative visibility group."),
			ReplayExplainerState->VisibilityGroupId,
			TEXT("skill-group/domain-creative")
		);
	}

	const FHyperTwistSkillControlStateEntry* ImplementationReviewState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/review-implementation")
		);
	TestNotNull(
		TEXT("The review-implementation skill state must exist."),
		ImplementationReviewState
	);
	if (ImplementationReviewState != nullptr)
	{
		TestFalse(
			TEXT("The review-implementation skill must remain opt-in by default."),
			ImplementationReviewState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The review-implementation skill must remain visible by default."),
			ImplementationReviewState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The review-implementation skill must use the analysis/review visibility group."),
			ImplementationReviewState->VisibilityGroupId,
			TEXT("skill-group/analysis-review")
		);
	}

	const FHyperTwistSkillControlStateEntry* PlanSynthesisState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/synthesize-plan")
		);
	TestNotNull(
		TEXT("The synthesize-plan skill state must exist."),
		PlanSynthesisState
	);
	if (PlanSynthesisState != nullptr)
	{
		TestFalse(
			TEXT("The synthesize-plan skill must remain opt-in by default."),
			PlanSynthesisState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The synthesize-plan skill must remain visible by default."),
			PlanSynthesisState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The synthesize-plan skill must use the analysis/review visibility group."),
			PlanSynthesisState->VisibilityGroupId,
			TEXT("skill-group/analysis-review")
		);
	}

	const FHyperTwistSkillControlStateEntry* ProviderProfileState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/inspect-provider-profile")
		);
	TestNotNull(
		TEXT("The inspect-provider-profile skill state must exist."),
		ProviderProfileState
	);
	if (ProviderProfileState != nullptr)
	{
		TestFalse(
			TEXT("The inspect-provider-profile skill must remain opt-in by default."),
			ProviderProfileState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The inspect-provider-profile skill must remain visible by default."),
			ProviderProfileState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The inspect-provider-profile skill must use the provider-operations visibility group."),
			ProviderProfileState->VisibilityGroupId,
			TEXT("skill-group/provider-operations")
		);
	}

	const FHyperTwistSkillControlStateEntry* UsageAuditState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/audit-provider-usage")
		);
	TestNotNull(
		TEXT("The audit-provider-usage skill state must exist."),
		UsageAuditState
	);
	if (UsageAuditState != nullptr)
	{
		TestFalse(
			TEXT("The audit-provider-usage skill must remain opt-in by default."),
			UsageAuditState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The audit-provider-usage skill must remain visible by default."),
			UsageAuditState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The audit-provider-usage skill must use the provider-operations visibility group."),
			UsageAuditState->VisibilityGroupId,
			TEXT("skill-group/provider-operations")
		);
	}

	const FHyperTwistSkillControlStateEntry* DomainPackagingState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/specify-domain-packaging")
		);
	TestNotNull(
		TEXT("The specify-domain-packaging skill state must exist."),
		DomainPackagingState
	);
	if (DomainPackagingState != nullptr)
	{
		TestFalse(
			TEXT("The specify-domain-packaging skill must remain opt-in by default."),
			DomainPackagingState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The specify-domain-packaging skill must remain visible by default."),
			DomainPackagingState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The specify-domain-packaging skill must use the domain-creative visibility group."),
			DomainPackagingState->VisibilityGroupId,
			TEXT("skill-group/domain-creative")
		);
	}

	const FHyperTwistSkillControlStateEntry* TrainingReplayPackState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/review-training-replay-pack")
		);
	TestNotNull(
		TEXT("The review-training-replay-pack skill state must exist."),
		TrainingReplayPackState
	);
	if (TrainingReplayPackState != nullptr)
	{
		TestFalse(
			TEXT("The review-training-replay-pack skill must remain opt-in by default."),
			TrainingReplayPackState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The review-training-replay-pack skill must remain visible by default."),
			TrainingReplayPackState->bEffectiveVisible
		);
		TestEqual(
			TEXT("The review-training-replay-pack skill must use the domain-creative visibility group."),
			TrainingReplayPackState->VisibilityGroupId,
			TEXT("skill-group/domain-creative")
		);
	}

	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistSkillPhaseS1BAllSkillsOffCorrectnessTest,
	"HyperTwist.FirstParty.Skill.PhaseS1B.AllSkillsOffCorrectness",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistSkillPhaseS1BAllSkillsOffCorrectnessTest::RunTest(
	const FString& Parameters
)
{
	const FHyperTwistSkillControlState ControlState =
		UHyperTwistContractLibrary::MakeAllSkillsOffSkillControlState();

	TestTrue(
		TEXT("The all-skills-off S1-B control state must remain structurally valid."),
		ControlState.IsStructurallyValid()
	);
	TestFalse(
		TEXT("The master switch must be disabled in the all-skills-off profile."),
		ControlState.MasterSwitch.bEnabled
	);
	TestTrue(
		TEXT("The all-skills-off control state must confirm off-state safety."),
		ControlState.MasterSwitch.bAllSkillsOffSafe
	);
	TestEqual(
		TEXT("The all-skills-off control state must expose zero effective enabled skills."),
		ControlState.EffectiveEnabledSkillCount,
		0
	);
	TestEqual(
		TEXT("The all-skills-off control state must preserve all installed skills as disabled."),
		ControlState.EffectiveDisabledSkillCount,
		ControlState.SkillCount
	);
	TestTrue(
		TEXT("The core product must still work with all skills off."),
		ControlState.bCoreProductWorksWithAllSkillsOff
	);
	TestTrue(
		TEXT("Disabled skills must remain reenableable."),
		ControlState.bAllInstalledSkillsRemainReenableable
	);

	const FHyperTwistSkillControlStateEntry* GovernanceState =
		HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById(
			ControlState,
			TEXT("skill/skillization-governance")
		);
	TestNotNull(
		TEXT("The governance skill state must still exist with all skills off."),
		GovernanceState
	);
	if (GovernanceState != nullptr)
	{
		TestTrue(
			TEXT("The governance skill must stay requested-enabled by default."),
			GovernanceState->bRequestedEnabled
		);
		TestFalse(
			TEXT("The governance skill must become effectively disabled when the master switch is off."),
			GovernanceState->bEffectiveEnabled
		);
		TestTrue(
			TEXT("The governance skill must remain installed when disabled."),
			GovernanceState->bInstalled
		);
		TestTrue(
			TEXT("The governance skill must remain inert when disabled."),
			GovernanceState->bInertWhenDisabled
		);
	}

	return true;
}

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
	FHyperTwistSkillPhaseS1BSerializationRoundTripTest,
	"HyperTwist.FirstParty.Skill.PhaseS1B.SerializationRoundTrip",
	EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)

bool FHyperTwistSkillPhaseS1BSerializationRoundTripTest::RunTest(
	const FString& Parameters
)
{
	const FHyperTwistSkillControlState ControlState =
		UHyperTwistContractLibrary::MakeSampleSkillControlState();
	TestTrue(
		TEXT("The Phase S1-B skill-control state must be structurally valid before serialization."),
		ControlState.IsStructurallyValid()
	);

	const FString Json =
		UHyperTwistContractLibrary::SerializeSkillControlStateToJson(ControlState);
	TestFalse(TEXT("The serialized S1-B JSON must not be empty."), Json.IsEmpty());
	TestTrue(
		TEXT("The serialized S1-B JSON must expose the master-switch contract."),
		Json.Contains(TEXT("MasterSwitch"))
	);
	TestTrue(
		TEXT("The serialized S1-B JSON must expose visibility groups."),
		Json.Contains(TEXT("VisibilityGroups"))
	);

	FHyperTwistSkillControlState RoundTrippedState;
	TestTrue(
		TEXT("The S1-B JSON must deserialize cleanly."),
		UHyperTwistContractLibrary::DeserializeSkillControlStateFromJson(
			Json,
			RoundTrippedState
		)
	);
	TestTrue(
		TEXT("The round-tripped S1-B control state must remain structurally valid."),
		RoundTrippedState.IsStructurallyValid()
	);
	TestEqual(
		TEXT("The round-tripped S1-B control state must preserve skill counts."),
		RoundTrippedState.SkillCount,
		ControlState.SkillCount
	);
	TestEqual(
		TEXT("The round-tripped S1-B control state must preserve effective enabled counts."),
		RoundTrippedState.EffectiveEnabledSkillCount,
		ControlState.EffectiveEnabledSkillCount
	);
	TestEqual(
		TEXT("The round-tripped S1-B control state must preserve visibility-group counts."),
		RoundTrippedState.VisibilityGroups.Num(),
		ControlState.VisibilityGroups.Num()
	);

	return true;
}

#endif
