#include "HyperTwistTraining/HyperTwistFirstRunLaunchLibrary.h"

#include "Misc/CommandLine.h"

namespace HyperTwistFirstRunLaunchLibraryInternal
{
	const TCHAR* SurfaceId = TEXT("first-run/native-launch-and-settings-surface");
	const TCHAR* DefaultRouteId = TEXT("classic-cube-training");
	const TCHAR* CoachDashboardRouteId = TEXT("coach-dashboard");
	const TCHAR* StartupFallbackRouteId = TEXT("classic-cube-training");
	const TCHAR* PackagedStartupRouteArgumentName = TEXT("HyperTwistStartupRoute");
	const TCHAR* FirstRunGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistFirstRunLaunchGameMode");
	const TCHAR* CoachDashboardGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistCoachDashboardGameMode");
	const TCHAR* ClassicCubeGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistClassicCubeGameMode");
	const TCHAR* ClassicCubeFollowAlongGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistClassicCubeFollowAlongGameMode");
	const TCHAR* HigherDimensionalTrainingGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistHigherDimensionalTrainingGameMode");
	const TCHAR* MelindaProjectionGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistMelindaProjectionGameMode");
	const TCHAR* Virtual3333ProjectionGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistVirtual3333ProjectionGameMode");
	const TCHAR* Virtual4444ProjectionGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistVirtual4444ProjectionGameMode");
	const TCHAR* Virtual5555ProjectionGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistVirtual5555ProjectionGameMode");
	const TCHAR* Virtual6666ProjectionGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistVirtual6666ProjectionGameMode");
	const TCHAR* XrTrainingGameModeClassPath =
		TEXT("/Script/UnrealHyperTwist.HyperTwistXrTrainingGameMode");
	const TCHAR* ClassicCubeMapPath =
		TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_ClassicTraining");
	const TCHAR* FollowAlongMapPath =
		TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_FollowAlongTraining");
	const TCHAR* MelindaProjectionMapPath =
		TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube4D_2x2x2x2Training");
	const TCHAR* Virtual3333ProjectionMapPath =
		TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube4D_3x3x3x3Training");
	const TCHAR* Virtual4444ProjectionMapPath =
		TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube4D_4x4x4x4Training");
	const TCHAR* Virtual5555ProjectionMapPath =
		TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube4D_5x5x5x5Training");
	const TCHAR* Virtual6666ProjectionMapPath =
		TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube4D_6x6x6x6Training");
	const TCHAR* Magic120CellMapPath =
		TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining");
	const TCHAR* MagicCube5DMapPath =
		TEXT("/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining");
	const TCHAR* RuntimeLogFileName = TEXT("HyperTwistRuntime-latest.log");
	const TCHAR* StartupDiagnosticsLogFileName = TEXT("HyperTwistFirstRunLaunch-latest.log");

	FString BuildLaunchUrl(const FString& MapAssetPath, const FString& GameModeClassPath)
	{
		if (MapAssetPath.IsEmpty())
		{
			return FString();
		}

		if (GameModeClassPath.IsEmpty())
		{
			return MapAssetPath;
		}

		return FString::Printf(TEXT("%s?game=%s"), *MapAssetPath, *GameModeClassPath);
	}

	FHyperTwistFirstRunLaunchRoute MakeRoute(
		const FString& RouteId,
		const FString& Label,
		const FString& Description,
		const FString& MapAssetPath,
		const FString& GameModeClassPath,
		const FString& PrimaryInputMode,
		const FString& RuntimeProofStatus,
		const FString& PlayerSection,
		const FString& AvailabilityLabel,
		const bool bDefaultSafeChoice,
		const bool bOpensDashboard,
		const bool bLaunchesDedicatedMap,
		const bool bRequiresEntitlement,
		const bool bRequiresLiveHeadset,
		const bool bRequiresLiveControllerObservation,
		const bool bHasWebSimulatorEquivalent,
		const bool bPlayerFacing = true
	)
	{
		FHyperTwistFirstRunLaunchRoute Route;
		Route.RouteId = RouteId;
		Route.Label = Label;
		Route.Description = Description;
		Route.MapAssetPath = MapAssetPath;
		Route.GameModeClassPath = GameModeClassPath;
		Route.LaunchUrl = BuildLaunchUrl(MapAssetPath, GameModeClassPath);
		Route.PrimaryInputMode = PrimaryInputMode;
		Route.RuntimeProofStatus = RuntimeProofStatus;
		Route.PlayerSection = PlayerSection;
		Route.AvailabilityLabel = AvailabilityLabel;
		Route.bDefaultSafeChoice = bDefaultSafeChoice;
		Route.bOpensDashboard = bOpensDashboard;
		Route.bLaunchesDedicatedMap = bLaunchesDedicatedMap;
		Route.bRequiresEntitlement = bRequiresEntitlement;
		Route.bRequiresLiveHeadset = bRequiresLiveHeadset;
		Route.bRequiresLiveControllerObservation = bRequiresLiveControllerObservation;
		Route.bHasWebSimulatorEquivalent = bHasWebSimulatorEquivalent;
		Route.bPlayerFacing = bPlayerFacing;
		return Route;
	}

