using ErsatzTV.Core; using ErsatzTV.Core.Domain.Scheduling; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Application.Scheduling; public class UpdateDecoHandler(IDbContextFactory dbContextFactory) : IRequestHandler> { public async Task> Handle(UpdateDeco 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 static async Task ApplyUpdateRequest( TvContext dbContext, Deco existing, UpdateDeco request) { existing.Name = request.Name; // watermark existing.WatermarkMode = request.WatermarkMode; existing.WatermarkId = request.WatermarkMode is DecoMode.Override ? request.WatermarkId : null; existing.UseWatermarkDuringFiller = request.WatermarkMode is DecoMode.Override && request.UseWatermarkDuringFiller; // default filler existing.DefaultFillerMode = request.DefaultFillerMode; existing.DefaultFillerCollectionType = request.DefaultFillerCollectionType; existing.DefaultFillerCollectionId = request.DefaultFillerMode is DecoMode.Override ? request.DefaultFillerCollectionId : null; existing.DefaultFillerMediaItemId = request.DefaultFillerMode is DecoMode.Override ? request.DefaultFillerMediaItemId : null; existing.DefaultFillerMultiCollectionId = request.DefaultFillerMode is DecoMode.Override ? request.DefaultFillerMultiCollectionId : null; existing.DefaultFillerSmartCollectionId = request.DefaultFillerMode is DecoMode.Override ? request.DefaultFillerSmartCollectionId : null; existing.DefaultFillerTrimToFit = request.DefaultFillerTrimToFit; // dead air fallback existing.DeadAirFallbackMode = request.DeadAirFallbackMode; existing.DeadAirFallbackCollectionType = request.DeadAirFallbackCollectionType; existing.DeadAirFallbackCollectionId = request.DeadAirFallbackMode is DecoMode.Override ? request.DeadAirFallbackCollectionId : null; existing.DeadAirFallbackMediaItemId = request.DeadAirFallbackMode is DecoMode.Override ? request.DeadAirFallbackMediaItemId : null; existing.DeadAirFallbackMultiCollectionId = request.DeadAirFallbackMode is DecoMode.Override ? request.DeadAirFallbackMultiCollectionId : null; existing.DeadAirFallbackSmartCollectionId = request.DeadAirFallbackMode is DecoMode.Override ? request.DeadAirFallbackSmartCollectionId : null; await dbContext.SaveChangesAsync(); return Mapper.ProjectToViewModel(existing); } private static async Task> Validate(TvContext dbContext, UpdateDeco request) => (await DecoMustExist(dbContext, request), await ValidateDecoName(dbContext, request)) .Apply((deco, _) => deco); private static Task> DecoMustExist( TvContext dbContext, UpdateDeco request) => dbContext.Decos .SelectOneAsync(d => d.Id, d => d.Id == request.DecoId) .Map(o => o.ToValidation("Deco does not exist")); private static async Task> ValidateDecoName( TvContext dbContext, UpdateDeco request) { if (request.Name.Length > 50) { return BaseError.New($"Deco name \"{request.Name}\" is invalid"); } Option maybeExisting = await dbContext.Decos .FirstOrDefaultAsync( d => d.Id != request.DecoId && d.DecoGroupId == request.DecoGroupId && d.Name == request.Name) .Map(Optional); return maybeExisting.IsSome ? BaseError.New($"A deco named \"{request.Name}\" already exists in that deco group") : Success(request.Name); } }