#nullable enable
using Baya.Application.Common;
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.ListBookingRequests;

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

        var (page, pageSize) = Pagination.Normalize(request.Page, request.PageSize);

        var nurseId = await unitOfWork.NurseProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        var customerId = await unitOfWork.CustomerProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);

        var asNurse = ResolveInboxRole(request.Role, nurseId, customerId);
        if (asNurse is null)
        {
            if (nurseId is null && customerId is null)
                return OperationResult<PagedResult<BookingRequestListItemDto>>.SuccessResult(
                    new PagedResult<BookingRequestListItemDto>([], 0, page, pageSize));

            return OperationResult<PagedResult<BookingRequestListItemDto>>.FailureResult(
                nameof(request.Role), "Specify role=customer or role=nurse — you hold both roles.");
        }

        var result = asNurse.Value
            ? await unitOfWork.BookingRequestRepository.ListForNurseAsync(nurseId!.Value, request.Status, page, pageSize, cancellationToken)
            : await unitOfWork.BookingRequestRepository.ListForCustomerAsync(customerId!.Value, request.Status, page, pageSize, cancellationToken);

        return OperationResult<PagedResult<BookingRequestListItemDto>>.SuccessResult(result);
    }

    // Returns true = nurse inbox, false = customer inbox, null = undecidable (no profile, or both without a
    // Role hint).
    private static bool? ResolveInboxRole(string? role, long? nurseId, long? customerId)
    {
        if (string.Equals(role, RoleNames.Nurse, StringComparison.OrdinalIgnoreCase))
            return nurseId is not null ? true : null;
        if (string.Equals(role, RoleNames.Customer, StringComparison.OrdinalIgnoreCase))
            return customerId is not null ? false : null;

        return (nurseId, customerId) switch
        {
            (not null, null) => true,
            (null, not null) => false,
            _ => null
        };
    }
}
