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

namespace Baya.Application.Features.Booking.Queries.GetBookingRequest;

internal sealed class GetBookingRequestQueryHandler(ICurrentUser currentUser, IUnitOfWork unitOfWork)
    : IRequestHandler<GetBookingRequestQuery, OperationResult<BookingRequestDto>>
{
    private static readonly string[] AdminRoles =
        [RoleNames.Admin, RoleNames.SuperAdmin, RoleNames.Support, RoleNames.Finance, RoleNames.Moderation];

    public async ValueTask<OperationResult<BookingRequestDto>> Handle(GetBookingRequestQuery request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<BookingRequestDto>.UnauthorizedResult("Not authenticated.");

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

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

        var customerId = await unitOfWork.CustomerProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        if (customerId == detail.CustomerId)
            return OperationResult<BookingRequestDto>.SuccessResult(BookingRequestMapper.ToDto(detail, includeFullAddress: true));

        var nurseId = await unitOfWork.NurseProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        if (nurseId == detail.NurseId)
            return OperationResult<BookingRequestDto>.SuccessResult(BookingRequestMapper.ToDto(detail, includeFullAddress: false));

        if (isAdmin)
            return OperationResult<BookingRequestDto>.SuccessResult(BookingRequestMapper.ToDto(detail, includeFullAddress: true));

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