using Baya.Domain.Entities.Booking;

namespace Baya.Test.Foundation.Booking;

public class BookingRequestTransitionsTests
{
    [Theory]
    [InlineData(BookingRequestStatus.PendingNurseResponse, BookingRequestStatus.AcceptedAwaitingPayment, true)]
    [InlineData(BookingRequestStatus.PendingNurseResponse, BookingRequestStatus.RejectedByNurse, true)]
    [InlineData(BookingRequestStatus.PendingNurseResponse, BookingRequestStatus.ExpiredNoResponse, true)]
    [InlineData(BookingRequestStatus.PendingNurseResponse, BookingRequestStatus.CancelledByCustomer, true)]
    [InlineData(BookingRequestStatus.AcceptedAwaitingPayment, BookingRequestStatus.Converted, true)]
    [InlineData(BookingRequestStatus.AcceptedAwaitingPayment, BookingRequestStatus.PaymentDeadlineExpired, true)]
    [InlineData(BookingRequestStatus.AcceptedAwaitingPayment, BookingRequestStatus.CancelledByCustomer, true)]
    // Illegal edges.
    [InlineData(BookingRequestStatus.PendingNurseResponse, BookingRequestStatus.Converted, false)]
    [InlineData(BookingRequestStatus.PendingNurseResponse, BookingRequestStatus.PaymentDeadlineExpired, false)]
    [InlineData(BookingRequestStatus.AcceptedAwaitingPayment, BookingRequestStatus.RejectedByNurse, false)]
    [InlineData(BookingRequestStatus.AcceptedAwaitingPayment, BookingRequestStatus.ExpiredNoResponse, false)]
    // Terminals have no outgoing edges.
    [InlineData(BookingRequestStatus.Converted, BookingRequestStatus.CancelledByCustomer, false)]
    [InlineData(BookingRequestStatus.RejectedByNurse, BookingRequestStatus.AcceptedAwaitingPayment, false)]
    [InlineData(BookingRequestStatus.ExpiredNoResponse, BookingRequestStatus.AcceptedAwaitingPayment, false)]
    [InlineData(BookingRequestStatus.PaymentDeadlineExpired, BookingRequestStatus.CancelledByCustomer, false)]
    [InlineData(BookingRequestStatus.CancelledByCustomer, BookingRequestStatus.AcceptedAwaitingPayment, false)]
    public void CanTransition_MatchesForwardOnlyMachine(string from, string to, bool expected)
        => Assert.Equal(expected, BookingRequestTransitions.CanTransition(from, to));

    [Fact]
    public void Accept_FromPending_SetsPaymentDeadlineAndStatus()
    {
        var request = new BookingRequest { NurseResponseDeadlineAt = DateTime.UnixEpoch.AddHours(24) };
        var deadline = DateTime.UnixEpoch.AddMinutes(30);

        request.Accept(deadline);

        Assert.Equal(BookingRequestStatus.AcceptedAwaitingPayment, request.Status);
        Assert.Equal(deadline, request.PaymentDeadlineAt);
    }

    [Fact]
    public void Accept_FromTerminal_Throws()
    {
        var request = new BookingRequest { NurseResponseDeadlineAt = DateTime.UnixEpoch };
        request.Reject("no");

        Assert.Throws<InvalidOperationException>(() => request.Accept(DateTime.UnixEpoch));
    }
}
