using LehrerApp.Core.Models; namespace LehrerApp.Core.Services; /// Welcher der drei Leistungsbereiche (siehe GradingScheme) bei der Zielnoten-Frage der /// gesuchte/unbekannte ist. public enum GradeBucketKind { Exams, Participation, Other } public readonly record struct TargetGradeResult(double RequiredAverage, bool IsAchievable); /// /// Beantwortet die Zielnoten-Frage "Was brauche ich noch, um Zeugnisnote X zu erreichen?" /// (Nutzer-Feedback) — kehrt um: löst nach /// dem Durchschnitt eines gewählten Bereichs auf, der zusammen mit den bekannten Durchschnitten /// der übrigen Bereiche (gewichtet nach ) genau die Zielnote ergibt. /// Bereiche ohne bekannten Durchschnitt (z.B. noch keine Mitarbeitsnote im Halbjahr) fließen /// nicht in die bekannte Seite der Gleichung ein — exakt dieselbe Normierung wie /// bei fehlenden Bereichen. /// public static class ReportGradeTargetCalculator { public static TargetGradeResult? SolveRequiredAverage(double target, GradeBucketKind solveFor, double? examsAverage, double? participationAverage, double? otherAverage, GradingScheme scheme, GradingSystem system) { var solvePercent = solveFor switch { GradeBucketKind.Exams => scheme.ExamsPercent, GradeBucketKind.Participation => scheme.ParticipationPercent, _ => scheme.OtherPercent, }; // Dieser Bereich fließt laut Gewichtungsschema gar nicht in die Zeugnisnote ein — // keine Zielnoten-Frage für ihn beantwortbar. if (solvePercent <= 0) return null; var known = new List<(double Avg, double Percent)>(); if (solveFor != GradeBucketKind.Exams && examsAverage is { } e) known.Add((e, scheme.ExamsPercent)); if (solveFor != GradeBucketKind.Participation && participationAverage is { } p) known.Add((p, scheme.ParticipationPercent)); if (solveFor != GradeBucketKind.Other && otherAverage is { } o) known.Add((o, scheme.OtherPercent)); var totalPercent = known.Sum(k => k.Percent) + solvePercent; var knownContribution = known.Sum(k => k.Avg * k.Percent); var required = (target * totalPercent - knownContribution) / solvePercent; var (min, max) = system == GradingSystem.Grades1To6 ? (1.0, 6.0) : (0.0, 15.0); return new TargetGradeResult(required, required >= min && required <= max); } }