	FHyperTwistPuzzleCatalogEntry MakeCatalogEntry(
		const FString& PuzzleId,
		const FString& Title,
		const FString& Dimensionality,
		const FString& Description,
		const EHyperTwistPuzzleAvailability Availability,
		const FString& AvailabilityLabel,
		const FString& LaunchRouteId,
		const TArray<FString>& ExperienceTags
	)
	{
		FHyperTwistPuzzleCatalogEntry Entry;
		Entry.PuzzleId = PuzzleId;
		Entry.Title = Title;
		Entry.Dimensionality = Dimensionality;
		Entry.Description = Description;
		Entry.Availability = Availability;
		Entry.AvailabilityLabel = AvailabilityLabel;
		Entry.LaunchRouteId = LaunchRouteId;
		Entry.ExperienceTags = ExperienceTags;
		return Entry;
	}

	FHyperTwistIntegratedCapability MakeIntegratedCapability(
		const FString& CapabilityId,
		const FString& Title,
		const FString& Summary,
		const FString& CanonicalRepository,
		const FString& LicenseId,
		const EHyperTwistIntegrationLicenseLane LicenseLane,
		const EHyperTwistIntegrationSurface Surface,
		const FString& PrimaryExperienceRoute,
		const FString& RuntimeOwnerId,
		const FString& ImplementationPosture
	)
	{
		FHyperTwistIntegratedCapability Capability;
		Capability.CapabilityId = CapabilityId;
		Capability.Title = Title;
		Capability.Summary = Summary;
		Capability.CanonicalRepository = CanonicalRepository;
		Capability.LicenseId = LicenseId;
		Capability.LicenseLane = LicenseLane;
		Capability.Surface = Surface;
		Capability.PrimaryExperienceRoute = PrimaryExperienceRoute;
		Capability.RuntimeOwnerId = RuntimeOwnerId;
		Capability.ImplementationPosture = ImplementationPosture;
		return Capability;
	}
}

bool FHyperTwistFirstRunLaunchRoute::IsStructurallyValid() const
{
	return !RouteId.IsEmpty()
		&& !Label.IsEmpty()
		&& !Description.IsEmpty()
		&& !PrimaryInputMode.IsEmpty()
		&& !RuntimeProofStatus.IsEmpty()
		&& !PlayerSection.IsEmpty()
		&& !AvailabilityLabel.IsEmpty()
		&& (!bOpensDashboard || !GameModeClassPath.IsEmpty())
		&& (!bLaunchesDedicatedMap || (!MapAssetPath.IsEmpty() && !LaunchUrl.IsEmpty()))
		&& (!bRequiresLiveControllerObservation || bRequiresLiveHeadset);
}

FString UHyperTwistFirstRunLaunchLibrary::GetFirstRunLaunchSurfaceId()
{
	return HyperTwistFirstRunLaunchLibraryInternal::SurfaceId;
}

FString UHyperTwistFirstRunLaunchLibrary::GetFirstRunGameModeClassPath()
{
	return HyperTwistFirstRunLaunchLibraryInternal::FirstRunGameModeClassPath;
}

FString UHyperTwistFirstRunLaunchLibrary::GetDefaultRouteId()
{
	return HyperTwistFirstRunLaunchLibraryInternal::DefaultRouteId;
}

FString UHyperTwistFirstRunLaunchLibrary::GetStartupFallbackRouteId()
{
	return HyperTwistFirstRunLaunchLibraryInternal::StartupFallbackRouteId;
}

FString UHyperTwistFirstRunLaunchLibrary::GetPackagedStartupMapAssetPath()
{
	return HyperTwistFirstRunLaunchLibraryInternal::ClassicCubeMapPath;
}

FString UHyperTwistFirstRunLaunchLibrary::GetPackagedStartupRouteArgumentName()
{
	return HyperTwistFirstRunLaunchLibraryInternal::PackagedStartupRouteArgumentName;
}

FString UHyperTwistFirstRunLaunchLibrary::GetRuntimeLogFileName()
{
	return HyperTwistFirstRunLaunchLibraryInternal::RuntimeLogFileName;
}

FString UHyperTwistFirstRunLaunchLibrary::GetStartupDiagnosticsLogFileName()
{
	return HyperTwistFirstRunLaunchLibraryInternal::StartupDiagnosticsLogFileName;
}

TArray<FString> UHyperTwistFirstRunLaunchLibrary::BuildFirstRunGuidanceLines()
{
	return {
		TEXT("Start with Classic Cube, learn through Follow-Along, or move into 4D, the 120-cell, and 5D at your own pace."),
		TEXT("Keyboard and mouse is the complete primary desktop path; a headset is never required for the puzzle library."),
		TEXT("Open Settings at any time to choose controls, audio, graphics, accessibility, speech, AI providers, and account options."),
		TEXT("Press Esc inside a puzzle to pause, review controls, change settings, or return safely to this menu."),
		TEXT("XR is an optional validation route; full readiness requires a live headset session with observed OpenXR controller input."),
		TEXT("The browser experience is a lightweight preview and account companion; the downloadable Unreal build is the authoritative full simulator."),
		TEXT("Runtime diagnostics are written to Saved/Logs/HyperTwistRuntime-latest.log and startup recovery details to Saved/Logs/HyperTwistFirstRunLaunch-latest.log."),
		TEXT("If the launch menu cannot render safely, HyperTwist automatically falls back into Classic Cube Free Play instead of leaving a blank scene.")
	};
}

