using System.Threading.Channels; using ErsatzTV.Application.Playouts; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Scheduling; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Application.ProgramSchedules; public class UpdateProgramScheduleHandler : IRequestHandler> { private readonly ChannelWriter _channel; private readonly IDbContextFactory _dbContextFactory; public UpdateProgramScheduleHandler( IDbContextFactory dbContextFactory, ChannelWriter channel) { _dbContextFactory = dbContextFactory; _channel = channel; } public async Task> Handle( UpdateProgramSchedule request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request); return await validation.Apply(ps => ApplyUpdateRequest(dbContext, ps, request)); } private async Task ApplyUpdateRequest( TvContext dbContext, ProgramSchedule programSchedule, UpdateProgramSchedule request) { // we need to refresh playouts if the playback order or keep multi-episodes has been modified bool needToRefreshPlayout = programSchedule.KeepMultiPartEpisodesTogether != request.KeepMultiPartEpisodesTogether || programSchedule.TreatCollectionsAsShows != request.TreatCollectionsAsShows || programSchedule.ShuffleScheduleItems != request.ShuffleScheduleItems; programSchedule.Name = request.Name; programSchedule.KeepMultiPartEpisodesTogether = request.KeepMultiPartEpisodesTogether; programSchedule.TreatCollectionsAsShows = programSchedule.KeepMultiPartEpisodesTogether && request.TreatCollectionsAsShows; programSchedule.ShuffleScheduleItems = request.ShuffleScheduleItems; await dbContext.SaveChangesAsync(); if (needToRefreshPlayout) { List playoutIds = await dbContext.Playouts .Filter(p => p.ProgramScheduleId == programSchedule.Id) .Map(p => p.Id) .ToListAsync(); foreach (int playoutId in playoutIds) { await _channel.WriteAsync(new BuildPlayout(playoutId, PlayoutBuildMode.Refresh)); } } return new UpdateProgramScheduleResult(programSchedule.Id); } private static async Task> Validate( TvContext dbContext, UpdateProgramSchedule request) => (await ProgramScheduleMustExist(dbContext, request), ValidateName(request)) .Apply((programSchedule, _) => programSchedule); private static Task> ProgramScheduleMustExist( TvContext dbContext, UpdateProgramSchedule request) => dbContext.ProgramSchedules .SelectOneAsync(ps => ps.Id, ps => ps.Id == request.ProgramScheduleId) .Map(o => o.ToValidation("ProgramSchedule does not exist")); private static Validation ValidateName(UpdateProgramSchedule request) => request.NotEmpty(c => c.Name) .Bind(_ => request.NotLongerThan(50)(c => c.Name)); }