using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using NexusReader.Application.Abstractions.Messaging;
using NexusReader.Application.DTOs.Creator;
using NexusReader.Data.Persistence;
using NexusReader.Domain.Exceptions;
namespace NexusReader.Application.Queries.Creator;
///
/// Query to load all revisions for a specific Book, checking multi-tenant ownership boundaries.
///
/// The unique identifier of the target Book.
/// The ID of the creator requesting revision data.
/// The tenant ID for multi-tenant isolation.
public record GetBookRevisionsQuery(Guid BookId, string UserId, string TenantId) : IQuery>;
///
/// Handler that lists past revisions of a Book, verifying ownership to prevent cross-tenant leakages.
///
public class GetBookRevisionsQueryHandler : IQueryHandler>
{
private readonly IDbContextFactory _dbContextFactory;
public GetBookRevisionsQueryHandler(IDbContextFactory dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public async Task>> Handle(GetBookRevisionsQuery request, CancellationToken cancellationToken)
{
using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
// Verify the book exists and belongs to this tenant/user to prevent cross-tenant data leaks
var bookExists = await dbContext.Books
.AnyAsync(b => b.Id == request.BookId && b.UserId == request.UserId && b.TenantId == request.TenantId, cancellationToken);
if (!bookExists)
{
return FluentResults.Result.Fail>(new FluentResults.Error($"Book with ID '{request.BookId}' was not found."));
}
// Fetch all revisions sorted chronologically
var revisions = await dbContext.BookRevisions
.AsNoTracking()
.Where(r => r.BookId == request.BookId)
.OrderByDescending(r => r.CreatedAt)
.Select(r => new CreatorBookRevisionDto(
r.Id,
r.VersionString,
r.IsPublished,
r.CreatedAt,
r.PublishedAt
))
.ToListAsync(cancellationToken);
return FluentResults.Result.Ok(revisions);
}
}