using System.Globalization; using LehrerApp.Core.Models; namespace LehrerApp.Core.Services; /// /// Zählt eigene Klausuren pro ISO-Kalenderwoche über alle Lerngruppen hinweg. Nutzer-Feedback: /// die klassenbezogene Kollisionsprüfung (mehrere Klausuren einer einzelnen Klasse in einer /// Woche) übernimmt bereits der schulische Klausurplaner (externes Klassenbuch) — was dort /// fehlt, ist die persönliche Belastung der Lehrkraft: mehr eigene Klausuren in derselben Woche /// bedeuten unabhängig von der Klasse mehr Erstellungsaufwand vorher und mehr Korrekturaufwand /// danach. Da eine LiteDB-Datei genau einem Nutzer gehört (siehe CLAUDE.md), sind "alle /// Klausuren in der Datenbank" bereits gleichbedeutend mit "meine Klausuren". /// public static class ExamWeekLoadService { /// Ab dieser Anzahl eigener Klausuren in derselben Woche gilt die Woche als spürbar belastet. /// Nutzer-Feedback: zwei Klausuren aus zwei unterrichteten Fächern in derselben Woche sind /// normal, eine dritte ist die eigentliche Häufung. public const int WarningThreshold = 3; /// Anzahl Klausuren (ohne , z.B. die gerade im Dialog /// bearbeitete), die in dieselbe ISO-Kalenderwoche wie fallen. public static int CountInSameWeek(IEnumerable allExams, DateOnly date, Guid? excludeExamId = null) { var (year, week) = IsoWeek(date); return allExams.Count(e => e.Id != excludeExamId && IsoWeek(e.Date) == (year, week)); } /// Gruppiert die übergebenen Klausuren nach ISO-Kalenderwoche und liefert nur die Wochen mit /// mindestens Klausuren, chronologisch sortiert — für einen /// vorausschauenden Überblick (z.B. Dashboard), nicht für die Einzelprüfung beim Anlegen. public static List FindOverloadedWeeks(IEnumerable exams) => exams .GroupBy(e => IsoWeek(e.Date)) .Where(g => g.Count() >= WarningThreshold) .Select(g => new ExamWeekLoad(g.Key.Year, g.Key.Week, WeekStart(g.Key.Year, g.Key.Week), g.Count())) .OrderBy(w => w.WeekStart) .ToList(); private static (int Year, int Week) IsoWeek(DateOnly date) { var dt = date.ToDateTime(TimeOnly.MinValue); return (ISOWeek.GetYear(dt), ISOWeek.GetWeekOfYear(dt)); } private static DateOnly WeekStart(int isoYear, int isoWeek) => DateOnly.FromDateTime(ISOWeek.ToDateTime(isoYear, isoWeek, DayOfWeek.Monday)); } public readonly record struct ExamWeekLoad(int IsoYear, int IsoWeek, DateOnly WeekStart, int ExamCount) { public DateOnly WeekEnd => WeekStart.AddDays(6); }