#include "HyperTwistTraining/HyperTwistTrainingViewerLibrary.h"

namespace HyperTwistTrainingViewerLibraryInternal
{
	FHyperTwistTrainingSourceAttribution MakeAttribution(
		const FString& SourceRepo,
		const FString& SourceLicense,
		const FString& TrackId,
		const FString& Notes
	)
	{
		FHyperTwistTrainingSourceAttribution Attribution;
		Attribution.SourceMode = EHyperTwistTrainingSourceMode::DirectDonor;
		Attribution.SourceRepo = SourceRepo;
		Attribution.SourceLicense = SourceLicense;
		Attribution.SourceTrackId = TrackId;
		Attribution.SourceNotes = Notes;
		return Attribution;
	}

	FHyperTwistTrainingSourceAttribution MakeModelViewerAttribution(const FString& TrackId, const FString& Notes)
	{
		return MakeAttribution(TEXT("google/model-viewer"), TEXT("Apache-2.0"), TrackId, Notes);
	}

	FHyperTwistTrainingSourceAttribution MakeSpaceOperaAttribution(const FString& TrackId, const FString& Notes)
	{
		return MakeAttribution(TEXT("google/model-viewer/packages/space-opera"), TEXT("Apache-2.0"), TrackId, Notes);
	}

	FHyperTwistTrainingSourceAttribution MakeEffectsAttribution(const FString& TrackId, const FString& Notes)
	{
		return MakeAttribution(
			TEXT("google/model-viewer/packages/model-viewer-effects"),
			TEXT("Apache-2.0"),
			TrackId,
			Notes
		);
	}

	FHyperTwistTrainingSourceAttribution MakeModelViewerDevAttribution(const FString& TrackId, const FString& Notes)
	{
		return MakeAttribution(TEXT("google/model-viewer/packages/modelviewer.dev"), TEXT("Apache-2.0"), TrackId, Notes);
	}

	FHyperTwistTrainingSourceAttribution MakeRenderFidelityAttribution(const FString& TrackId, const FString& Notes)
	{
		return MakeAttribution(
			TEXT("google/model-viewer/packages/render-fidelity-tools"),
			TEXT("Apache-2.0"),
			TrackId,
			Notes
		);
	}

	FHyperTwistTrainingSourceAttribution MakeKhronosViewerAttribution(const FString& TrackId, const FString& Notes)
	{
		return MakeAttribution(TEXT("KhronosGroup/glTF-Sample-Viewer"), TEXT("Apache-2.0"), TrackId, Notes);
	}

	FHyperTwistTrainingSourceAttribution MakeKhronosRendererAttribution(const FString& TrackId, const FString& Notes)
	{
		return MakeAttribution(TEXT("KhronosGroup/glTF-Sample-Renderer"), TEXT("Apache-2.0"), TrackId, Notes);
	}

	FHyperTwistTrainingViewerAssetInputReference MakeAssetInput(
		const FString& AssetInputId,
		const FString& Label,
		const TArray<FString>& FileExtensions,
		const TArray<FString>& DeliveryModes,
		const FString& Summary,
		const FHyperTwistTrainingSourceAttribution& SourceAttribution
	)
	{
		FHyperTwistTrainingViewerAssetInputReference Input;
		Input.AssetInputId = AssetInputId;
		Input.Label = Label;
		Input.FileExtensions = FileExtensions;
		Input.DeliveryModes = DeliveryModes;
		Input.Summary = Summary;
		Input.SourceAttribution = SourceAttribution;
		return Input;
	}

	FHyperTwistTrainingViewerLifecycleHookReference MakeLifecycleHook(
		const FString& HookId,
		const FString& Label,
		const FString& Trigger,
		const FString& OutputSurface,
		const TArray<FString>& Tags,
		const FHyperTwistTrainingSourceAttribution& SourceAttribution
	)
	{
		FHyperTwistTrainingViewerLifecycleHookReference Hook;
		Hook.HookId = HookId;
		Hook.Label = Label;
		Hook.Trigger = Trigger;
		Hook.OutputSurface = OutputSurface;
		Hook.Tags = Tags;
		Hook.SourceAttribution = SourceAttribution;
		return Hook;
	}

