#nullable enable
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Booking;
using Baya.Application.Models.Common;
using Mediator;

namespace Baya.Application.Features.Bookings.Queries.GetBookingDetail;

internal sealed class GetBookingDetailQueryHandler(ICurrentUser currentUser, IUnitOfWork unitOfWork)
    : IRequestHandler<GetBookingDetailQuery, OperationResult<BookingDetailDto>>
{
    public async ValueTask<OperationResult<BookingDetailDto>> Handle(GetBookingDetailQuery request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<BookingDetailDto>.UnauthorizedResult("Not authenticated.");

        var detail = await unitOfWork.BookingRepository.GetDetailAsync(request.Id, cancellationToken);
        if (detail is null)
            return OperationResult<BookingDetailDto>.NotFoundResult("Booking not found.");

        var isAdmin = currentUser.Roles?.Any(BookingRoles.Admin.Contains) == true;

        var customerId = await unitOfWork.CustomerProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        if (customerId == detail.CustomerId)
            return OperationResult<BookingDetailDto>.SuccessResult(BookingMapper.ToDetailDto(detail, includeAddress: true));

        var nurseId = await unitOfWork.NurseProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        if (nurseId == detail.NurseId)
            return OperationResult<BookingDetailDto>.SuccessResult(BookingMapper.ToDetailDto(detail, includeAddress: false));

        if (isAdmin)
            return OperationResult<BookingDetailDto>.SuccessResult(BookingMapper.ToDetailDto(detail, includeAddress: true));

        // Neither party nor admin — do not leak that the booking exists.
        return OperationResult<BookingDetailDto>.NotFoundResult("Booking not found.");
    }
}
