using System.Linq; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using LanguageExt; using MediatR; using static ErsatzTV.Application.Playouts.Mapper; using static LanguageExt.Prelude; using Channel = ErsatzTV.Core.Domain.Channel; namespace ErsatzTV.Application.Playouts.Commands { public class CreatePlayoutHandler : IRequestHandler> { private readonly ChannelWriter _channel; private readonly IChannelRepository _channelRepository; private readonly IPlayoutRepository _playoutRepository; private readonly IProgramScheduleRepository _programScheduleRepository; public CreatePlayoutHandler( IPlayoutRepository playoutRepository, IChannelRepository channelRepository, IProgramScheduleRepository programScheduleRepository, ChannelWriter channel) { _playoutRepository = playoutRepository; _channelRepository = channelRepository; _programScheduleRepository = programScheduleRepository; _channel = channel; } public Task> Handle( CreatePlayout request, CancellationToken cancellationToken) => Validate(request) .MapT(PersistPlayout) .Bind(v => v.ToEitherAsync()); private async Task PersistPlayout(Playout c) { PlayoutViewModel result = await _playoutRepository.Add(c).Map(ProjectToViewModel); await _channel.WriteAsync(new BuildPlayout(result.Id)); return result; } private async Task> Validate(CreatePlayout request) => (await ValidateChannel(request), await ProgramScheduleMustExist(request), ValidatePlayoutType(request)) .Apply( (channel, programSchedule, playoutType) => new Playout { ChannelId = channel.Id, ProgramScheduleId = programSchedule.Id, ProgramSchedulePlayoutType = playoutType }); private Task> ValidateChannel(CreatePlayout createPlayout) => ChannelMustExist(createPlayout).BindT(ChannelMustNotHavePlayouts); private async Task> ChannelMustExist(CreatePlayout createPlayout) => (await _channelRepository.Get(createPlayout.ChannelId)) .ToValidation("Channel does not exist."); private async Task> ChannelMustNotHavePlayouts(Channel channel) => Optional(await _channelRepository.CountPlayouts(channel.Id)) .Filter(count => count == 0) .Map(_ => channel) .ToValidation("Channel already has one playout."); private async Task> ProgramScheduleMustExist( CreatePlayout createPlayout) => (await _programScheduleRepository.GetWithPlayouts(createPlayout.ProgramScheduleId)) .ToValidation("ProgramSchedule does not exist.") .Bind(ProgramScheduleMustHaveItems); private Validation ProgramScheduleMustHaveItems(ProgramSchedule programSchedule) => Optional(programSchedule) .Filter(ps => ps.Items.Any()) .ToValidation("Program schedule must have items"); private Validation ValidatePlayoutType(CreatePlayout createPlayout) => Optional(createPlayout.ProgramSchedulePlayoutType) .Filter(playoutType => playoutType != ProgramSchedulePlayoutType.None) .ToValidation("[ProgramSchedulePlayoutType] must not be None"); } }