	FHyperTwistTrainingViewerEditorToolReference MakeEditorTool(
		const FString& ToolId,
		const FString& Label,
		const FString& Summary,
		const TArray<FString>& WorkflowTags,
		const TArray<FString>& PreviewStateTags,
		const TArray<FString>& ExportArtifactIds,
		const FHyperTwistTrainingSourceAttribution& SourceAttribution
	)
	{
		FHyperTwistTrainingViewerEditorToolReference Tool;
		Tool.ToolId = ToolId;
		Tool.Label = Label;
		Tool.Summary = Summary;
		Tool.WorkflowTags = WorkflowTags;
		Tool.PreviewStateTags = PreviewStateTags;
		Tool.ExportArtifactIds = ExportArtifactIds;
		Tool.SourceAttribution = SourceAttribution;
		return Tool;
	}

	FHyperTwistTrainingViewerQaArtifactReference MakeQaArtifact(
		const FString& ArtifactId,
		const FString& Label,
		const FString& ArtifactKind,
		const FString& Summary,
		const TArray<FString>& Tags,
		const FHyperTwistTrainingSourceAttribution& SourceAttribution
	)
	{
		FHyperTwistTrainingViewerQaArtifactReference Artifact;
		Artifact.ArtifactId = ArtifactId;
		Artifact.Label = Label;
		Artifact.ArtifactKind = ArtifactKind;
		Artifact.Summary = Summary;
		Artifact.Tags = Tags;
		Artifact.SourceAttribution = SourceAttribution;
		return Artifact;
	}

	void AppendJoined(FString& OutText, const TArray<FString>& Values)
	{
		for (int32 Index = 0; Index < Values.Num(); ++Index)
		{
			if (Index > 0)
			{
				OutText.Append(TEXT(", "));
			}
			OutText.Append(Values[Index]);
		}
	}
}

