using Baya.Domain.Entities.Booking;
using BookingEntity = Baya.Domain.Entities.Booking.Booking;

namespace Baya.Test.Foundation.Bookings;

public class BookingTransitionsTests
{
    [Theory]
    [InlineData(BookingStatus.PendingPayment, BookingStatus.Confirmed, true)]
    [InlineData(BookingStatus.PendingPayment, BookingStatus.Cancelled, true)]
    [InlineData(BookingStatus.Confirmed, BookingStatus.InProgress, true)]
    [InlineData(BookingStatus.InProgress, BookingStatus.Completed, true)]
    [InlineData(BookingStatus.Completed, BookingStatus.Disputed, true)]
    [InlineData(BookingStatus.Completed, BookingStatus.Closed, true)]
    [InlineData(BookingStatus.Disputed, BookingStatus.Closed, true)]
    // Illegal edges.
    [InlineData(BookingStatus.Confirmed, BookingStatus.Completed, false)]
    [InlineData(BookingStatus.PendingPayment, BookingStatus.InProgress, false)]
    [InlineData(BookingStatus.Closed, BookingStatus.InProgress, false)]
    [InlineData(BookingStatus.Cancelled, BookingStatus.Confirmed, false)]
    public void Booking_transition_guard(string from, string to, bool allowed)
        => Assert.Equal(allowed, BookingTransitions.CanTransition(from, to));

    [Theory]
    [InlineData(BookingSessionStatus.Scheduled, BookingSessionStatus.InProgress, true)]
    [InlineData(BookingSessionStatus.Scheduled, BookingSessionStatus.Cancelled, true)]
    [InlineData(BookingSessionStatus.Scheduled, BookingSessionStatus.Missed, true)]
    [InlineData(BookingSessionStatus.InProgress, BookingSessionStatus.Completed, true)]
    [InlineData(BookingSessionStatus.Completed, BookingSessionStatus.InProgress, false)]
    [InlineData(BookingSessionStatus.Missed, BookingSessionStatus.Completed, false)]
    public void Session_transition_guard(string from, string to, bool allowed)
        => Assert.Equal(allowed, BookingSessionTransitions.CanTransition(from, to));

    [Fact]
    public void Booking_TransitionTo_stamps_timestamps_and_rejects_illegal_edge()
    {
        var booking = new BookingEntity();
        var now = new DateTime(2026, 7, 6, 10, 0, 0, DateTimeKind.Utc);

        booking.TransitionTo(BookingStatus.Confirmed, now);
        Assert.Equal(BookingStatus.Confirmed, booking.Status);
        Assert.Equal(now, booking.ConfirmedAt);

        Assert.Throws<InvalidOperationException>(() => { booking.TransitionTo(BookingStatus.Completed, now); });

        booking.TransitionTo(BookingStatus.InProgress, now);
        booking.TransitionTo(BookingStatus.Completed, now);
        Assert.Equal(now, booking.CompletedAt);
    }

    [Theory]
    [InlineData(48, true, false)]   // ≥ 24h → standard_24h
    [InlineData(10, false, true)]   // < 24h → standard_inside_24h
    [InlineData(-3, false, true)]   // already started → still inside-24h bucket (open lower bound)
    public void Customer_policy_buckets_are_non_overlapping_and_total(double hoursBefore, bool covers24h, bool coversInside)
    {
        var full = new CancellationPolicy { HoursBeforeStartMin = 24, HoursBeforeStartMax = null };
        var inside = new CancellationPolicy { HoursBeforeStartMin = null, HoursBeforeStartMax = 24 };

        Assert.Equal(covers24h, full.Covers(hoursBefore));
        Assert.Equal(coversInside, inside.Covers(hoursBefore));
    }
}
