using LiteCqrs; using Microsoft.EntityFrameworkCore; using TeleWave.Application.Common.Interfaces; using TeleWave.Application.Common.Models; using TeleWave.Domain.Media; namespace TeleWave.Application.Media.Register; public sealed class RegisterMediaAssetCommandHandler(IAppDbContext dbContext, IMediaStorage storage) : ICommandHandler> { public async Task> Handle( RegisterMediaAssetCommand command, CancellationToken cancellationToken ) { // Дедуп по имени: тот же файл уже в библиотеке (кроме проваленных — их разрешаем перезалить). var duplicate = await dbContext.MediaAssets.AnyAsync( x => x.OriginalFileName == command.OriginalFileName && x.Status != MediaAssetStatus.Failed, cancellationToken ); if (duplicate) return Result.Failure(MediaErrors.DuplicateFileName); var extension = Path.GetExtension(command.OriginalFileName).ToLowerInvariant(); var asset = MediaAsset.Register(command.OriginalFileName, extension, command.Source); // Сначала фиксируем ассет в БД, затем переносим файл в originals/. Если перенос не удался — // откатываем регистрацию, чтобы не оставить orphan (либо есть и строка БД, и файл, либо нет ни // того, ни другого). Обратный порядок оставлял бы перемещённый файл без строки БД при сбое save. dbContext.MediaAssets.Add(asset); await dbContext.SaveChangesAsync(cancellationToken); try { await storage.PromoteToOriginalAsync( command.Source, command.SourceToken, asset.Id, extension, cancellationToken ); } catch { dbContext.MediaAssets.Remove(asset); await dbContext.SaveChangesAsync(cancellationToken); throw; } return Result.Success(asset.Id); } }