FHyperTwistTrainingViewerReferenceBundle UHyperTwistTrainingViewerLibrary::BuildBundledBrowserViewerReferenceBundle()
{
	using namespace HyperTwistTrainingViewerLibraryInternal;

	FHyperTwistTrainingViewerReferenceBundle Bundle;
	Bundle.ReferenceUtc = TEXT("2026-05-13T00:00:00Z");
	Bundle.PrimaryEmbedContractId = TEXT("browser-viewer-embed");
	Bundle.PrimaryEditorContractId = TEXT("compact-viewer-editor");
	Bundle.PrimaryQaCheckId = TEXT("asset-validation-and-statistics");
	Bundle.PrimaryDocumentationBoundaryId = TEXT("docs-demo-separation");

	Bundle.AssetInputs =
	{
		MakeAssetInput(
			TEXT("asset-input/glb-local-upload"),
			TEXT("GLB local upload"),
			{TEXT(".glb")},
			{TEXT("local-file"), TEXT("drag-drop")},
			TEXT("Single-file model ingestion for compact browser preview, poster capture, and QA verification."),
			MakeModelViewerAttribution(
				TEXT("viewer-embed"),
				TEXT("Preserves polished direct model loading and progress tracking from model-viewer without inheriting the donor app shell.")
			)
		),
		MakeAssetInput(
			TEXT("asset-input/gltf-relative-bundle"),
			TEXT("glTF relative bundle"),
			{TEXT(".gltf"), TEXT(".bin"), TEXT(".png"), TEXT(".jpg"), TEXT(".ktx2")},
			{TEXT("relative-bundle"), TEXT("url-resolved")},
			TEXT("Multi-file bundle ingestion for standards-aware preview, variant coverage, and resource-resolution checks."),
			MakeKhronosViewerAttribution(
				TEXT("asset-qa"),
				TEXT("Preserves bundle and resource-loading expectations from the retained glTF-Sample-Viewer lane for standards-aware QA.")
			)
		),
		MakeAssetInput(
			TEXT("asset-input/environment-fixture"),
			TEXT("Environment and lighting fixture"),
			{TEXT(".hdr"), TEXT(".exr")},
			{TEXT("qa-fixture"), TEXT("local-sidecar")},
			TEXT("Environment fixture input for lighting parity, tone-mapping comparison, and visual-regression capture."),
			MakeKhronosRendererAttribution(
				TEXT("renderer-fixture"),
				TEXT("Preserves environment-lighting and renderer-state expectations from the retained renderer substrate for QA and comparison work.")
			)
		),
		MakeAssetInput(
			TEXT("asset-input/catalog-reference-model"),
			TEXT("Catalog reference model"),
			{TEXT(".glb"), TEXT(".gltf")},
			{TEXT("catalog-reference"), TEXT("first-party-relative")},
			TEXT("First-party packaged reference model input for support-plane viewer embeds without relying on donor docs/demo shells."),
			MakeModelViewerAttribution(
				TEXT("support-plane-reference"),
				TEXT("Preserves embeddable viewer behavior for first-party catalog references while keeping donor docs and demos out of the shippable lane.")
			)
		)
	};

	Bundle.LifecycleHooks =
	{
		MakeLifecycleHook(
			TEXT("hook/model-load-progress"),
			TEXT("Model load progress"),
			TEXT("asset ingestion begins or resources resolve"),
			TEXT("progress and readiness surface"),
			{TEXT("load"), TEXT("progress"), TEXT("readiness")},
			MakeModelViewerAttribution(
				TEXT("viewer-lifecycle"),
				TEXT("Preserves progress tracking, load completion, and visibility-readiness behavior from the core model-viewer component.")
			)
		),
		MakeLifecycleHook(
			TEXT("hook/model-loaded"),
			TEXT("Model loaded"),
			TEXT("scene and framing data become ready"),
			TEXT("viewer-ready surface"),
			{TEXT("load"), TEXT("framing"), TEXT("ready")},
			MakeModelViewerAttribution(
				TEXT("viewer-lifecycle"),
				TEXT("Preserves the donor's framing-aware loaded state and post-load interaction readiness boundary.")
			)
		),
		MakeLifecycleHook(
			TEXT("hook/camera-state-changed"),
			TEXT("Camera state changed"),
			TEXT("camera orbit, target, or field of view changes"),
			TEXT("camera-settings surface"),
			{TEXT("camera"), TEXT("orbit"), TEXT("preview-state")},
			MakeSpaceOperaAttribution(
				TEXT("editor-camera"),
				TEXT("Preserves bounded camera orbit, target, and framing edit semantics from the space-opera camera settings surface.")
			)
		),
		MakeLifecycleHook(
			TEXT("hook/hotspot-selection-changed"),
			TEXT("Hotspot selection changed"),
			TEXT("annotation or hotspot selection mutates"),
			TEXT("annotation and focus surface"),
			{TEXT("hotspot"), TEXT("annotation"), TEXT("focus")},
			MakeSpaceOperaAttribution(
				TEXT("editor-hotspot"),
				TEXT("Preserves bounded hotspot authoring and focus semantics from the space-opera hotspot panel and editor surfaces.")
			)
		),
		MakeLifecycleHook(
			TEXT("hook/capture-requested"),
			TEXT("Capture requested"),
			TEXT("viewer capture, screenshot, or poster artifact is requested"),
			TEXT("artifact capture surface"),
			{TEXT("capture"), TEXT("artifact"), TEXT("qa")},
			MakeKhronosViewerAttribution(
				TEXT("qa-capture"),
				TEXT("Preserves standards-aware capture and camera export posture from the retained glTF-Sample-Viewer lane.")
			)
		),
		MakeLifecycleHook(
			TEXT("hook/validation-requested"),
			TEXT("Validation requested"),
			TEXT("validator or renderer-comparison workflow is invoked"),
			TEXT("validation and failure-reporting surface"),
			{TEXT("validation"), TEXT("statistics"), TEXT("failure-reporting")},
			MakeKhronosViewerAttribution(
				TEXT("qa-validation"),
				TEXT("Preserves validator, statistics, and failure-reporting entry points from the retained glTF-Sample-Viewer lane.")
			)
		)
	};

	FHyperTwistTrainingViewerEmbedContract EmbedContract;
	EmbedContract.ContractId = TEXT("browser-viewer-embed");
	EmbedContract.Title = TEXT("Browser viewer embed contract");
	EmbedContract.Summary = TEXT("First-party support-plane embed for model preview, orbit control, annotation, and standards-aware readiness checks.");
	EmbedContract.SupportedAssetInputIds =
	{
		TEXT("asset-input/glb-local-upload"),
		TEXT("asset-input/gltf-relative-bundle"),
		TEXT("asset-input/environment-fixture"),
		TEXT("asset-input/catalog-reference-model")
	};
	EmbedContract.CameraStateFields =
	{
		TEXT("camera-orbit"),
		TEXT("camera-target"),
		TEXT("field-of-view"),
		TEXT("auto-rotate"),
		TEXT("scene-camera-selection"),
		TEXT("camera-export")
	};
	EmbedContract.AnnotationSurfaceTags =
	{
		TEXT("hotspot-slot"),
		TEXT("focus-annotation"),
		TEXT("selected-emphasis"),
		TEXT("preview-callout")
	};
	EmbedContract.LifecycleHookIds =
	{
		TEXT("hook/model-load-progress"),
		TEXT("hook/model-loaded"),
		TEXT("hook/camera-state-changed"),
		TEXT("hook/hotspot-selection-changed"),
		TEXT("hook/capture-requested"),
		TEXT("hook/validation-requested")
	};
	EmbedContract.ShippableBehaviorTags =
	{
		TEXT("embeddable-viewer"),
		TEXT("orbit-controls"),
		TEXT("annotation-ready"),
		TEXT("capture-ready"),
		TEXT("qa-hook-ready")
	};
	EmbedContract.ExplicitExclusions =
	{
		TEXT("static documentation site shell"),
		TEXT("demo navigation chrome"),
		TEXT("mixed-provenance shared-assets payload shipping"),
		TEXT("gameplay or simulation ownership")
	};
	EmbedContract.SourceAttribution = MakeModelViewerAttribution(
		TEXT("browser-viewer-embed"),
		TEXT("Preserves bounded viewer embed, camera, and annotation semantics from model-viewer while keeping docs/demo shells and runtime-foundation ownership out of scope.")
	);
	Bundle.EmbedContracts = {EmbedContract};

	Bundle.EditorTools =
	{
		MakeEditorTool(
			TEXT("tool/inspector-json-surface"),
			TEXT("Inspector JSON surface"),
			TEXT("Inspectable model JSON and thumbnail surface for compact viewer-side inspection and debugging."),
			{TEXT("inspection"), TEXT("gltf-json"), TEXT("thumbnail-review")},
			{TEXT("model-loaded"), TEXT("texture-thumbnail-cache")},
			{},
			MakeSpaceOperaAttribution(
				TEXT("editor-inspector"),
				TEXT("Preserves the bounded inspector surface for loaded GLTF JSON and thumbnail inspection from the retained space-opera lane.")
			)
		),
		MakeEditorTool(
			TEXT("tool/camera-settings"),
			TEXT("Camera settings"),
			TEXT("Orbit, target, framing, and auto-rotate editor surface for compact viewer support flows."),
			{TEXT("camera"), TEXT("orbit"), TEXT("framing")},
			{TEXT("model-loaded"), TEXT("camera-editable")},
			{TEXT("artifact/camera-export-json")},
			MakeSpaceOperaAttribution(
				TEXT("editor-camera"),
				TEXT("Preserves bounded camera settings editing, framing reset, and saved orbit semantics from the retained space-opera lane.")
			)
		),
		MakeEditorTool(
			TEXT("tool/hotspot-panel"),
			TEXT("Hotspot panel"),
			TEXT("Annotation authoring and focus-point editing surface for model-side explainers and callouts."),
			{TEXT("hotspot"), TEXT("annotation"), TEXT("explainer")},
			{TEXT("model-loaded"), TEXT("annotation-editable")},
			{TEXT("artifact/snippet-html")},
			MakeSpaceOperaAttribution(
				TEXT("editor-hotspot"),
				TEXT("Preserves bounded hotspot authoring, add-hotspot, and focus-callout semantics from the retained space-opera lane.")
			)
		),
		MakeEditorTool(
			TEXT("tool/snippet-export"),
			TEXT("Snippet and export surface"),
			TEXT("Compact snippet, poster, and portable viewer-export surface for support-plane browser embeds."),
			{TEXT("snippet"), TEXT("export"), TEXT("portable-preview")},
			{TEXT("model-loaded"), TEXT("preview-rendered")},
			{TEXT("artifact/snippet-html"), TEXT("artifact/capture-png")},
			MakeSpaceOperaAttribution(
				TEXT("editor-export"),
				TEXT("Preserves snippet/export and compact preview semantics from the retained model_viewer_snippet and export-panel surfaces.")
			)
		),
		MakeEditorTool(
			TEXT("tool/highlight-effects"),
			TEXT("Highlight and emphasis effects"),
			TEXT("Optional outline and SSAO emphasis surface that stays subordinate to the viewer/editor lane."),
			{TEXT("effects"), TEXT("highlight"), TEXT("guided-focus")},
			{TEXT("model-loaded"), TEXT("camera-editable"), TEXT("annotation-editable")},
			{},
			MakeEffectsAttribution(
				TEXT("viewer-effects"),
				TEXT("Preserves bounded outline, SSAO, and guided-emphasis patterns from the retained model-viewer-effects package.")
			)
		)
	};

	FHyperTwistTrainingViewerEditorContract EditorContract;
	EditorContract.EditorContractId = TEXT("compact-viewer-editor");
	EditorContract.Title = TEXT("Compact browser editor and inspection contract");
	EditorContract.Summary = TEXT("First-party editor boundary for hotspot authoring, camera state editing, snippet export, and compact inspection around a bundled browser viewer.");
	EditorContract.ToolIds =
	{
		TEXT("tool/inspector-json-surface"),
		TEXT("tool/camera-settings"),
		TEXT("tool/hotspot-panel"),
		TEXT("tool/snippet-export"),
		TEXT("tool/highlight-effects")
	};
	EditorContract.RequiredPreviewStateTags =
	{
		TEXT("model-loaded"),
		TEXT("camera-editable"),
		TEXT("annotation-editable"),
		TEXT("preview-rendered")
	};
	EditorContract.ExportArtifactIds =
	{
		TEXT("artifact/snippet-html"),
		TEXT("artifact/camera-export-json"),
		TEXT("artifact/capture-png")
	};
	EditorContract.SourceAttribution = MakeSpaceOperaAttribution(
		TEXT("compact-editor"),
		TEXT("Preserves the bounded editor and inspection shell from space-opera while keeping it subordinate to the main model-viewer lane.")
	);
	Bundle.EditorContracts = {EditorContract};

	Bundle.QaArtifacts =
	{
		MakeQaArtifact(
			TEXT("artifact/validator-report"),
			TEXT("Validator report"),
			TEXT("validation-report"),
			TEXT("Structured asset-validation report for conformance failures, extension warnings, and import blockers."),
			{TEXT("validation"), TEXT("failure-reporting"), TEXT("statistics")},
			MakeKhronosViewerAttribution(
				TEXT("qa-validation"),
				TEXT("Preserves the viewer-side validator and report boundary from the retained glTF-Sample-Viewer lane.")
			)
		),
		MakeQaArtifact(
			TEXT("artifact/statistics-snapshot"),
			TEXT("Statistics snapshot"),
			TEXT("statistics"),
			TEXT("Scene, animation, material, and feature-count summary for compact standards-aware QA review."),
			{TEXT("statistics"), TEXT("inspection"), TEXT("asset-profile")},
			MakeKhronosViewerAttribution(
				TEXT("qa-statistics"),
				TEXT("Preserves bounded statistics and scene-profile reporting from the retained glTF-Sample-Viewer lane.")
			)
		),
		MakeQaArtifact(
			TEXT("artifact/capture-png"),
			TEXT("Capture PNG"),
			TEXT("image-capture"),
			TEXT("Rendered capture artifact for compact preview, poster generation, and renderer comparison."),
			{TEXT("capture"), TEXT("poster"), TEXT("regression")},
			MakeKhronosViewerAttribution(
				TEXT("qa-capture"),
				TEXT("Preserves bounded screenshot and capture behavior from the retained glTF-Sample-Viewer lane.")
			)
		),
		MakeQaArtifact(
			TEXT("artifact/golden-analysis-json"),
			TEXT("Golden analysis JSON"),
			TEXT("fidelity-analysis"),
			TEXT("Golden-result comparison and delta artifact for renderer-regression checks."),
			{TEXT("fidelity"), TEXT("delta"), TEXT("comparison")},
			MakeRenderFidelityAttribution(
				TEXT("qa-fidelity"),
				TEXT("Preserves bounded golden-image, delta, and threshold comparison semantics from render-fidelity-tools.")
			)
		),
		MakeQaArtifact(
			TEXT("artifact/camera-export-json"),
			TEXT("Camera export JSON"),
			TEXT("camera-export"),
			TEXT("Camera state export artifact for reproducible preview framing and comparison passes."),
			{TEXT("camera"), TEXT("export"), TEXT("reproducibility")},
			MakeKhronosViewerAttribution(
				TEXT("qa-camera-export"),
				TEXT("Preserves bounded camera export and reproducible framing posture from the retained glTF-Sample-Viewer lane.")
			)
		),
		MakeQaArtifact(
			TEXT("artifact/snippet-html"),
			TEXT("Snippet HTML"),
			TEXT("snippet-export"),
			TEXT("Portable viewer embed snippet for compact first-party browser support surfaces."),
			{TEXT("snippet"), TEXT("embed"), TEXT("support-plane")},
			MakeModelViewerDevAttribution(
				TEXT("docs-demo-boundary"),
				TEXT("Preserves single-source snippet and runnable-example semantics from modelviewer.dev while keeping docs/demo framing outside the shippable lane.")
			)
		)
	};

	FHyperTwistTrainingViewerQaCheck ValidationCheck;
	ValidationCheck.CheckId = TEXT("asset-validation-and-statistics");
	ValidationCheck.Title = TEXT("Asset validation and statistics");
	ValidationCheck.Summary = TEXT("Standards-aware validation gate for structural conformance, extension compatibility, and scene statistics before a viewer surface is promoted.");
	ValidationCheck.RequiredArtifactIds =
	{
		TEXT("artifact/validator-report"),
		TEXT("artifact/statistics-snapshot"),
		TEXT("artifact/camera-export-json")
	};
	ValidationCheck.MetricLabels =
	{
		TEXT("validation-status"),
		TEXT("scene-count"),
		TEXT("animation-count"),
		TEXT("material-variant-count"),
		TEXT("camera-export-ready")
	};
	ValidationCheck.FailureSignals =
	{
		TEXT("validator-errors-present"),
		TEXT("unsupported-extension-surface"),
		TEXT("camera-export-missing"),
		TEXT("statistics-unavailable")
	};
	ValidationCheck.SourceAttribution = MakeKhronosViewerAttribution(
		TEXT("qa-validation"),
		TEXT("Preserves bounded validation, statistics, and failure-reporting expectations from the retained glTF-Sample-Viewer lane.")
	);

	FHyperTwistTrainingViewerQaCheck FidelityCheck;
	FidelityCheck.CheckId = TEXT("renderer-comparison-and-fidelity");
	FidelityCheck.Title = TEXT("Renderer comparison and fidelity");
	FidelityCheck.Summary = TEXT("Regression and comparison gate that pairs captured renders with golden and delta analysis before first-party browser viewer changes ship.");
	FidelityCheck.RequiredArtifactIds =
	{
		TEXT("artifact/capture-png"),
		TEXT("artifact/golden-analysis-json"),
		TEXT("artifact/validator-report")
	};
	FidelityCheck.MetricLabels =
	{
		TEXT("golden-threshold"),
		TEXT("delta-score"),
		TEXT("renderer-parity"),
		TEXT("capture-complete")
	};
	FidelityCheck.FailureSignals =
	{
		TEXT("delta-threshold-exceeded"),
		TEXT("capture-missing"),
		TEXT("renderer-mismatch"),
		TEXT("analysis-json-missing")
	};
	FidelityCheck.SourceAttribution = MakeRenderFidelityAttribution(
		TEXT("qa-fidelity"),
		TEXT("Preserves bounded golden-image and renderer-harness comparison discipline from render-fidelity-tools.")
	);

	FHyperTwistTrainingViewerQaCheck EmbedReadinessCheck;
	EmbedReadinessCheck.CheckId = TEXT("viewer-embed-readiness");
	EmbedReadinessCheck.Title = TEXT("Viewer embed readiness");
	EmbedReadinessCheck.Summary = TEXT("Compact support-plane embed gate covering snippet export, hotspot coverage, and capture-ready preview state.");
	EmbedReadinessCheck.RequiredArtifactIds =
	{
		TEXT("artifact/snippet-html"),
		TEXT("artifact/capture-png"),
		TEXT("artifact/camera-export-json")
	};
	EmbedReadinessCheck.MetricLabels =
	{
		TEXT("snippet-export-ready"),
		TEXT("hotspot-coverage"),
		TEXT("preview-framing-ready"),
		TEXT("capture-ready")
	};
	EmbedReadinessCheck.FailureSignals =
	{
		TEXT("snippet-export-missing"),
		TEXT("hotspot-surface-missing"),
		TEXT("preview-framing-unstable"),
		TEXT("capture-artifact-missing")
	};
	EmbedReadinessCheck.SourceAttribution = MakeSpaceOperaAttribution(
		TEXT("viewer-embed-readiness"),
		TEXT("Preserves bounded snippet, hotspot, and preview-state readiness expectations from the retained space-opera lane.")
	);
	Bundle.QaChecks = {ValidationCheck, FidelityCheck, EmbedReadinessCheck};

	FHyperTwistTrainingViewerRendererComparison Comparison;
	Comparison.ComparisonId = TEXT("renderer-comparison/modelviewer-vs-khronos-reference");
	Comparison.Title = TEXT("Model viewer vs Khronos reference comparison");
	Comparison.Summary = TEXT("First-party renderer-comparison surface pairing the shippable model-viewer embed with the retained Khronos standards viewer and renderer substrate.");
	Comparison.CandidateRendererLabel = TEXT("google/model-viewer");
	Comparison.ReferenceRendererLabel = TEXT("KhronosGroup/glTF-Sample-Viewer + glTF-Sample-Renderer");
	Comparison.ArtifactIds =
	{
		TEXT("artifact/capture-png"),
		TEXT("artifact/golden-analysis-json"),
		TEXT("artifact/validator-report"),
		TEXT("artifact/camera-export-json")
	};
	Comparison.ComparisonDimensions =
	{
		TEXT("tone-mapping"),
		TEXT("material-extension-coverage"),
		TEXT("environment-lighting"),
		TEXT("camera-framing"),
		TEXT("variant-and-animation-readiness")
	};
	Comparison.SourceAttribution = MakeKhronosRendererAttribution(
		TEXT("renderer-comparison"),
		TEXT("Preserves the lower-level reference-renderer role for standards-aware comparison beneath the shippable model-viewer lane.")
	);
	Bundle.RendererComparisons = {Comparison};

	FHyperTwistTrainingViewerDocumentationBoundary Boundary;
	Boundary.BoundaryId = TEXT("docs-demo-separation");
	Boundary.Title = TEXT("Docs/demo separation boundary");
	Boundary.Summary = TEXT("Separates shippable first-party browser viewer behavior from donor docs/demo-only shells, navigation, and example framing.");
	Boundary.DemoOnlyBehaviors =
	{
		TEXT("docs navigation chrome"),
		TEXT("runnable example-site scaffolding"),
		TEXT("open-mobile-view demo shell"),
		TEXT("donor docs prose and tutorial framing")
	};
	Boundary.ShippableBehaviors =
	{
		TEXT("embedded viewer widget"),
		TEXT("compact editor and inspection panel"),
		TEXT("hotspot authoring"),
		TEXT("asset QA capture and validation"),
		TEXT("snippet export for first-party support surfaces")
	};
	Boundary.RewriteRequiredElements =
	{
		TEXT("all donor docs/demo copy"),
		TEXT("all donor site-navigation framing"),
		TEXT("all donor example-shell assumptions")
	};
	Boundary.SourceAttribution = MakeModelViewerDevAttribution(
		TEXT("docs-demo-boundary"),
		TEXT("Preserves snippet-to-demo infrastructure insights from modelviewer.dev while keeping docs/demo framing explicitly outside the shippable viewer lane.")
	);
	Bundle.DocumentationBoundaries = {Boundary};

	return Bundle;
}

