using GmRelay.Shared.Domain; namespace GmRelay.Web.Services; public enum BatchCloneInterval { NextWeek, NextMonth } public sealed record WebSessionBatch( Guid Id, Guid GroupId, string Title, string JoinLink, DateTime FirstScheduledAt, DateTime LastScheduledAt, int SessionCount, string NotificationMode = SessionNotificationModeExtensions.GroupAndDirectValue); public sealed record WebCampaignTemplate( Guid Id, Guid GroupId, string Name, string Title, string JoinLink, int SessionCount, int IntervalDays, int? MaxPlayers, string NotificationMode, DateTime CreatedAt, DateTime UpdatedAt); public sealed record CreateCampaignTemplateRequest( string Name, string Title, string JoinLink, int SessionCount, int IntervalDays, int? MaxPlayers, SessionNotificationMode NotificationMode); public static class BatchSchedulePlanner { private const int MaxTemplateSessionCount = 52; private const int MaxTemplateIntervalDays = 365; public static IReadOnlyList BuildFixedIntervalSchedule( IEnumerable currentSchedule, DateTime firstScheduledAt, int intervalDays) { if (intervalDays <= 0) { throw new ArgumentOutOfRangeException(nameof(intervalDays), intervalDays, "Interval must be greater than zero."); } return currentSchedule .OrderBy(scheduledAt => scheduledAt) .Select((_, index) => firstScheduledAt.AddDays(intervalDays * index)) .ToList(); } public static IReadOnlyList BuildRecurringSchedule( DateTime firstScheduledAt, int sessionCount, int intervalDays) { if (sessionCount is < 1 or > MaxTemplateSessionCount) { throw new ArgumentOutOfRangeException(nameof(sessionCount), sessionCount, "Session count must be between 1 and 52."); } if (intervalDays is < 1 or > MaxTemplateIntervalDays) { throw new ArgumentOutOfRangeException(nameof(intervalDays), intervalDays, "Interval must be between 1 and 365 days."); } return Enumerable.Range(0, sessionCount) .Select(index => firstScheduledAt.AddDays(intervalDays * index)) .ToList(); } public static DateTime ShiftForClone(DateTime scheduledAt, BatchCloneInterval interval) => interval switch { BatchCloneInterval.NextWeek => scheduledAt.AddDays(7), BatchCloneInterval.NextMonth => scheduledAt.AddMonths(1), _ => throw new ArgumentOutOfRangeException(nameof(interval), interval, "Unknown clone interval.") }; }