#nullable enable
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Common;
using Baya.Application.Models.Invoices;
using Baya.Domain.Entities.User;
using Mediator;

namespace Baya.Application.Features.Invoices.Queries.GetInvoice;

internal sealed class GetInvoiceQueryHandler(
    IUnitOfWork unitOfWork,
    ICurrentUser currentUser,
    IObjectStorage objectStorage)
    : IRequestHandler<GetInvoiceQuery, OperationResult<InvoiceDto>>
{
    public async ValueTask<OperationResult<InvoiceDto>> Handle(GetInvoiceQuery request, CancellationToken cancellationToken)
    {
        var projection = await unitOfWork.InvoiceRepository.GetByBookingIdAsync(request.BookingId, cancellationToken);
        if (projection is null)
            return OperationResult<InvoiceDto>.NotFoundResult("Invoice not found.");

        // Admins read any invoice; a customer reads only their own booking's — a cross-customer read is a
        // clean not-found, never a leak.
        var isAdmin = currentUser.Roles.Contains(RoleNames.Admin);
        if (!isAdmin && projection.CustomerUserId != currentUser.UserId)
            return OperationResult<InvoiceDto>.NotFoundResult("Invoice not found.");

        var pdfUrl = projection.PdfStorageKey is { } key ? objectStorage.GetUrl(key) : null;
        return OperationResult<InvoiceDto>.SuccessResult(projection.Invoice with { PdfUrl = pdfUrl });
    }
}
