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<DateTime> BuildFixedIntervalSchedule(
        IEnumerable<DateTime> 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<DateTime> 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.")
        };
}
