using System.Linq; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using ErsatzTV.Application.Playouts.Commands; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Infrastructure.Data; using LanguageExt; using MediatR; using Microsoft.EntityFrameworkCore; using static ErsatzTV.Application.ProgramSchedules.Mapper; namespace ErsatzTV.Application.ProgramSchedules.Commands { public class AddProgramScheduleItemHandler : ProgramScheduleItemCommandBase, IRequestHandler> { private readonly ChannelWriter _channel; private readonly IDbContextFactory _dbContextFactory; public AddProgramScheduleItemHandler( IDbContextFactory dbContextFactory, ChannelWriter channel) { _dbContextFactory = dbContextFactory; _channel = channel; } public async Task> Handle( AddProgramScheduleItem request, CancellationToken cancellationToken) { await using TvContext dbContext = _dbContextFactory.CreateDbContext(); Validation validation = await Validate(dbContext, request); return await validation.Apply(ps => PersistItem(dbContext, request, ps)); } private async Task PersistItem( TvContext dbContext, AddProgramScheduleItem request, ProgramSchedule programSchedule) { int nextIndex = programSchedule.Items.Select(i => i.Index).DefaultIfEmpty(0).Max() + 1; ProgramScheduleItem item = BuildItem(programSchedule, nextIndex, request); programSchedule.Items.Add(item); await dbContext.SaveChangesAsync(); // rebuild any playouts that use this schedule foreach (Playout playout in programSchedule.Playouts) { await _channel.WriteAsync(new BuildPlayout(playout.Id, true)); } return ProjectToViewModel(item); } private static Task> Validate( TvContext dbContext, AddProgramScheduleItem request) => ProgramScheduleMustExist(dbContext, request.ProgramScheduleId) .BindT(programSchedule => PlayoutModeMustBeValid(request, programSchedule)); } }