using System.Threading.Channels; using ErsatzTV.Application.Playouts; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Scheduling; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Application.MediaCollections; public class AddArtistToCollectionHandler : IRequestHandler> { private readonly ChannelWriter _channel; private readonly IDbContextFactory _dbContextFactory; private readonly IMediaCollectionRepository _mediaCollectionRepository; public AddArtistToCollectionHandler( IDbContextFactory dbContextFactory, IMediaCollectionRepository mediaCollectionRepository, ChannelWriter channel) { _dbContextFactory = dbContextFactory; _mediaCollectionRepository = mediaCollectionRepository; _channel = channel; } public async Task> Handle( AddArtistToCollection request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); return await LanguageExtensions.Apply(validation, parameters => ApplyAddArtistRequest(dbContext, parameters)); } private async Task ApplyAddArtistRequest(TvContext dbContext, Parameters parameters) { parameters.Collection.MediaItems.Add(parameters.Artist); if (await dbContext.SaveChangesAsync() > 0) { // refresh all playouts that use this collection foreach (int playoutId in await _mediaCollectionRepository .PlayoutIdsUsingCollection(parameters.Collection.Id)) { await _channel.WriteAsync(new BuildPlayout(playoutId, PlayoutBuildMode.Refresh)); } } return Unit.Default; } private static async Task> Validate( TvContext dbContext, AddArtistToCollection request) => (await CollectionMustExist(dbContext, request), await ValidateArtist(dbContext, request)) .Apply((collection, artist) => new Parameters(collection, artist)); private static Task> CollectionMustExist( TvContext dbContext, AddArtistToCollection request) => dbContext.Collections .Include(c => c.MediaItems) .SelectOneAsync(c => c.Id, c => c.Id == request.CollectionId) .Map(o => o.ToValidation("Collection does not exist.")); private static Task> ValidateArtist( TvContext dbContext, AddArtistToCollection request) => dbContext.Artists .SelectOneAsync(a => a.Id, a => a.Id == request.ArtistId) .Map(o => o.ToValidation("Artist does not exist")); private sealed record Parameters(Collection Collection, Artist Artist); }