using AutoMapper; using GameIdeas.Shared.Dto; using GameIdeas.Shared.Exceptions; using GameIdeas.Shared.Model; using GameIdeas.WebAPI.Context; using Microsoft.EntityFrameworkCore; using System.Threading.Tasks; namespace GameIdeas.WebAPI.Services.Games; public class GameWriteService(GameIdeasContext context, IMapper mapper) : IGameWriteService { public async Task CreateGame(GameDetailDto gameDto) { var gameToCreate = mapper.Map(gameDto); await HandleDeveloperPublisherCreation(gameToCreate); await context.Games.AddAsync(gameToCreate); await context.SaveChangesAsync(); await HandlePlatformsCreation(gameDto.Platforms, gameToCreate.Id); await HandlePropertiesCreation(gameDto.Properties, gameToCreate.Id); await HandleTagsCreation(gameDto.Tags, gameToCreate.Id); await context.SaveChangesAsync(); return mapper.Map(gameToCreate); } public async Task UpdateGame(GameDetailDto gameDto) { if (await context.Games.CountAsync(g => g.Id == gameDto.Id) == 0) { throw new NotFoundException($"[{typeof(Game).FullName}] with ID {gameDto.Id} has not been found in context"); } var gameToUpdate = mapper.Map(gameDto); await HandleDeveloperPublisherCreation(gameToUpdate); await HandlePlatformsCreation(gameDto.Platforms, gameToUpdate.Id); await HandlePropertiesCreation(gameDto.Properties, gameToUpdate.Id); await HandleTagsCreation(gameDto.Tags, gameToUpdate.Id); context.Games.Update(gameToUpdate); await context.SaveChangesAsync(); return mapper.Map(gameToUpdate); } public async Task DeleteGame(int gameId) { await HandlePlatformsCreation([], gameId); await HandlePropertiesCreation([], gameId); await HandleTagsCreation([], gameId); var gameToRemove = await context.Games .FirstOrDefaultAsync(g => g.Id == gameId) ?? throw new NotFoundException($"[{typeof(Game).FullName}] with ID {gameId} has not been found in context"); context.Games.Remove(gameToRemove); await context.SaveChangesAsync(); context.Publishers.RemoveRange( context.Publishers.Include(p => p.Games) .Where(p => p.Games.Count == 0)); context.Developers.RemoveRange( context.Developers.Include(d => d.Games) .Where(d => d.Games.Count == 0)); await context.SaveChangesAsync(); return true; } private async Task HandlePlatformsCreation(IEnumerable? categoriesToCreate, int gameId) { if (categoriesToCreate != null) { var gps = mapper.Map>(categoriesToCreate); context.GamePlatforms.RemoveRange( context.GamePlatforms.Where(gp => gp.GameId == gameId)); foreach (var gp in gps) { gp.GameId = gameId; } context.Platforms.AttachRange(gps.Select(gp => gp.Platform)); await context.GamePlatforms.AddRangeAsync(gps); await context.SaveChangesAsync(); context.Platforms.RemoveRange( context.Platforms.Include(p => p.GamePlatforms) .Where(p => p.GamePlatforms.Count == 0)); await context.SaveChangesAsync(); } } private async Task HandlePropertiesCreation(IEnumerable? categoriesToCreate, int gameId) { if (categoriesToCreate != null) { var gps = mapper.Map>(categoriesToCreate); context.GameProperties.RemoveRange( context.GameProperties.Where(gp => gp.GameId == gameId)); foreach (var gp in gps) { gp.GameId = gameId; } context.Properties.AttachRange(gps.Select(gp => gp.Property)); await context.GameProperties.AddRangeAsync(gps); await context.SaveChangesAsync(); context.Properties.RemoveRange( context.Properties.Include(p => p.GameProperties) .Where(p => p.GameProperties.Count == 0)); await context.SaveChangesAsync(); } } private async Task HandleTagsCreation(IEnumerable? categoriesToCreate, int gameId) { if (categoriesToCreate != null) { var gts = mapper.Map>(categoriesToCreate); context.GameTags.RemoveRange( context.GameTags.Where(gt => gt.GameId == gameId)); foreach (var gt in gts) { gt.GameId = gameId; } context.Tags.AttachRange(gts.Select(gt => gt.Tag)); await context.GameTags.AddRangeAsync(gts); await context.SaveChangesAsync(); context.Tags.RemoveRange( context.Tags.Include(t => t.GameTags) .Where(t => t.GameTags.Count == 0)); await context.SaveChangesAsync(); } } private async Task HandleDeveloperPublisherCreation(Game? game) { context.Publishers.RemoveRange( context.Publishers.Include(p => p.Games) .Where(p => p.Games.Count == 0)); context.Developers.RemoveRange( context.Developers.Include(d => d.Games) .Where(d => d.Games.Count == 0)); await context.SaveChangesAsync(); if (game?.Publisher != null) { context.Publishers.Attach(game.Publisher); } if (game?.Developer != null) { context.Developers.Attach(game.Developer); } } }