TArray<FHyperTwistFirstRunLaunchRoute>
UHyperTwistFirstRunLaunchLibrary::BuildFirstRunLaunchRoutes()
{
	using namespace HyperTwistFirstRunLaunchLibraryInternal;

	return {
		MakeRoute(
			CoachDashboardRouteId,
			TEXT("Open Coach Dashboard and Settings"),
			TEXT("Start with the operator dashboard, control/status surfaces, browser shell bridge, and local training settings."),
			FString(),
			CoachDashboardGameModeClassPath,
			TEXT("keyboard-mouse-ui"),
			TEXT("ready-local-dashboard"),
			TEXT("advanced"),
			TEXT("Advanced"),
			false,
			true,
			false,
			false,
			false,
			false,
			true,
			false
		),
		MakeRoute(
			TEXT("classic-cube-training"),
			TEXT("Classic Cube Free Play"),
			TEXT("Launch the first-party classic-cube runtime with scramble, timer, orbit camera, hint, replay, leaderboard, and voice-command surfaces."),
			ClassicCubeMapPath,
			ClassicCubeGameModeClassPath,
			TEXT("keyboard-mouse-gameplay"),
			TEXT("ready-dedicated-map"),
			TEXT("play"),
			TEXT("Playable"),
			true,
			false,
			true,
			false,
			false,
			false,
			false
		),
		MakeRoute(
			TEXT("follow-along-training"),
			TEXT("Classic Cube Follow-Along"),
			TEXT("Launch guided classic-cube practice with scripted scramble playback and coach-facing training continuity."),
			FollowAlongMapPath,
			ClassicCubeFollowAlongGameModeClassPath,
			TEXT("keyboard-mouse-guided-gameplay"),
			TEXT("ready-dedicated-map"),
			TEXT("learn"),
			TEXT("Guided"),
			false,
			false,
			true,
			false,
			false,
			false,
			false
		),
		MakeRoute(
			TEXT("magic-cube-4d-2x2x2x2"),
			TEXT("4D Cube 2x2x2x2"),
			TEXT("Enter a compact four-dimensional cube through a cell-first projection built for learning, inspection, and exact turns."),
			MelindaProjectionMapPath,
			MelindaProjectionGameModeClassPath,
			TEXT("keyboard-mouse-4d-cell-projection"),
			TEXT("ready-first-party-runtime"),
			TEXT("play"),
			TEXT("Playable"),
			false,
			false,
			true,
			false,
			false,
			false,
			false
		),
		MakeRoute(
			TEXT("magic-cube-4d-3x3x3x3"),
			TEXT("4D Cube 3x3x3x3"),
			TEXT("Explore a full 3x3x3x3 visible-slice runtime with selectable axes, layers, projection shells, and exact reversible turns."),
			Virtual3333ProjectionMapPath,
			Virtual3333ProjectionGameModeClassPath,
			TEXT("keyboard-mouse-4d-visible-slice"),
			TEXT("ready-first-party-runtime"),
			TEXT("play"),
			TEXT("Playable"),
			false,
			false,
			true,
			false,
			false,
			false,
			false
		),
		MakeRoute(
			TEXT("magic-cube-4d-4x4x4x4"),
			TEXT("4D Cube 4x4x4x4"),
			TEXT("Take the generalized exact-state 4D runtime into 256-piece territory with four selectable layers on every slice axis."),
			Virtual4444ProjectionMapPath,
			Virtual4444ProjectionGameModeClassPath,
			TEXT("keyboard-mouse-4d-visible-slice"),
			TEXT("ready-first-party-runtime"),
			TEXT("play"),
			TEXT("Playable"),
			false,
			false,
			true,
			false,
			false,
			false,
			false
		),
		MakeRoute(
			TEXT("magic-cube-4d-5x5x5x5"),
			TEXT("4D Cube 5x5x5x5"),
			TEXT("Explore a 625-piece four-dimensional cube with five exact layers per axis and a focused 125-piece visible slice."),
			Virtual5555ProjectionMapPath,
			Virtual5555ProjectionGameModeClassPath,
			TEXT("keyboard-mouse-4d-visible-slice"),
			TEXT("ready-first-party-runtime"),
			TEXT("play"),
			TEXT("Playable"),
			false,
			false,
			true,
			false,
			false,
			false,
			false
		),
		MakeRoute(
			TEXT("magic-cube-4d-6x6x6x6"),
			TEXT("4D Cube 6x6x6x6"),
			TEXT("Work at the largest retained Hyperspeedcube order in this launch set: 1,296 exact pieces and six selectable layers per axis."),
			Virtual6666ProjectionMapPath,
			Virtual6666ProjectionGameModeClassPath,
			TEXT("keyboard-mouse-4d-visible-slice"),
			TEXT("ready-first-party-runtime"),
			TEXT("play"),
			TEXT("Playable"),
			false,
			false,
			true,
			false,
			false,
			false,
			false
		),
		MakeRoute(
			TEXT("magic-120-cell-training"),
			TEXT("Magic120Cell Training"),
			TEXT("Launch the family-owned 120-cell runtime-state, projection, persistence, and dedicated-map training surface."),
			Magic120CellMapPath,
			HigherDimensionalTrainingGameModeClassPath,
			TEXT("keyboard-mouse-higher-dimensional-training"),
			TEXT("ready-dedicated-family-map"),
			TEXT("play"),
			TEXT("Playable"),
			false,
			false,
			true,
			false,
			false,
			false,
			false
		),
		MakeRoute(
			TEXT("magic-cube-5d-training"),
			TEXT("MagicCube5D Training"),
			TEXT("Launch the family-owned 5D runtime-state, projection, persistence, and dedicated-map training surface."),
			MagicCube5DMapPath,
			HigherDimensionalTrainingGameModeClassPath,
			TEXT("keyboard-mouse-higher-dimensional-training"),
			TEXT("ready-dedicated-family-map"),
			TEXT("play"),
			TEXT("Playable"),
			false,
			false,
			true,
			false,
			false,
			false,
			false
		),
		MakeRoute(
			TEXT("xr-training-validation"),
			TEXT("XR Training Check"),
			TEXT("Launch the OpenXR training pawn on the follow-along map; full green status requires a connected headset session and observed controller input."),
			FollowAlongMapPath,
			XrTrainingGameModeClassPath,
			TEXT("openxr-headset-and-controllers"),
			TEXT("pending-live-headset-controller-observation"),
			TEXT("advanced"),
			TEXT("Optional hardware check"),
			false,
			false,
			true,
			false,
			true,
			true,
			false,
			false
		)
	};
}

