using System.Text.Json; namespace Server.WatchBody.Core.Programs; /// /// Пороги правил прогрессии/делоада/перерывов (секция Progression); /// умолчания — requirements разд. 3 и Ф-14.1. 🛡 В расчётном коде /// пороги не хардкодятся — только эти значения (Р3-А). /// public class ProgressionConfig { public decimal BaseStepKg { get; set; } = 2.5m; public decimal IsoStepKg { get; set; } = 1.0m; public int BackoffPercent { get; set; } = 5; public int DeloadMaxWeeks { get; set; } = 6; public int MissDaysForBreak { get; set; } = 4; public decimal ReturnMinFactor { get; set; } = 0.6m; public decimal ReturnMaxFactor { get; set; } = 0.9m; /// Чтение секции Progression (отсутствует/частичная — умолчания). public static ProgressionConfig Load(JsonElement root) { var config = new ProgressionConfig(); if (!root.TryGetProperty("Progression", out var section) || section.ValueKind != JsonValueKind.Object) return config; foreach (var property in typeof(ProgressionConfig).GetProperties()) { var name = char.ToLowerInvariant(property.Name[0]) + property.Name[1..]; if (!section.TryGetProperty(name, out var value)) continue; if (value.ValueKind != JsonValueKind.Number || !value.TryGetDecimal(out var number)) throw new InvalidOperationException($"Progression.{name}: ожидалось число"); property.SetValue(config, Convert.ChangeType(number, property.PropertyType)); } return config; } /// Ошибки конфигурации (фатальны при старте). public List Validate() { var errors = new List(); // IsoStepKg — коридор метрик «+0,5–1 кг» (О-3-А): 0.25–5 if (IsoStepKg < 0.25m || IsoStepKg > 5m) errors.Add("Progression: isoStepKg вне [0.25; 5]"); if (BaseStepKg < 0.5m || BaseStepKg > 10m) errors.Add("Progression: baseStepKg вне [0.5; 10]"); if (BackoffPercent < 1 || BackoffPercent > 20) errors.Add("Progression: backoffPercent вне [1; 20]"); if (DeloadMaxWeeks < 3 || DeloadMaxWeeks > 12) errors.Add("Progression: deloadMaxWeeks вне [3; 12]"); if (MissDaysForBreak < 2) errors.Add("Progression: missDaysForBreak < 2"); if (ReturnMinFactor < 0.3m || ReturnMinFactor > 0.9m) errors.Add("Progression: returnMinFactor вне [0.3; 0.9]"); if (ReturnMaxFactor <= 0.5m || ReturnMaxFactor > 1m) errors.Add("Progression: returnMaxFactor вне (0.5; 1]"); if (ReturnMinFactor > ReturnMaxFactor) errors.Add("Progression: returnMinFactor > returnMaxFactor"); return errors; } }