using QuestionsApi.Models; using System.Text.Json; namespace QuestionsApi.Services; public static class DynamicBlueprintResolver { private static readonly JsonSerializerOptions Json = new(JsonSerializerDefaults.Web); public static List ResolveAll(IEnumerable source) { var all = source.ToList(); var resolved = new List(); foreach (var blueprint in all.OrderBy(value => value.Version)) { if (blueprint.BaseBlueprintVersion <= 0) { resolved.Add(blueprint); continue; } var baseBlueprint = resolved.FirstOrDefault(value => value.ExternalId == blueprint.ExternalId && value.Version == blueprint.BaseBlueprintVersion) ?? throw new InvalidDataException( $"{blueprint.ExternalId} v{blueprint.Version} base version {blueprint.BaseBlueprintVersion} not found"); var materialized = Clone(baseBlueprint); materialized.Id = null; materialized.Version = blueprint.Version; materialized.BaseBlueprintVersion = blueprint.BaseBlueprintVersion; materialized.QualityStandardVersion = blueprint.QualityStandardVersion; materialized.IsPublished = blueprint.IsPublished; materialized.EncounterFrame = blueprint.EncounterFrame; materialized.SiteOfCare = blueprint.SiteOfCare; materialized.BlueprintWeight = blueprint.BlueprintWeight; materialized.ConceptIds = blueprint.ConceptIds; materialized.PrerequisiteConceptIds = blueprint.PrerequisiteConceptIds; materialized.MedicallyReviewedUtc = blueprint.MedicallyReviewedUtc; materialized.MedicalReviewExpiresUtc = blueprint.MedicalReviewExpiresUtc; materialized.MedicalReviewer = blueprint.MedicalReviewer; if (blueprint.Distractors.Count > 0) materialized.Distractors = blueprint.Distractors; if (blueprint.CaseFamilies.Count > 0) materialized.CaseFamilies = blueprint.CaseFamilies.Select(overlay => { var baseFamily = baseBlueprint.CaseFamilies.FirstOrDefault(value => value.Id == overlay.BaseFamilyId) ?? throw new InvalidDataException( $"{blueprint.ExternalId} v{blueprint.Version} base family {overlay.BaseFamilyId} not found"); var family = Clone(baseFamily); family.Id = overlay.Id; family.BaseFamilyId = overlay.BaseFamilyId; family.DifficultyTier = overlay.DifficultyTier; family.NominalElo = overlay.NominalElo; if (!string.IsNullOrWhiteSpace(family.LeadIn) && family.StemTemplate.EndsWith(family.LeadIn, StringComparison.Ordinal)) family.StemTemplate = family.StemTemplate[..^family.LeadIn.Length].TrimEnd(); if (!string.IsNullOrWhiteSpace(overlay.StemTemplate)) family.StemTemplate = $"{family.StemTemplate} {overlay.StemTemplate}".Trim(); if (!string.IsNullOrWhiteSpace(overlay.LeadIn)) family.LeadIn = overlay.LeadIn; if (overlay.Distractors.Count > 0) family.Distractors = overlay.Distractors; return family; }).ToList(); resolved.Add(materialized); } return resolved; } private static T Clone(T value) => JsonSerializer.Deserialize(JsonSerializer.Serialize(value, Json), Json) ?? throw new InvalidOperationException("Blueprint clone failed."); }