bool UHyperTwistTrainingViewerLibrary::TryGetEmbedContractById(
	const FHyperTwistTrainingViewerReferenceBundle& Bundle,
	const FString& ContractId,
	FHyperTwistTrainingViewerEmbedContract& OutContract
)
{
	for (const FHyperTwistTrainingViewerEmbedContract& Contract : Bundle.EmbedContracts)
	{
		if (Contract.ContractId.Equals(ContractId, ESearchCase::IgnoreCase))
		{
			OutContract = Contract;
			return true;
		}
	}

	OutContract = FHyperTwistTrainingViewerEmbedContract();
	return false;
}

bool UHyperTwistTrainingViewerLibrary::TryGetQaCheckById(
	const FHyperTwistTrainingViewerReferenceBundle& Bundle,
	const FString& CheckId,
	FHyperTwistTrainingViewerQaCheck& OutCheck
)
{
	for (const FHyperTwistTrainingViewerQaCheck& Check : Bundle.QaChecks)
	{
		if (Check.CheckId.Equals(CheckId, ESearchCase::IgnoreCase))
		{
			OutCheck = Check;
			return true;
		}
	}

	OutCheck = FHyperTwistTrainingViewerQaCheck();
	return false;
}

bool UHyperTwistTrainingViewerLibrary::TryGetDocumentationBoundaryById(
	const FHyperTwistTrainingViewerReferenceBundle& Bundle,
	const FString& BoundaryId,
	FHyperTwistTrainingViewerDocumentationBoundary& OutBoundary
)
{
	for (const FHyperTwistTrainingViewerDocumentationBoundary& Boundary : Bundle.DocumentationBoundaries)
	{
		if (Boundary.BoundaryId.Equals(BoundaryId, ESearchCase::IgnoreCase))
		{
			OutBoundary = Boundary;
			return true;
		}
	}

	OutBoundary = FHyperTwistTrainingViewerDocumentationBoundary();
	return false;
}

FString UHyperTwistTrainingViewerLibrary::BuildQaChecklistTsv(const FHyperTwistTrainingViewerReferenceBundle& Bundle)
{
	using namespace HyperTwistTrainingViewerLibraryInternal;

	FString Output = TEXT("CheckId\tTitle\tArtifacts\tMetrics\tFailureSignals\tSourceRepo\n");
	for (const FHyperTwistTrainingViewerQaCheck& Check : Bundle.QaChecks)
	{
		FString ArtifactIds;
		AppendJoined(ArtifactIds, Check.RequiredArtifactIds);

		FString MetricLabels;
		AppendJoined(MetricLabels, Check.MetricLabels);

		FString FailureSignals;
		AppendJoined(FailureSignals, Check.FailureSignals);

		Output.Appendf(
			TEXT("%s\t%s\t%s\t%s\t%s\t%s\n"),
			*Check.CheckId,
			*Check.Title,
			*ArtifactIds,
			*MetricLabels,
			*FailureSignals,
			*Check.SourceAttribution.SourceRepo
		);
	}

	return Output;
}
