namespace KArtSell.Modules.ModelOperations.Domain; public sealed class ScheduleOccurrencePlanner { public DateTimeOffset GetNextDueAt( DateTimeOffset scheduledFor, string cadence, string catchUpPolicy, int maxCatchUp, DateTimeOffset now) { if (maxCatchUp is < 0 or > 31) throw new ArgumentOutOfRangeException(nameof(maxCatchUp)); var next = Advance(scheduledFor, cadence); if (catchUpPolicy.Equals("ALL_WITH_LIMIT", StringComparison.OrdinalIgnoreCase)) return next; if (!catchUpPolicy.Equals("LATEST_ONLY", StringComparison.OrdinalIgnoreCase) && !catchUpPolicy.Equals("SKIP_MISSED", StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException($"Unsupported catch-up policy '{catchUpPolicy}'."); var guard = 0; while (next <= now) { next = Advance(next, cadence); if (++guard > 5000) throw new InvalidOperationException("Schedule catch-up exceeded safety guard."); } return next; } private static DateTimeOffset Advance(DateTimeOffset value, string cadence) => cadence.ToUpperInvariant() switch { "DAILY" => value.AddDays(1), "WEEKLY" => value.AddDays(7), "MONTHLY" => value.AddMonths(1), "QUARTERLY" => value.AddMonths(3), "EVENT_DRIVEN" => value.AddYears(100), _ => throw new InvalidOperationException($"Unsupported cadence '{cadence}'.") }; }