TArray<FHyperTwistPuzzleCatalogEntry>
UHyperTwistFirstRunLaunchLibrary::BuildPlayerPuzzleCatalog()
{
	using namespace HyperTwistFirstRunLaunchLibraryInternal;
	return {
		MakeCatalogEntry(
			TEXT("cube/3x3x3"),
			TEXT("Classic Cube"),
			TEXT("3D"),
			TEXT("A responsive 3x3x3 playground with physical picking, professional keyboard turns, timing, hints, replay, and guided practice."),
			EHyperTwistPuzzleAvailability::Playable,
			TEXT("Playable now"),
			TEXT("classic-cube-training"),
			{TEXT("free play"), TEXT("timed solves"), TEXT("guided learning")}
		),
		MakeCatalogEntry(
			TEXT("hypercube/2x2x2x2"),
			TEXT("4D Cube 2x2x2x2"),
			TEXT("4D"),
			TEXT("A compact tesseract puzzle presented through eight readable cells so four-dimensional turns remain learnable."),
			EHyperTwistPuzzleAvailability::Playable,
			TEXT("Playable now"),
			TEXT("magic-cube-4d-2x2x2x2"),
			{TEXT("cell-first projection"), TEXT("exact turns"), TEXT("teaching view")}
		),
		MakeCatalogEntry(
			TEXT("hypercube/3x3x3x3"),
			TEXT("4D Cube 3x3x3x3"),
			TEXT("4D"),
			TEXT("An 81-piece four-dimensional cube with visible-slice projection, axis selection, layer control, and optional shell context."),
			EHyperTwistPuzzleAvailability::Playable,
			TEXT("Playable now"),
			TEXT("magic-cube-4d-3x3x3x3"),
			{TEXT("visible slices"), TEXT("81 tesseracts"), TEXT("keyboard control")}
		),
		MakeCatalogEntry(
			TEXT("hypercube/4x4x4x4"),
			TEXT("4D Cube 4x4x4x4"),
			TEXT("4D"),
			TEXT("A 256-piece four-dimensional cube powered by the generalized exact-state visible-slice runtime, with four layers on every axis."),
			EHyperTwistPuzzleAvailability::Playable,
			TEXT("Playable now"),
			TEXT("magic-cube-4d-4x4x4x4"),
			{TEXT("visible slices"), TEXT("256 pieces"), TEXT("four layers")}
		),
		MakeCatalogEntry(
			TEXT("hypercube/5x5x5x5"),
			TEXT("4D Cube 5x5x5x5"),
			TEXT("4D"),
			TEXT("A 625-piece four-dimensional cube with five exact layers per axis and a focused 125-piece projection slice."),
			EHyperTwistPuzzleAvailability::Playable,
			TEXT("Playable now"),
			TEXT("magic-cube-4d-5x5x5x5"),
			{TEXT("visible slices"), TEXT("625 pieces"), TEXT("five layers")}
		),
		MakeCatalogEntry(
			TEXT("hypercube/6x6x6x6"),
			TEXT("4D Cube 6x6x6x6"),
			TEXT("4D"),
			TEXT("A 1,296-piece four-dimensional cube with six exact layers per axis and a focused 216-piece projection slice."),
			EHyperTwistPuzzleAvailability::Playable,
			TEXT("Playable now"),
			TEXT("magic-cube-4d-6x6x6x6"),
			{TEXT("visible slices"), TEXT("1,296 pieces"), TEXT("six layers")}
		),
		MakeCatalogEntry(
			TEXT("polychoron/magic120cell"),
			TEXT("Magic 120-cell"),
			TEXT("4D polychoron"),
			TEXT("Navigate all 120 dodecahedral cells through a family-owned projection, focus layers, persistence, and dedicated training scene."),
			EHyperTwistPuzzleAvailability::Playable,
			TEXT("Playable now"),
			TEXT("magic-120-cell-training"),
			{TEXT("120 cells"), TEXT("focus layers"), TEXT("save and resume")}
		),
		MakeCatalogEntry(
			TEXT("hypercube/magiccube5d/order3"),
			TEXT("5D Cube"),
			TEXT("5D"),
			TEXT("A five-dimensional order-3 runtime with projection layers, exact state ownership, and persistent sessions."),
			EHyperTwistPuzzleAvailability::Playable,
			TEXT("Playable now"),
			TEXT("magic-cube-5d-training"),
			{TEXT("five dimensions"), TEXT("projection layers"), TEXT("save and resume")}
		),
		MakeCatalogEntry(
			TEXT("tiling/magictile"),
			TEXT("MagicTile Lab"),
			TEXT("Spherical and hyperbolic"),
			TEXT("Experiment with non-Euclidean tiling concepts through the embedded browser preview while its native renderer remains intentionally gated."),
			EHyperTwistPuzzleAvailability::BrowserPreview,
			TEXT("Browser preview"),
			FString(),
			{TEXT("non-Euclidean"), TEXT("embedded preview"), TEXT("state bridge")}
		)
	};
}

