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

namespace Baya.Application.Features.Reviews.Queries.GetReviewEligibility;

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

        var customerId = await unitOfWork.CustomerProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        var booking = await unitOfWork.ReviewRepository.GetReviewableBookingAsync(request.BookingId, cancellationToken);

        if (booking is null)
            return Result(false, ReviewEligibilityDto.ReasonNotFound);
        if (customerId is not { } cid || booking.CustomerProfileId != cid)
            return Result(false, ReviewEligibilityDto.ReasonNotOwner);
        if (booking.Status is not (BookingStatus.Completed or BookingStatus.Closed))
            return Result(false, ReviewEligibilityDto.ReasonNotCompleted);
        if (await unitOfWork.ReviewRepository.ExistsForBookingAsync(request.BookingId, cancellationToken))
            return Result(false, ReviewEligibilityDto.ReasonAlreadyReviewed);

        return Result(true, null);
    }

    private static OperationResult<ReviewEligibilityDto> Result(bool canReview, string? reason)
        => OperationResult<ReviewEligibilityDto>.SuccessResult(new ReviewEligibilityDto(canReview, reason));
}
