using Backend.Contracts; using Backend.Common; using Backend.Data; using Backend.Domain; using Backend.Services; using Microsoft.EntityFrameworkCore; namespace Backend.Endpoints; public static partial class AdminSeasonManagementEndpoints { private static async Task CreateSeason( HttpContext context, CreateSeasonRequest request, AwardsDbContext db, IAdminAuditService adminAuditService) { var session = AdminEndpointConventions.CurrentSession(context); var validationError = ValidateSeasonRequest(request); if (validationError is not null) { return validationError; } if (await db.Seasons.AnyAsync(item => item.Year == request.Year)) { return Results.BadRequest(new { message = $"A season for {request.Year} already exists." }); } var showStreamUrl = NormalizeSeasonStreamUrl(request.ShowStreamUrl); var season = new Season { Year = request.Year, Name = request.Name.Trim(), ShowStreamUrl = showStreamUrl, CurrentPhase = request.CurrentPhase.Trim(), IsCurrent = request.IsCurrent, IsCommunityOnly = request.IsCommunityOnly, NominationStartsAt = request.NominationStartsAt, NominationEndsAt = request.NominationEndsAt, VotingStartsAt = request.VotingStartsAt, VotingEndsAt = request.VotingEndsAt, ReviewStartsAt = request.ReviewStartsAt, ReviewEndsAt = request.ReviewEndsAt, ShowDate = request.ShowDate, ShowStartsAt = request.ShowStartsAt, }; db.Seasons.Add(season); var copiedCategoryCount = 0; if (request.CopyStructureFromSeasonId is { } sourceSeasonId) { if (sourceSeasonId <= 0) { return Results.BadRequest(new { message = "A valid source season is required for copying structure." }); } var sourceSeasonExists = await db.Seasons .AsNoTracking() .AnyAsync(item => item.Id == sourceSeasonId, context.RequestAborted); if (!sourceSeasonExists) { return Results.BadRequest(new { message = "Source season for structure copy was not found." }); } var sourceCategories = await db.Categories .AsNoTracking() .Where(item => item.SeasonId == sourceSeasonId) .OrderBy(item => item.SortOrder) .ThenBy(item => item.Name) .ToArrayAsync(context.RequestAborted); copiedCategoryCount = sourceCategories.Length; foreach (var category in sourceCategories) { db.Categories.Add(new Category { Season = season, GroupName = category.GroupName, Name = category.Name, Slug = category.Slug, Description = category.Description, SortOrder = category.SortOrder, MaxNomineesPerUser = category.MaxNomineesPerUser, }); } } var readinessIssues = BuildNewSeasonReadinessIssues( request.CurrentPhase, request.IsCurrent, copiedCategoryCount); if (readinessIssues.Length > 0) { return CreateReadinessError(readinessIssues); } await UnsetOtherCurrentSeasonsAsync(db, request.IsCurrent, null, context.RequestAborted); adminAuditService.AddEntry( session.TwitchUserId, "season.create", "season", request.Year.ToString(), copiedCategoryCount > 0 ? $"Season {request.Year} wurde angelegt und {copiedCategoryCount} Kategorien wurden kopiert." : $"Season {request.Year} wurde angelegt.", new { request.IsCurrent, request.IsCommunityOnly, showStreamUrl, request.CurrentPhase, request.ShowDate, request.ShowStartsAt, request.CopyStructureFromSeasonId, copiedCategoryCount, }, RequestMetadataReader.Read(context)); await db.SaveChangesAsync(context.RequestAborted); return Results.Ok(new { saved = true, seasonId = season.Id, copiedCategoryCount }); } }