#include "HyperTwistTraining/HyperTwistTrainingSharedAssetLibrary.h"

namespace HyperTwistTrainingSharedAssetLibraryInternal
{
	const TCHAR* SharedAssetsRepo = TEXT("google/model-viewer/packages/shared-assets");
	const TCHAR* SharedAssetsLicense = TEXT("Apache-2.0 container; mixed per-asset terms");

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

	FHyperTwistTrainingSharedAssetFixtureReference MakeFixtureReference(
		const FString& FixtureId,
		const FString& Label,
		const TArray<FString>& RelativePaths,
		const FString& FixtureKind,
		const FString& UsagePosture,
		const FString& LicensePosture,
		const FString& Summary,
		const TArray<FString>& ApprovedWorkflowTags,
		const TArray<FString>& RequiredNoticeActions,
		const TArray<FString>& ExplicitExclusions,
		const FHyperTwistTrainingSourceAttribution& SourceAttribution
	)
	{
		FHyperTwistTrainingSharedAssetFixtureReference Reference;
		Reference.FixtureId = FixtureId;
		Reference.Label = Label;
		Reference.RelativePaths = RelativePaths;
		Reference.FixtureKind = FixtureKind;
		Reference.UsagePosture = UsagePosture;
		Reference.LicensePosture = LicensePosture;
		Reference.Summary = Summary;
		Reference.ApprovedWorkflowTags = ApprovedWorkflowTags;
		Reference.RequiredNoticeActions = RequiredNoticeActions;
		Reference.ExplicitExclusions = ExplicitExclusions;
		Reference.SourceAttribution = SourceAttribution;
		return Reference;
	}

	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]);
		}
	}
}

