using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Configuration;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Features.Booking.Queries.GetCheckoutSummary;
using Baya.Application.Models.Booking;
using Baya.Domain.Entities.Booking;
using Baya.Domain.Entities.User;
using NSubstitute;

namespace Baya.Test.Foundation.Booking;

public class GetCheckoutSummaryHandlerTests
{
    private readonly ICurrentUser _currentUser = Substitute.For<ICurrentUser>();
    private readonly IUnitOfWork _unitOfWork = Substitute.For<IUnitOfWork>();
    private readonly IPlatformConfig _config = Substitute.For<IPlatformConfig>();
    private readonly ICustomerProfileRepository _customers = Substitute.For<ICustomerProfileRepository>();
    private readonly IBookingRequestRepository _requests = Substitute.For<IBookingRequestRepository>();

    private const int CustomerUserId = 7;
    private const long CustomerId = 100;
    private const long RequestId = 1;

    public GetCheckoutSummaryHandlerTests()
    {
        _unitOfWork.CustomerProfileRepository.Returns(_customers);
        _unitOfWork.BookingRequestRepository.Returns(_requests);
        _currentUser.UserId.Returns(CustomerUserId);
        _currentUser.Roles.Returns([RoleNames.Customer]);
        _customers.GetProfileIdByUserIdAsync(CustomerUserId, Arg.Any<CancellationToken>()).Returns(CustomerId);
        _config.GetConfig<decimal>("platform_fee_rate", Arg.Any<CancellationToken>()).Returns(0.15m);
        _config.GetConfig<decimal>("vat_rate", Arg.Any<CancellationToken>()).Returns(0.10m);
    }

    [Fact]
    public async Task CheckoutSummary_Reconciles_ServicePlusCommissionPlusVatEqualsTotal()
    {
        // gross = 1,000,000 × 2 = 2,000,000; commission = 15% = 300,000; payout = 1,700,000.
        // VAT carved out of the commission: net = round(300,000 / 1.10) = 272,727; vat = 27,273.
        _requests.GetCheckoutContextAsync(RequestId, CustomerId, Arg.Any<CancellationToken>())
            .Returns(Context(1_000_000, sessionCount: 2));
        var handler = new GetCheckoutSummaryQueryHandler(_currentUser, _unitOfWork, _config);

        var result = await handler.Handle(new GetCheckoutSummaryQuery(RequestId), CancellationToken.None);

        Assert.True(result.IsSuccess);
        var dto = result.Result;
        Assert.Equal("2000000", dto.TotalIrr);
        Assert.Equal("2000000", dto.GrossPriceIrr);
        Assert.Equal("300000", dto.BalinyaarCommissionIrr);
        Assert.Equal("1700000", dto.NursePayoutAmount);
        Assert.Equal("1700000", dto.ServiceCostIrr);
        Assert.Equal("272727", dto.CommissionIrr);
        Assert.Equal("27273", dto.VatIrr);
        // The load-bearing invariant: service + commission(net) + vat == total, to the rial.
        Assert.Equal(
            long.Parse(dto.TotalIrr),
            long.Parse(dto.ServiceCostIrr) + long.Parse(dto.CommissionIrr) + long.Parse(dto.VatIrr));
    }

    [Fact]
    public async Task CheckoutSummary_ForeignRequest_IsNotFound()
    {
        _requests.GetCheckoutContextAsync(RequestId, CustomerId, Arg.Any<CancellationToken>())
            .Returns((CheckoutContext)null);
        var handler = new GetCheckoutSummaryQueryHandler(_currentUser, _unitOfWork, _config);

        var result = await handler.Handle(new GetCheckoutSummaryQuery(RequestId), CancellationToken.None);

        Assert.False(result.IsSuccess);
        Assert.True(result.IsNotFound);
    }

    private static CheckoutContext Context(long price, int sessionCount)
        => new(
            RequestId, BookingRequestStatus.AcceptedAwaitingPayment, "پرستار", "پدر",
            "خدمت", "per_session", sessionCount, price,
            new DateOnly(2026, 8, 1), new TimeOnly(9, 0), new TimeOnly(13, 0),
            new DateTime(2026, 7, 6, 10, 30, 0, DateTimeKind.Utc));
}
