using Baya.Application.Common;
using Baya.Application.Contracts.Common;
using Baya.Application.Features.Bookings.Commands.ConvertRequestToBooking;
using Baya.Application.Features.Bookings.Commands.SubmitCareInstructions;
using Baya.Application.Features.Bookings.Queries.GetCareInstructions;
using NSubstitute;

namespace Baya.Test.Foundation.Bookings;

public class CareInstructionsDisclosureTests
{
    private static readonly DateTimeOffset Now = new(2026, 7, 6, 10, 0, 0, TimeSpan.Zero);

    private static async Task<long> ConvertAsync(BookingsTestHost host)
    {
        var variantId = host.AddVariant(sessionCount: 1);
        var requestId = host.AddAcceptedRequest(variantId);
        var handler = new ConvertRequestToBookingCommandHandler(
            host.AsCustomer(), host.UnitOfWork, host.Config(), host.Clock(Now), host.Capture(),
            new VariantSnapshotSerializer(), Substitute.For<INotificationDispatcher>());
        var result = await handler.Handle(new ConvertRequestToBookingCommand(requestId), CancellationToken.None);
        return result.Result.Id;
    }

    [Fact]
    public async Task Care_instructions_are_gated_to_assigned_nurse_and_admin_only()
    {
        using var host = new BookingsTestHost();
        var bookingId = await ConvertAsync(host);

        // Customer authors the encrypted stage-2 instructions.
        var submit = new SubmitCareInstructionsCommandHandler(host.AsCustomer(), host.UnitOfWork);
        var submitResult = await submit.Handle(
            new SubmitCareInstructionsCommand("diabetes", "insulin", "penicillin", "ring twice", "Sara", "0912", bookingId),
            CancellationToken.None);
        Assert.True(submitResult.IsSuccess);

        // Assigned nurse → decrypted fields.
        var asNurse = new GetCareInstructionsQueryHandler(host.AsNurse(), host.UnitOfWork);
        var nurseRead = await asNurse.Handle(new GetCareInstructionsQuery(bookingId), CancellationToken.None);
        Assert.True(nurseRead.IsSuccess);
        Assert.Equal("insulin", nurseRead.Result.Medications);

        // Admin → decrypted fields.
        var asAdmin = new GetCareInstructionsQueryHandler(host.AsAdmin(), host.UnitOfWork);
        var adminRead = await asAdmin.Handle(new GetCareInstructionsQuery(bookingId), CancellationToken.None);
        Assert.True(adminRead.IsSuccess);

        // The customer (author) cannot read them back — the disclosure is the nurse's.
        var asCustomer = new GetCareInstructionsQueryHandler(host.AsCustomer(), host.UnitOfWork);
        var customerRead = await asCustomer.Handle(new GetCareInstructionsQuery(bookingId), CancellationToken.None);
        Assert.True(customerRead.IsNotFound);

        // An unassigned nurse (no matching profile) cannot read them.
        var asOtherNurse = new GetCareInstructionsQueryHandler(host.AsNurse(userId: 987654), host.UnitOfWork);
        var otherRead = await asOtherNurse.Handle(new GetCareInstructionsQuery(bookingId), CancellationToken.None);
        Assert.True(otherRead.IsNotFound);
    }
}
