#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.ListBookings;

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

        var page = request.Page < 1 ? 1 : request.Page;
        var pageSize = request.PageSize is < 1 or > 100 ? 20 : request.PageSize;
        var role = request.Role?.ToLowerInvariant();

        if (role == "all")
        {
            if (currentUser.Roles?.Any(BookingRoles.Admin.Contains) != true)
                return OperationResult<PagedResult<BookingListItemDto>>.ForbiddenResult("Only an admin can list all bookings.");

            var all = await unitOfWork.BookingRepository.ListAllAsync(request.Status, page, pageSize, cancellationToken);
            return OperationResult<PagedResult<BookingListItemDto>>.SuccessResult(all);
        }

        if (role == "nurse")
        {
            var nurseId = await unitOfWork.NurseProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
            if (nurseId is not { } nid)
                return OperationResult<PagedResult<BookingListItemDto>>.SuccessResult(Empty(page, pageSize));

            var nurseList = await unitOfWork.BookingRepository.ListForNurseAsync(nid, request.Status, page, pageSize, cancellationToken);
            return OperationResult<PagedResult<BookingListItemDto>>.SuccessResult(nurseList);
        }

        // Default: the customer's own bookings.
        var customerId = await unitOfWork.CustomerProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        if (customerId is not { } cid)
            return OperationResult<PagedResult<BookingListItemDto>>.SuccessResult(Empty(page, pageSize));

        var list = await unitOfWork.BookingRepository.ListForCustomerAsync(cid, request.Status, page, pageSize, cancellationToken);
        return OperationResult<PagedResult<BookingListItemDto>>.SuccessResult(list);
    }

    private static PagedResult<BookingListItemDto> Empty(int page, int pageSize)
        => new([], 0, page, pageSize);
}