FHyperTwistTrainingSharedAssetReferenceBundle
UHyperTwistTrainingSharedAssetLibrary::BuildBundledSharedAssetReferenceBundle()
{
	using namespace HyperTwistTrainingSharedAssetLibraryInternal;

	FHyperTwistTrainingSharedAssetReferenceBundle Bundle;
	Bundle.ReferenceUtc = TEXT("2026-05-13T23:59:00Z");
	Bundle.PrimaryQaPackContractId = TEXT("shared-assets-fixture-allowlist");
	Bundle.PrimaryProvenanceBoundaryId = TEXT("shared-assets-provenance-and-shipping-boundary");
	Bundle.PrimaryRefreshPatternId = TEXT("shared-assets-refresh-and-attribution-recheck");

	const TArray<FString> CommonPackageNoticeActions =
	{
		TEXT("preserve package-level Apache license materials in third-party notices or equivalent release/legal materials"),
		TEXT("retain the fixture-level provenance record from ATTRIBUTIONS.md for every selected asset family"),
		TEXT("recheck the mirrored ATTRIBUTIONS.md entry before promoting any new asset into a shipped surface")
	};

	Bundle.FixtureReferences =
	{
		MakeFixtureReference(
			TEXT("fixture/robotexpressive-cc0"),
			TEXT("RobotExpressive character fixture"),
			{TEXT("./RobotExpressive.glb")},
			TEXT("character-model"),
			TEXT("ship-eligible-qa-fixture"),
			TEXT("CC0"),
			TEXT("Character and animation regression fixture for viewer smoke tests, camera framing, and expressive narration-side preview surfaces."),
			{TEXT("viewer-smoke-test"), TEXT("animation-preview"), TEXT("capture-regression")},
			CommonPackageNoticeActions,
			{
				TEXT("blanket adoption of the full shared-assets pack"),
				TEXT("treating this fixture as the product's owned avatar program")
			},
			MakeAttribution(
				TEXT("shared-assets/robotexpressive"),
				TEXT("Preserves the CC0 RobotExpressive sample as an explicit ship-eligible QA and preview fixture without promoting the mixed shared-assets pack into a blanket asset source.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/barramundi-fish-cc0"),
			TEXT("Barramundi Fish material-response fixture"),
			{TEXT("./BarramundiFish.mixed.glb")},
			TEXT("material-model"),
			TEXT("ship-eligible-qa-fixture"),
			TEXT("CC0"),
			TEXT("Material-response and lighting-parity fixture for browser viewer capture, highlight, and shading regressions."),
			{TEXT("material-response"), TEXT("lighting-parity"), TEXT("capture-regression")},
			CommonPackageNoticeActions,
			{
				TEXT("blanket product-asset shipping beyond the explicitly reviewed fixture role")
			},
			MakeAttribution(
				TEXT("shared-assets/barramundi-fish"),
				TEXT("Preserves the CC0 Barramundi Fish sample as an explicit material and lighting QA fixture beneath the bounded shared-assets lane.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/aircraft-workshop-cc0"),
			TEXT("Aircraft workshop lighting fixture"),
			{TEXT("./aircraft_workshop_01_1k.hdr")},
			TEXT("environment-map"),
			TEXT("ship-eligible-qa-fixture"),
			TEXT("CC0"),
			TEXT("High-contrast HDR lighting fixture for environment-reflection, tone-mapping, and exposure-parity checks."),
			{TEXT("lighting-parity"), TEXT("reflection-check"), TEXT("tone-mapping")},
			CommonPackageNoticeActions,
			{
				TEXT("silent inheritance of the whole shared-assets environment library")
			},
			MakeAttribution(
				TEXT("shared-assets/aircraft-workshop"),
				TEXT("Preserves the CC0 aircraft workshop HDRI as an explicit environment-lighting fixture for first-party viewer QA and regression capture.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/music-hall-cc0"),
			TEXT("Music hall lighting fixture"),
			{TEXT("./music_hall_01_1k.hdr")},
			TEXT("environment-map"),
			TEXT("ship-eligible-qa-fixture"),
			TEXT("CC0"),
			TEXT("Interior HDR lighting fixture for soft reflections, tone-mapping, and exposure variation checks."),
			{TEXT("lighting-parity"), TEXT("reflection-check"), TEXT("exposure-variation")},
			CommonPackageNoticeActions,
			{
				TEXT("silent inheritance of the whole shared-assets environment library")
			},
			MakeAttribution(
				TEXT("shared-assets/music-hall"),
				TEXT("Preserves the CC0 music hall HDRI as an explicit environment-lighting fixture for first-party viewer QA.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/spruit-sunrise-cc0"),
			TEXT("Spruit sunrise lighting family"),
			{
				TEXT("./spruit_sunrise_1k_HDR.hdr"),
				TEXT("./spruit_sunrise_1k_LDR.jpg"),
				TEXT("./spruit_sunrise_1k_PURE_SKY.hdr")
			},
			TEXT("environment-family"),
			TEXT("ship-eligible-qa-fixture"),
			TEXT("CC0"),
			TEXT("Outdoor lighting fixture family for sky-only, HDR, and LDR parity comparisons across browser capture flows."),
			{TEXT("lighting-parity"), TEXT("skybox-parity"), TEXT("capture-regression")},
			CommonPackageNoticeActions,
			{
				TEXT("assuming all shared-assets environments are equally approved without review")
			},
			MakeAttribution(
				TEXT("shared-assets/spruit-sunrise"),
				TEXT("Preserves the CC0 spruit sunrise environment family as an explicit outdoor-lighting fixture matrix for first-party viewer QA.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/whipple-creek-cc0"),
			TEXT("Whipple Creek lighting family"),
			{
				TEXT("./whipple_creek_regional_park_04_1k.hdr"),
				TEXT("./whipple_creek_regional_park_04_1k.jpg")
			},
			TEXT("environment-family"),
			TEXT("ship-eligible-qa-fixture"),
			TEXT("CC0"),
			TEXT("Outdoor lighting fixture family for reflection, sky tint, and exposure-parity comparison under natural conditions."),
			{TEXT("lighting-parity"), TEXT("reflection-check"), TEXT("natural-lighting")},
			CommonPackageNoticeActions,
			{
				TEXT("assuming all shared-assets environments are equally approved without review")
			},
			MakeAttribution(
				TEXT("shared-assets/whipple-creek"),
				TEXT("Preserves the CC0 Whipple Creek environment family as an explicit natural-lighting fixture matrix for first-party browser QA.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/astronaut-cc-by"),
			TEXT("Astronaut character family"),
			{
				TEXT("./Astronaut.glb"),
				TEXT("./AstronautDRACO.glb"),
				TEXT("./Astronaut-Unlit.glb"),
				TEXT("./Astronaut.usdz")
			},
			TEXT("character-family"),
			TEXT("notice-bound-review-fixture"),
			TEXT("CC-BY"),
			TEXT("Character fixture family for viewer embedding, compression, and format-parity checks that requires explicit attribution review before any shipped use."),
			{TEXT("viewer-smoke-test"), TEXT("compression-parity"), TEXT("format-parity")},
			{
				TEXT("preserve visible CC-BY creator attribution in any shipped usage"),
				TEXT("retain the exact asset family reference from ATTRIBUTIONS.md in the asset ledger"),
				TEXT("preserve package-level Apache license materials in third-party notices or equivalent release/legal materials")
			},
			{
				TEXT("shipping without explicit attribution review"),
				TEXT("treating the package container license as overriding CC-BY obligations")
			},
			MakeAttribution(
				TEXT("shared-assets/astronaut"),
				TEXT("Preserves the Astronaut sample family as a bounded review-required fixture set for format and compression parity while keeping CC-BY obligations explicit.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/shishkebab-cc-by"),
			TEXT("Shishkebab food fixture"),
			{TEXT("./Shishkebab.glb"), TEXT("./Shishkebab.png")},
			TEXT("material-model"),
			TEXT("notice-bound-review-fixture"),
			TEXT("CC-BY"),
			TEXT("Material and texture fixture for food-surface shading checks that remains review-required before any shipped use."),
			{TEXT("material-response"), TEXT("texture-parity"), TEXT("capture-regression")},
			{
				TEXT("preserve visible CC-BY creator attribution in any shipped usage"),
				TEXT("retain the exact asset family reference from ATTRIBUTIONS.md in the asset ledger"),
				TEXT("preserve package-level Apache license materials in third-party notices or equivalent release/legal materials")
			},
			{
				TEXT("shipping without explicit attribution review")
			},
			MakeAttribution(
				TEXT("shared-assets/shishkebab"),
				TEXT("Preserves the Shishkebab sample family as a bounded material-response fixture while keeping CC-BY review duties explicit.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/neil-armstrong-smithsonian"),
			TEXT("Neil Armstrong spacesuit fixture"),
			{TEXT("./NeilArmstrong.glb")},
			TEXT("historical-model"),
			TEXT("review-required-fixture"),
			TEXT("Smithsonian usage conditions"),
			TEXT("Historically distinctive model fixture for local viewer QA and documentation-example evaluation only until Smithsonian terms are reviewed for the exact target use."),
			{TEXT("viewer-smoke-test"), TEXT("documentation-example-evaluation"), TEXT("local-qa")},
			{
				TEXT("review the Smithsonian usage conditions before any shipped or public-facing use"),
				TEXT("retain the source institution and asset title in the fixture ledger"),
				TEXT("preserve package-level Apache license materials in third-party notices or equivalent release/legal materials")
			},
			{
				TEXT("treating the asset as ship-approved by default"),
				TEXT("assuming Smithsonian terms behave like a generic permissive asset license")
			},
			MakeAttribution(
				TEXT("shared-assets/neil-armstrong"),
				TEXT("Preserves the Neil Armstrong sample as a bounded review-required historical-model fixture while keeping Smithsonian usage conditions explicit.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/horse-cc-by-nc-sa"),
			TEXT("Horse model fixture"),
			{TEXT("./Horse.glb")},
			TEXT("character-model"),
			TEXT("local-only-restricted-fixture"),
			TEXT("CC-BY-NC-SA"),
			TEXT("Local-only model fixture for internal shading and animation smoke tests that must not be treated as a commercial shippable product asset."),
			{TEXT("local-qa"), TEXT("material-response"), TEXT("animation-preview")},
			{
				TEXT("retain the exact CC-BY-NC-SA entry from ATTRIBUTIONS.md in the internal fixture ledger"),
				TEXT("preserve package-level Apache license materials in third-party notices or equivalent release/legal materials")
			},
			{
				TEXT("commercial shipping"),
				TEXT("public sample-asset promotion"),
				TEXT("treating noncommercial terms as a generic permissive allowance")
			},
			MakeAttribution(
				TEXT("shared-assets/horse"),
				TEXT("Preserves the Horse sample only as a local-only restricted fixture because the CC-BY-NC-SA posture is incompatible with a blanket shipped-product asset role.")
			)
		),
		MakeFixtureReference(
			TEXT("fixture/contributed-geometry-smoke-tests"),
			TEXT("Contributed geometry smoke-test family"),
			{
				TEXT("./cube.gltf"),
				TEXT("./offcenter-cube.gltf"),
				TEXT("./pbr-spheres.glb"),
				TEXT("./radiance.glb"),
				TEXT("./reflective-sphere.gltf"),
				TEXT("./Triangle.gltf"),
				TEXT("./odd-shape.glb"),
				TEXT("./odd-shape-labeled.glb")
			},
			TEXT("geometry-smoke-test-family"),
			TEXT("review-required-fixture"),
			TEXT("Contributor-noted in ATTRIBUTIONS.md; asset-specific shipping posture requires separate review"),
			TEXT("Small geometry and radiance fixtures for parsing, framing, and shader smoke tests that remain review-required until each contributed asset's shipping posture is explicitly resolved."),
			{TEXT("geometry-smoke-test"), TEXT("parsing-smoke-test"), TEXT("capture-regression")},
			{
				TEXT("retain the contributor references from ATTRIBUTIONS.md in the fixture ledger"),
				TEXT("do not assume the package container license resolves the per-asset shipping posture"),
				TEXT("preserve package-level Apache license materials in third-party notices or equivalent release/legal materials")
			},
			{
				TEXT("treating contributor-noted smoke-test assets as auto-approved shippable product assets")
			},
			MakeAttribution(
				TEXT("shared-assets/contributed-geometry"),
				TEXT("Preserves the contributed geometry smoke-test family as a bounded parsing and framing fixture set while keeping per-asset review duties explicit.")
			)
		)
	};

	FHyperTwistTrainingSharedAssetQaPackContract QaPackContract;
	QaPackContract.ContractId = TEXT("shared-assets-fixture-allowlist");
	QaPackContract.Title = TEXT("Shared-assets fixture allowlist");
	QaPackContract.Summary = TEXT("First-party HyperTwist allowlist contract for using google/model-viewer shared-assets as a bounded fixture, documentation-example, and visual-QA lane with explicit per-asset posture instead of blanket bundle shipping.");
	QaPackContract.RequiredFixtureIds =
	{
		TEXT("fixture/robotexpressive-cc0"),
		TEXT("fixture/barramundi-fish-cc0"),
		TEXT("fixture/aircraft-workshop-cc0"),
		TEXT("fixture/music-hall-cc0"),
		TEXT("fixture/spruit-sunrise-cc0"),
		TEXT("fixture/whipple-creek-cc0"),
		TEXT("fixture/astronaut-cc-by"),
		TEXT("fixture/shishkebab-cc-by"),
		TEXT("fixture/neil-armstrong-smithsonian"),
		TEXT("fixture/horse-cc-by-nc-sa"),
		TEXT("fixture/contributed-geometry-smoke-tests")
	};
	QaPackContract.ShipEligibleFixtureIds =
	{
		TEXT("fixture/robotexpressive-cc0"),
		TEXT("fixture/barramundi-fish-cc0"),
		TEXT("fixture/aircraft-workshop-cc0"),
		TEXT("fixture/music-hall-cc0"),
		TEXT("fixture/spruit-sunrise-cc0"),
		TEXT("fixture/whipple-creek-cc0")
	};
	QaPackContract.ReviewRequiredFixtureIds =
	{
		TEXT("fixture/astronaut-cc-by"),
		TEXT("fixture/shishkebab-cc-by"),
		TEXT("fixture/neil-armstrong-smithsonian"),
		TEXT("fixture/contributed-geometry-smoke-tests")
	};
	QaPackContract.LocalOnlyFixtureIds =
	{
		TEXT("fixture/horse-cc-by-nc-sa")
	};
	QaPackContract.ApprovedWorkflowTags =
	{
		TEXT("viewer-smoke-test"),
		TEXT("lighting-parity"),
		TEXT("capture-regression"),
		TEXT("documentation-example-evaluation"),
		TEXT("explicitly-reviewed-shipping")
	};
	QaPackContract.ExplicitExclusions =
	{
		TEXT("blanket shipping of the shared-assets package"),
		TEXT("treating all mixed-provenance assets as if the package container license were decisive"),
		TEXT("promoting the fixture pack into runtime or gameplay ownership")
	};
	QaPackContract.SourceAttribution = MakeAttribution(
		TEXT("shared-assets/allowlist-contract"),
		TEXT("Preserves explicit fixture allowlisting, review-required splits, and local-only exclusions from the shared-assets lane so HyperTwist can use the pack for QA without pretending it is a blanket shippable bundle.")
	);
	Bundle.QaPackContracts = {QaPackContract};

	FHyperTwistTrainingSharedAssetProvenanceBoundary ProvenanceBoundary;
	ProvenanceBoundary.BoundaryId = TEXT("shared-assets-provenance-and-shipping-boundary");
	ProvenanceBoundary.Title = TEXT("Shared-assets provenance and shipping boundary");
	ProvenanceBoundary.Summary = TEXT("First-party HyperTwist provenance boundary for using google/model-viewer shared-assets as a mixed-terms fixture pack with explicit CC0, attribution-bound, review-only, and excluded lanes.");
	ProvenanceBoundary.AllowedShippingFixtureIds =
	{
		TEXT("fixture/robotexpressive-cc0"),
		TEXT("fixture/barramundi-fish-cc0"),
		TEXT("fixture/aircraft-workshop-cc0"),
		TEXT("fixture/music-hall-cc0"),
		TEXT("fixture/spruit-sunrise-cc0"),
		TEXT("fixture/whipple-creek-cc0")
	};
	ProvenanceBoundary.NoticeBoundFixtureIds =
	{
		TEXT("fixture/astronaut-cc-by"),
		TEXT("fixture/shishkebab-cc-by")
	};
	ProvenanceBoundary.ReviewOnlyFixtureIds =
	{
		TEXT("fixture/neil-armstrong-smithsonian"),
		TEXT("fixture/contributed-geometry-smoke-tests")
	};
	ProvenanceBoundary.ExcludedFixtureIds =
	{
		TEXT("fixture/horse-cc-by-nc-sa")
	};
	ProvenanceBoundary.RequiredNoticeActions =
	{
		TEXT("preserve package-level Apache license materials in third-party notices or equivalent release/legal materials"),
		TEXT("retain the exact selected-asset entries from ATTRIBUTIONS.md in the fixture ledger"),
		TEXT("preserve visible creator attribution whenever a notice-bound asset is promoted into a shipped surface"),
		TEXT("document the reviewed shipping decision for each non-CC0 asset before use")
	};
	ProvenanceBoundary.ProvenanceCaveats =
	{
		TEXT("the package container license does not override per-asset terms in ATTRIBUTIONS.md"),
		TEXT("Smithsonian usage conditions require explicit review before public or shipped use"),
		TEXT("contributor-noted geometry smoke-test assets remain review-required until their shipping posture is resolved"),
		TEXT("CC-BY-NC-SA assets remain excluded from HyperTwist's normal commercial shipping lane")
	};
	ProvenanceBoundary.ExplicitExclusions =
	{
		TEXT("blanket product shipping of mixed-provenance assets"),
		TEXT("erasing attribution or contributor records from the fixture ledger"),
		TEXT("treating local-only restricted fixtures as general product assets")
	};
	ProvenanceBoundary.SourceAttribution = MakeAttribution(
		TEXT("shared-assets/provenance-boundary"),
		TEXT("Preserves the shared-assets per-asset provenance split so HyperTwist can use approved fixtures while keeping attribution-bound, review-only, and excluded assets explicit.")
	);
	Bundle.ProvenanceBoundaries = {ProvenanceBoundary};

	FHyperTwistTrainingSharedAssetRefreshPattern RefreshPattern;
	RefreshPattern.PatternId = TEXT("shared-assets-refresh-and-attribution-recheck");
	RefreshPattern.Title = TEXT("Shared-assets refresh and attribution recheck");
	RefreshPattern.Summary = TEXT("First-party HyperTwist refresh pattern for sample-fixture updates that keeps fetch-script behavior, provenance rechecks, and allowlist verification explicit.");
	RefreshPattern.ScriptPath = TEXT("./scripts/fetch-khronos-gltf-samples.sh");
	RefreshPattern.RefreshInputTags =
	{
		TEXT("khronos-sample-refresh"),
		TEXT("fixture-sync"),
		TEXT("environment-fixture-matrix"),
		TEXT("attribution-recheck")
	};
	RefreshPattern.VerificationSteps =
	{
		TEXT("re-read ATTRIBUTIONS.md before promoting any refreshed fixture"),
		TEXT("verify the selected fixture files still exist at the mirrored relative paths"),
		TEXT("reconfirm shipping-eligible, notice-bound, review-only, and excluded splits"),
		TEXT("update first-party fixture ledgers before expanding the shipping allowlist")
	};
	RefreshPattern.ExplicitExclusions =
	{
		TEXT("silent fixture refresh without provenance review"),
		TEXT("using the fetch script as permission to widen the shipping allowlist automatically")
	};
	RefreshPattern.SourceAttribution = MakeAttribution(
		TEXT("shared-assets/refresh-pattern"),
		TEXT("Preserves the fetch-script refresh pattern from shared-assets while keeping attribution rechecks and allowlist review mandatory for HyperTwist.")
	);
	Bundle.RefreshPatterns = {RefreshPattern};

	return Bundle;
}

bool UHyperTwistTrainingSharedAssetLibrary::TryGetFixtureReferenceById(
	const FHyperTwistTrainingSharedAssetReferenceBundle& Bundle,
	const FString& FixtureId,
	FHyperTwistTrainingSharedAssetFixtureReference& OutReference
)
{
	for (const FHyperTwistTrainingSharedAssetFixtureReference& Reference : Bundle.FixtureReferences)
	{
		if (Reference.FixtureId.Equals(FixtureId, ESearchCase::IgnoreCase))
		{
			OutReference = Reference;
			return true;
		}
	}

	OutReference = FHyperTwistTrainingSharedAssetFixtureReference();
	return false;
}

bool UHyperTwistTrainingSharedAssetLibrary::TryGetQaPackContractById(
	const FHyperTwistTrainingSharedAssetReferenceBundle& Bundle,
	const FString& ContractId,
	FHyperTwistTrainingSharedAssetQaPackContract& OutContract
)
{
	for (const FHyperTwistTrainingSharedAssetQaPackContract& Contract : Bundle.QaPackContracts)
	{
		if (Contract.ContractId.Equals(ContractId, ESearchCase::IgnoreCase))
		{
			OutContract = Contract;
			return true;
		}
	}

	OutContract = FHyperTwistTrainingSharedAssetQaPackContract();
	return false;
}

bool UHyperTwistTrainingSharedAssetLibrary::TryGetProvenanceBoundaryById(
	const FHyperTwistTrainingSharedAssetReferenceBundle& Bundle,
	const FString& BoundaryId,
	FHyperTwistTrainingSharedAssetProvenanceBoundary& OutBoundary
)
{
	for (const FHyperTwistTrainingSharedAssetProvenanceBoundary& Boundary : Bundle.ProvenanceBoundaries)
	{
		if (Boundary.BoundaryId.Equals(BoundaryId, ESearchCase::IgnoreCase))
		{
			OutBoundary = Boundary;
			return true;
		}
	}

	OutBoundary = FHyperTwistTrainingSharedAssetProvenanceBoundary();
	return false;
}

bool UHyperTwistTrainingSharedAssetLibrary::TryGetRefreshPatternById(
	const FHyperTwistTrainingSharedAssetReferenceBundle& Bundle,
	const FString& PatternId,
	FHyperTwistTrainingSharedAssetRefreshPattern& OutPattern
)
{
	for (const FHyperTwistTrainingSharedAssetRefreshPattern& Pattern : Bundle.RefreshPatterns)
	{
		if (Pattern.PatternId.Equals(PatternId, ESearchCase::IgnoreCase))
		{
			OutPattern = Pattern;
			return true;
		}
	}

	OutPattern = FHyperTwistTrainingSharedAssetRefreshPattern();
	return false;
}

FString UHyperTwistTrainingSharedAssetLibrary::BuildFixtureChecklistTsv(
	const FHyperTwistTrainingSharedAssetReferenceBundle& Bundle
)
{
	using namespace HyperTwistTrainingSharedAssetLibraryInternal;

	FString Output = TEXT("fixture_id\tlabel\tfixture_kind\tusage_posture\tlicense_posture\trelative_paths\tsummary\n");
	for (const FHyperTwistTrainingSharedAssetFixtureReference& Reference : Bundle.FixtureReferences)
	{
		if (!Reference.IsStructurallyValid())
		{
			continue;
		}

		FString RelativePaths;
		AppendJoined(RelativePaths, Reference.RelativePaths);

		Output.Append(Reference.FixtureId);
		Output.Append(TEXT("\t"));
		Output.Append(Reference.Label);
		Output.Append(TEXT("\t"));
		Output.Append(Reference.FixtureKind);
		Output.Append(TEXT("\t"));
		Output.Append(Reference.UsagePosture);
		Output.Append(TEXT("\t"));
		Output.Append(Reference.LicensePosture);
		Output.Append(TEXT("\t"));
		Output.Append(RelativePaths);
		Output.Append(TEXT("\t"));
		Output.Append(Reference.Summary.Replace(TEXT("\t"), TEXT(" ")));
		Output.Append(TEXT("\n"));
	}

	return Output;
}
