using Baya.Application.Contracts.Common;
using Baya.Application.Features.Booking.Queries.GetBookingRequest;
using Baya.Application.Features.Booking.Queries.ListBookingRequests;
using Baya.Domain.Entities.User;
using NSubstitute;

namespace Baya.Test.Foundation.Booking;

public class BookingRequestQueryTests : IDisposable
{
    private readonly BookingTestHost _host = new();
    private readonly ICurrentUser _currentUser = Substitute.For<ICurrentUser>();

    private void SignInAs(int userId, params string[] roles)
    {
        _currentUser.UserId.Returns(userId);
        _currentUser.Roles.Returns(roles);
    }

    [Fact]
    public async Task List_NurseInbox_ShowsPatientCounterpartyAndCustomerNotesOnly()
    {
        _host.AddPendingRequest();
        SignInAs(_host.NurseUserId, RoleNames.Nurse);

        var handler = new ListBookingRequestsQueryHandler(_currentUser, _host.UnitOfWork);
        var result = await handler.Handle(new ListBookingRequestsQuery(), CancellationToken.None);

        Assert.True(result.IsSuccess);
        Assert.Equal(1, result.Result.Total);
        var item = result.Result.Items[0];
        Assert.Contains("پدر", item.CounterpartyName);
        Assert.Equal("Careful with the IV.", item.CustomerNotes);
        Assert.Null(item.NurseRating);
    }

    [Fact]
    public async Task List_CustomerInbox_ShowsNurseCounterpartyWithoutCustomerNotes()
    {
        _host.AddPendingRequest();
        SignInAs(_host.CustomerUserId, RoleNames.Customer);

        var handler = new ListBookingRequestsQueryHandler(_currentUser, _host.UnitOfWork);
        var result = await handler.Handle(new ListBookingRequestsQuery(), CancellationToken.None);

        Assert.True(result.IsSuccess);
        Assert.Equal(1, result.Result.Total);
        var item = result.Result.Items[0];
        Assert.Contains("زهرا", item.CounterpartyName);
        Assert.Null(item.CustomerNotes);
        Assert.NotNull(item.NurseRating);
    }

    [Fact]
    public async Task Get_AsNurse_MasksFullAddress()
    {
        var request = _host.AddPendingRequest();
        SignInAs(_host.NurseUserId, RoleNames.Nurse);

        var handler = new GetBookingRequestQueryHandler(_currentUser, _host.UnitOfWork);
        var result = await handler.Handle(new GetBookingRequestQuery(request.Id), CancellationToken.None);

        Assert.True(result.IsSuccess);
        Assert.Null(result.Result.AddressLine);
        Assert.Null(result.Result.PostalCode);
        // Coarse location + stage-1 notes are still available to the nurse.
        Assert.Equal("Careful with the IV.", result.Result.CustomerNotes);
        Assert.False(string.IsNullOrEmpty(result.Result.CityNameFa));
    }

    [Fact]
    public async Task Get_AsOwningCustomer_ReturnsFullAddress()
    {
        var request = _host.AddPendingRequest();
        SignInAs(_host.CustomerUserId, RoleNames.Customer);

        var handler = new GetBookingRequestQueryHandler(_currentUser, _host.UnitOfWork);
        var result = await handler.Handle(new GetBookingRequestQuery(request.Id), CancellationToken.None);

        Assert.True(result.IsSuccess);
        Assert.False(string.IsNullOrEmpty(result.Result.AddressLine));
    }

    [Fact]
    public async Task Get_AsThirdParty_IsNotFound()
    {
        var request = _host.AddPendingRequest();
        SignInAs(999999, RoleNames.Customer);

        var handler = new GetBookingRequestQueryHandler(_currentUser, _host.UnitOfWork);
        var result = await handler.Handle(new GetBookingRequestQuery(request.Id), CancellationToken.None);

        Assert.True(result.IsNotFound);
    }

    public void Dispose() => _host.Dispose();
}
