#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.Booking;
using Mediator;

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

internal sealed class GetCareInstructionsQueryHandler(ICurrentUser currentUser, IUnitOfWork unitOfWork)
    : IRequestHandler<GetCareInstructionsQuery, OperationResult<CareInstructionsDto>>
{
    // The clinical fields are visible only once the booking is confirmed and while it is a live/closed
    // engagement — never pre-payment, never on a cancelled booking.
    private static readonly string[] DisclosableStatuses =
    [
        BookingStatus.Confirmed, BookingStatus.InProgress,
        BookingStatus.Completed, BookingStatus.Disputed, BookingStatus.Closed
    ];

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

        var gate = await unitOfWork.BookingRepository.GetCareInstructionsGateAsync(request.BookingId, cancellationToken);
        if (gate is null)
            return OperationResult<CareInstructionsDto>.NotFoundResult("Booking not found.");

        var isAdmin = currentUser.Roles?.Any(BookingRoles.Admin.Contains) == true;
        var nurseId = await unitOfWork.NurseProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        var isAssignedNurse = nurseId == gate.NurseId;

        // Two-stage disclosure: only the assigned nurse or an admin, only post-confirmation. Any other caller
        // (the customer, an unassigned nurse, or a pre-confirmation booking) must not learn anything.
        if ((!isAssignedNurse && !isAdmin) || !DisclosableStatuses.Contains(gate.BookingStatus))
            return OperationResult<CareInstructionsDto>.NotFoundResult("Care instructions not found.");

        if (gate.Instructions is null)
            return OperationResult<CareInstructionsDto>.NotFoundResult("No care instructions have been added for this booking yet.");

        return OperationResult<CareInstructionsDto>.SuccessResult(gate.Instructions);
    }
}
