using FluentResults; using MediatR; using NexusReader.Application.Abstractions.Messaging; using NexusReader.Application.Abstractions.Persistence; using NexusReader.Application.Abstractions.Services; using NexusReader.Domain.Entities; namespace NexusReader.Application.Commands.Library; public class IngestEbookCommandHandler : IRequestHandler> { private readonly IEbookRepository _ebookRepository; private readonly IBookStorageService _storageService; public IngestEbookCommandHandler( IEbookRepository ebookRepository, IBookStorageService storageService) { _ebookRepository = ebookRepository; _storageService = storageService; } public async Task> Handle(IngestEbookCommand request, CancellationToken cancellationToken) { string epubPath; string? coverUrl; try { // 1. Save Files epubPath = await _storageService.SaveEbookAsync(request.EpubData, $"{request.Title}.epub"); coverUrl = request.CoverImage != null && request.CoverImage.Length > 0 ? await _storageService.SaveCoverAsync(request.CoverImage, $"{request.Title}_cover.jpg") : null; } catch (IOException ex) { return Result.Fail(new Error($"Storage I/O failure: {ex.Message}").CausedBy(ex)); } catch (Exception ex) { return Result.Fail(new Error($"Storage failure: {ex.Message}").CausedBy(ex)); } try { // 2. Resolve Author (case-insensitive via repository) var authorName = string.IsNullOrWhiteSpace(request.AuthorName) ? "Unknown Author" : request.AuthorName.Trim(); var author = await _ebookRepository.FindAuthorByNameAsync(authorName, cancellationToken); if (author == null) { author = new Author { Name = authorName }; _ebookRepository.AddAuthor(author); } // 3. Create Ebook var ebook = new Ebook { Title = request.Title, Author = author, FilePath = epubPath, CoverUrl = coverUrl, UserId = request.UserId, TenantId = request.TenantId, AddedDate = DateTime.UtcNow }; _ebookRepository.AddEbook(ebook); await _ebookRepository.SaveChangesAsync(cancellationToken); return Result.Ok(ebook.Id); } catch (Exception ex) { return Result.Fail(new Error($"Database error during ingestion: {ex.Message}").CausedBy(ex)); } } }