TArray<FHyperTwistIntegratedCapability>
UHyperTwistFirstRunLaunchLibrary::BuildIntegratedCapabilityCatalog()
{
	using enum EHyperTwistIntegrationLicenseLane;
	using enum EHyperTwistIntegrationSurface;
	using namespace HyperTwistFirstRunLaunchLibraryInternal;

	return {
		MakeIntegratedCapability(
			TEXT("timer/local-solve-lifecycle"),
			TEXT("Solve timer and session statistics"),
			TEXT("Inspection, solve timing, splits, rolling averages, personal bests, local persistence, and timer-scoped replay."),
			TEXT("Aarav2709/KubeTimr"),
			TEXT("MIT"),
			Permissive,
			NativePlayerService,
			TEXT("classic-cube-training"),
			TEXT("UHyperTwistTrainingSubsystem.LiveTimer"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("learning/advanced-five-style"),
			TEXT("Advanced 5-style drills"),
			TEXT("Focused edge-cycle and blindfold micro-drills with reveal, self-grading, timing, and review scheduling."),
			TEXT("abunickabhi/5style-Trainer"),
			TEXT("MIT"),
			Permissive,
			NativePlayerService,
			TEXT("menu:learn"),
			TEXT("UHyperTwistTrainingCatalogLibrary.5style-4mover"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("browser/solve-analytics"),
			TEXT("Browser solve analytics"),
			TEXT("Solve-trend and progress visualization in the bounded browser companion runtime."),
			TEXT("apache/echarts"),
			TEXT("Apache-2.0"),
			Permissive,
			BrowserSupport,
			TEXT("web:browser-access"),
			TEXT("UHyperTwistTrainingAnalyticsLibrary"),
			TEXT("permissive-browser-support")
		),
		MakeIntegratedCapability(
			TEXT("browser/model-preview"),
			TEXT("Standards-aware model preview"),
			TEXT("A bounded glTF preview and quality-assurance surface for browser companion assets."),
			TEXT("google/model-viewer"),
			TEXT("Apache-2.0"),
			Permissive,
			BrowserSupport,
			TEXT("web:browser-access"),
			TEXT("UHyperTwistTrainingViewerLibrary"),
			TEXT("permissive-browser-support")
		),
		MakeIntegratedCapability(
			TEXT("puzzle/generalized-four-dimensional-cubes"),
			TEXT("Generalized four-dimensional cubes"),
			TEXT("Exact order-3 through order-6 state, notation, projection, replay verification, statistics, and puzzle-definition contracts."),
			TEXT("HactarCE/Hyperspeedcube"),
			TEXT("MIT OR Apache-2.0"),
			Permissive,
			NativePlayable,
			TEXT("magic-cube-4d-3x3x3x3"),
			TEXT("UHyperTwistVirtual3333ProjectionLibrary"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("learning/higher-dimensional-knowledge"),
			TEXT("Higher-dimensional learning library"),
			TEXT("Curriculum, notation, puzzle taxonomy, progression stages, software references, and community context."),
			TEXT("Hypercubers/hypercubing.xyz"),
			TEXT("MIT"),
			Permissive,
			NativePlayerService,
			TEXT("menu:learn"),
			TEXT("UHyperTwistTrainingKnowledgeLibrary"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("recognition/classic-cube-observation"),
			TEXT("Cube recognition and calibration"),
			TEXT("Face observation, webcam-shell calibration, multilingual guidance, presentation, and bounded font readiness."),
			TEXT("kkoomen/qbr"),
			TEXT("MIT"),
			Permissive,
			NativePlayerService,
			TEXT("menu:settings"),
			TEXT("UHyperTwistTrainingSubsystem.RecognitionSession"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("learning/persisted-coaching"),
			TEXT("Persisted and weighted coaching"),
			TEXT("Weighted and recency-aware review, persisted training sessions, method exploration, and blindfold-oriented coaching."),
			TEXT("Lykos/cube_trainer"),
			TEXT("MIT"),
			Permissive,
			NativePlayerService,
			TEXT("menu:learn"),
			TEXT("UHyperTwistTrainingRepositoryLibrary"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("coach/embodied-companion"),
			TEXT("Narrated coach presentation"),
			TEXT("Voice, subtitle, avatar-embed, and provider-boundary contracts beneath HyperTwist's fixed in-game coach."),
			TEXT("met4citizen/TalkingHead"),
			TEXT("MIT"),
			Permissive,
			NativePlayerService,
			TEXT("menu:settings"),
			TEXT("UHyperTwistTrainingCompanionLibrary"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("browser/spatial-runtime"),
			TEXT("Browser spatial runtime"),
			TEXT("The browser companion's bounded three-dimensional rendering substrate."),
			TEXT("mrdoob/three.js"),
			TEXT("MIT"),
			Permissive,
			BrowserSupport,
			TEXT("web:browser-access"),
			TEXT("UHyperTwistTrainingSpatialLibrary.Three"),
			TEXT("permissive-browser-support")
		),
		MakeIntegratedCapability(
			TEXT("browser/spatial-composition"),
			TEXT("Browser scene composition"),
			TEXT("Declarative browser-side scene composition above the bounded spatial runtime."),
			TEXT("pmndrs/react-three-fiber"),
			TEXT("MIT"),
			Permissive,
			BrowserSupport,
			TEXT("web:browser-access"),
			TEXT("UHyperTwistTrainingSpatialLibrary.ReactThreeFiber"),
			TEXT("permissive-browser-support")
		),
		MakeIntegratedCapability(
			TEXT("browser/xr-support"),
			TEXT("Optional browser XR support"),
			TEXT("Browser-side XR session contracts kept separate from the authoritative Unreal OpenXR desktop path."),
			TEXT("pmndrs/xr"),
			TEXT("MIT"),
			Permissive,
			BrowserSupport,
			TEXT("web:browser-access"),
			TEXT("UHyperTwistTrainingSpatialLibrary.Xr"),
			TEXT("permissive-browser-support")
		),
		MakeIntegratedCapability(
			TEXT("puzzle/magic-120-cell"),
			TEXT("Magic 120-cell"),
			TEXT("A family-owned 7,560-facelet permutation state, legal turns, projection, focus, persistence, and dedicated scene."),
			TEXT("roice3/Magic120Cell"),
			TEXT("MIT"),
			Permissive,
			NativePlayable,
			TEXT("magic-120-cell-training"),
			TEXT("UHyperTwistMagic120CellRuntimeLibrary"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("puzzle/magic-cube-5d"),
			TEXT("Five-dimensional cube"),
			TEXT("An exact order-3 five-dimensional state with 243 cubies, 810 facelets, legal turns, projection, and persistence."),
			TEXT("roice3/MagicCube5D"),
			TEXT("MIT"),
			Permissive,
			NativePlayable,
			TEXT("magic-cube-5d-training"),
			TEXT("UHyperTwistMagicCube5DRuntimeLibrary"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("puzzle/non-euclidean-tiling-preview"),
			TEXT("MagicTile browser lab"),
			TEXT("Topology, macro remapping, state bridge, and browser preview while native renderer widening remains gated."),
			TEXT("roice3/MagicTile"),
			TEXT("MIT"),
			Permissive,
			BrowserSupport,
			TEXT("web:browser-access"),
			TEXT("UHyperTwistTrainingTilingLibrary"),
			TEXT("permissive-browser-support")
		),
		MakeIntegratedCapability(
			TEXT("learning/algorithm-foundation"),
			TEXT("Algorithm training foundation"),
			TEXT("Organized algorithm sets, prompts, scrambles, reveal flow, self-grading, and training-catalog composition."),
			TEXT("tao-yu/Alg-Trainer"),
			TEXT("MIT"),
			Permissive,
			NativePlayerService,
			TEXT("menu:learn"),
			TEXT("UHyperTwistTrainingCatalogLibrary.oll-t"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("learning/cross-ladder"),
			TEXT("Cross planning ladder"),
			TEXT("Four-move cross-planning drills with setup, hidden answer, timing, self-grading, and review continuity."),
			TEXT("newyork-anthonyng/rubiks-cross-trainer"),
			TEXT("MIT"),
			Permissive,
			NativePlayerService,
			TEXT("menu:learn"),
			TEXT("UHyperTwistTrainingCatalogLibrary.cross-4move"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("solver/classic-cube-reconstruction"),
			TEXT("Classic cube solve guidance"),
			TEXT("Committed-face reconstruction, correction flow, solve explanation, and bounded browser/webcam support."),
			TEXT("vivaansinghvi07/rubix-cube-solver"),
			TEXT("MIT"),
			Permissive,
			NativePlayerService,
			TEXT("classic-cube-training"),
			TEXT("UHyperTwistTrainingSubsystem.SolveExplanation"),
			TEXT("permissive-first-party-owner")
		),
		MakeIntegratedCapability(
			TEXT("learning/roux-method"),
			TEXT("Roux method studio"),
			TEXT("First-party Roux stages, blockbuilding, CMLL study, and review flow produced through the accepted clean-room chain."),
			TEXT("onionhoney/roux-trainers"),
			TEXT("GPL-3.0"),
			RestrictiveCleanRoom,
			NativePlayerService,
			TEXT("menu:learn"),
			TEXT("UHyperTwistTrainingCatalogLibrary.roux-cmll"),
			TEXT("restrictive-clean-room-first-party")
		),
		MakeIntegratedCapability(
			TEXT("algorithm/parser-and-interchange"),
			TEXT("Algorithm parser and interchange"),
			TEXT("First-party parser, AST, traversal, validation, keyboard mapping, serialization, and sharing semantics."),
			TEXT("cubing/alg.js"),
			TEXT("GPL-3.0-or-later"),
			RestrictiveCleanRoom,
			NativePlayerService,
			TEXT("classic-cube-training"),
			TEXT("UHyperTwistAlgorithmLibrary"),
			TEXT("restrictive-clean-room-first-party")
		),
		MakeIntegratedCapability(
			TEXT("replay/player-and-timeline"),
			TEXT("Replay player and timeline"),
			TEXT("First-party player shell, scrubber, cursor timeline, adapter boundary, and local visualization fallback."),
			TEXT("cubing/twisty.js"),
			TEXT("GPL-3.0-or-later"),
			RestrictiveCleanRoom,
			NativePlayerService,
			TEXT("classic-cube-training"),
			TEXT("UHyperTwistViewerLibrary"),
			TEXT("restrictive-clean-room-first-party")
		),
		MakeIntegratedCapability(
			TEXT("puzzle/four-dimensional-order-2"),
			TEXT("Four-dimensional 2x2x2x2"),
			TEXT("First-party legality, random-state generation, move algebra, exact turns, scramble packets, and teaching projection."),
			TEXT("HactarCE/2x2x2x2-Scrambler"),
			TEXT("GPL-3.0"),
			RestrictiveCleanRoom,
			NativePlayable,
			TEXT("magic-cube-4d-2x2x2x2"),
			TEXT("UHyperTwistCoreLibrary.Melinda"),
			TEXT("restrictive-clean-room-first-party")
		),
		MakeIntegratedCapability(
			TEXT("session/integrated-practice"),
			TEXT("Integrated practice sessions"),
			TEXT("First-party training/timer coupling, session analytics, smart-device lifecycle, publication gating, and local challenges."),
			TEXT("kash/cubedesk"),
			TEXT("GPL-3.0 / proprietary-conflict"),
			RestrictiveCleanRoom,
			NativePlayerService,
			TEXT("classic-cube-training"),
			TEXT("UHyperTwistTrainingSubsystem.CubeDeskBounds"),
			TEXT("restrictive-clean-room-first-party")
		),
		MakeIntegratedCapability(
			TEXT("classic/semantic-adapter"),
			TEXT("Classic cubing semantics"),
			TEXT("A bounded semantic, geometry, search, viewer-adapter, and device-boundary layer beneath classic play."),
			TEXT("cubing/cubing.js"),
			TEXT("MPL-2.0 OR GPL-3.0-or-later"),
			BoundarySensitive,
			NativePlayerService,
			TEXT("classic-cube-training"),
			TEXT("UHyperTwistTrainingClassicCubingLibrary"),
			TEXT("boundary-sensitive-first-party-adapter")
		),
		MakeIntegratedCapability(
			TEXT("puzzle/legacy-four-dimensional-context"),
			TEXT("Legacy four-dimensional continuity"),
			TEXT("Attributed history, macro, puzzle-description, and interaction contracts beneath the modern exact 4D runtimes."),
			TEXT("cutelyaware/magiccube4d"),
			TEXT("Custom permissive attribution license"),
			BoundarySensitive,
			NativePlayable,
			TEXT("magic-cube-4d-3x3x3x3"),
			TEXT("UHyperTwistTrainingLegacy4DLibrary"),
			TEXT("boundary-sensitive-attributed-first-party")
		),
		MakeIntegratedCapability(
			TEXT("browser/shared-asset-qa"),
			TEXT("Browser asset quality fixtures"),
			TEXT("An allowlisted mixed-provenance fixture and environment pack used only for bounded browser quality checks."),
			TEXT("google/model-viewer/packages/shared-assets"),
			TEXT("Mixed per-asset terms"),
			BoundarySensitive,
			BrowserSupport,
			TEXT("web:browser-access"),
			TEXT("UHyperTwistTrainingSharedAssetLibrary"),
			TEXT("boundary-sensitive-allowlisted-support")
		),
		MakeIntegratedCapability(
			TEXT("operator/feature-control-plane"),
			TEXT("Feature and rollout control plane"),
			TEXT("Local feature governance, rollout, replay diagnostics, scheduling, and compliance boundaries; telemetry is not silently enabled."),
			TEXT("PostHog/posthog"),
			TEXT("MIT with enterprise boundaries"),
			BoundarySensitive,
			OperatorSupport,
			TEXT("menu:advanced"),
			TEXT("UHyperTwistTrainingControlPlaneLibrary"),
			TEXT("boundary-sensitive-first-party-control-plane")
		),
		MakeIntegratedCapability(
			TEXT("operator/capture-history"),
			TEXT("Consent-bound capture history"),
			TEXT("Local event capture, permission, persistence, vault lifecycle, and timeline-review contracts without background capture by default."),
			TEXT("screenpipe/screenpipe"),
			TEXT("MIT with enterprise boundaries"),
			BoundarySensitive,
			OperatorSupport,
			TEXT("menu:advanced"),
			TEXT("UHyperTwistTrainingCaptureHistoryLibrary"),
			TEXT("boundary-sensitive-first-party-contract")
		),
		MakeIntegratedCapability(
			TEXT("operator/replay-media-export"),
			TEXT("Replay media export planning"),
			TEXT("First-party replay plan, playback, render-orchestration, parser, explainer, and compliance contracts; fresh shipping work prefers Unreal-native export."),
			TEXT("remotion-dev/remotion"),
			TEXT("Remotion License"),
			BoundarySensitive,
			OperatorSupport,
			TEXT("menu:advanced"),
			TEXT("UHyperTwistTrainingMediaExportLibrary"),
			TEXT("boundary-sensitive-retained-output-restrictive-future")
		)
	};
}

bool UHyperTwistFirstRunLaunchLibrary::TryFindIntegratedCapability(
	const FString& CanonicalRepository,
	FHyperTwistIntegratedCapability& OutCapability
)
{
	for (const FHyperTwistIntegratedCapability& Capability
		: BuildIntegratedCapabilityCatalog())
	{
		if (Capability.CanonicalRepository.Equals(
				CanonicalRepository,
				ESearchCase::IgnoreCase))
		{
			OutCapability = Capability;
			return true;
		}
	}

	OutCapability = FHyperTwistIntegratedCapability();
	return false;
}

FString UHyperTwistFirstRunLaunchLibrary::GetIntegrationLicenseLaneLabel(
	const EHyperTwistIntegrationLicenseLane LicenseLane
)
{
	switch (LicenseLane)
	{
	case EHyperTwistIntegrationLicenseLane::Permissive:
		return TEXT("Permissive");
	case EHyperTwistIntegrationLicenseLane::RestrictiveCleanRoom:
		return TEXT("Restrictive clean-room");
	case EHyperTwistIntegrationLicenseLane::BoundarySensitive:
		return TEXT("Boundary-sensitive");
	default:
		return TEXT("Unknown");
	}
}

FString UHyperTwistFirstRunLaunchLibrary::GetIntegrationSurfaceLabel(
	const EHyperTwistIntegrationSurface Surface
)
{
	switch (Surface)
	{
	case EHyperTwistIntegrationSurface::NativePlayable:
		return TEXT("Playable puzzle engines");
	case EHyperTwistIntegrationSurface::NativePlayerService:
		return TEXT("Learning and player services");
	case EHyperTwistIntegrationSurface::BrowserSupport:
		return TEXT("Browser companion support");
	case EHyperTwistIntegrationSurface::OperatorSupport:
		return TEXT("Operator and release support");
	default:
		return TEXT("Other support");
	}
}

bool UHyperTwistFirstRunLaunchLibrary::TryFindPuzzleCatalogEntry(
	const FString& PuzzleId,
	FHyperTwistPuzzleCatalogEntry& OutEntry
)
{
	for (const FHyperTwistPuzzleCatalogEntry& Entry : BuildPlayerPuzzleCatalog())
	{
		if (Entry.PuzzleId.Equals(PuzzleId, ESearchCase::IgnoreCase))
		{
			OutEntry = Entry;
			return true;
		}
	}
	OutEntry = FHyperTwistPuzzleCatalogEntry();
	return false;
}

bool UHyperTwistFirstRunLaunchLibrary::TryFindFirstRunLaunchRoute(
	const FString& RouteId,
	FHyperTwistFirstRunLaunchRoute& OutRoute
)
{
	for (const FHyperTwistFirstRunLaunchRoute& Route : BuildFirstRunLaunchRoutes())
	{
		if (Route.RouteId == RouteId)
		{
			OutRoute = Route;
			return true;
		}
	}

	OutRoute = FHyperTwistFirstRunLaunchRoute();
	return false;
}

EHyperTwistPackagedStartupRouteParseResult
UHyperTwistFirstRunLaunchLibrary::ParsePackagedStartupRouteArgument(
	const TCHAR* CommandLine,
	FHyperTwistFirstRunLaunchRoute& OutRoute,
	FString& OutFailureReason
)
{
	using namespace HyperTwistFirstRunLaunchLibraryInternal;

	OutRoute = FHyperTwistFirstRunLaunchRoute();
	OutFailureReason.Reset();
	if (CommandLine == nullptr || CommandLine[0] == TEXT('\0'))
	{
		return EHyperTwistPackagedStartupRouteParseResult::NotPresent;
	}

	TArray<FString> Tokens;
	TArray<FString> Switches;
	FCommandLine::Parse(CommandLine, Tokens, Switches);

	const FString ArgumentName(PackagedStartupRouteArgumentName);
	const FString ArgumentPrefix = ArgumentName + TEXT("=");
	TArray<FString> RouteValues;
	for (FString Switch : Switches)
	{
		while (Switch.StartsWith(TEXT("-")))
		{
			Switch.RightChopInline(1, EAllowShrinking::No);
		}

		if (Switch.Equals(ArgumentName, ESearchCase::IgnoreCase))
		{
			RouteValues.Add(FString());
		}
		else if (Switch.StartsWith(ArgumentPrefix, ESearchCase::IgnoreCase))
		{
			RouteValues.Add(Switch.Mid(ArgumentPrefix.Len()));
		}
	}

	if (RouteValues.IsEmpty())
	{
		return EHyperTwistPackagedStartupRouteParseResult::NotPresent;
	}
	if (RouteValues.Num() != 1)
	{
		OutFailureReason = FString::Printf(
			TEXT("Expected exactly one -%s argument, but received %d."),
			PackagedStartupRouteArgumentName,
			RouteValues.Num()
		);
		return EHyperTwistPackagedStartupRouteParseResult::Invalid;
	}

	FString RouteId = RouteValues[0].TrimStartAndEnd();
	if (RouteId.Len() >= 2
		&& RouteId.StartsWith(TEXT("\""))
		&& RouteId.EndsWith(TEXT("\"")))
	{
		RouteId = RouteId.Mid(1, RouteId.Len() - 2).TrimStartAndEnd();
	}
	if (RouteId.IsEmpty())
	{
		OutFailureReason = FString::Printf(
			TEXT("-%s requires a registered route identifier."),
			PackagedStartupRouteArgumentName
		);
		return EHyperTwistPackagedStartupRouteParseResult::Invalid;
	}
	if (RouteId.Len() > 64)
	{
		OutFailureReason = FString::Printf(
			TEXT("-%s exceeded the 64-character route identifier limit."),
			PackagedStartupRouteArgumentName
		);
		return EHyperTwistPackagedStartupRouteParseResult::Invalid;
	}

	for (const TCHAR Character : RouteId)
	{
		const bool bAllowedCharacter =
			(Character >= TEXT('a') && Character <= TEXT('z'))
			|| (Character >= TEXT('0') && Character <= TEXT('9'))
			|| Character == TEXT('-');
		if (!bAllowedCharacter)
		{
			OutFailureReason = FString::Printf(
				TEXT("-%s contains an invalid route identifier."),
				PackagedStartupRouteArgumentName
			);
			return EHyperTwistPackagedStartupRouteParseResult::Invalid;
		}
	}

	if (!TryFindFirstRunLaunchRoute(RouteId, OutRoute)
		|| !OutRoute.IsStructurallyValid())
	{
		OutRoute = FHyperTwistFirstRunLaunchRoute();
		OutFailureReason = FString::Printf(
			TEXT("-%s requested unknown route '%s'."),
			PackagedStartupRouteArgumentName,
			*RouteId
		);
		return EHyperTwistPackagedStartupRouteParseResult::Invalid;
	}

	return EHyperTwistPackagedStartupRouteParseResult::Valid;
}
