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