using FluentAssertions;
using OrderService.Domain.AggregatesModel.OrderAggregate;
using OrderService.Domain.Exceptions;
using Xunit;

namespace OrderService.UnitTests.Domain;

/// <summary>
/// EN: Unit tests for Order aggregate domain behavior.
/// VI: Unit tests cho hành vi domain của aggregate Order.
/// </summary>
public class OrderAggregateTests
{
    [Fact]
    public void CreateOrder_WithValidShopId_ShouldStartInDraftStatus()
    {
        // Arrange
        var shopId = Guid.NewGuid();

        // Act
        var order = new Order(shopId);

        // Assert
        order.Id.Should().NotBe(Guid.Empty);
        order.ShopId.Should().Be(shopId);
        order.Status.Should().Be(OrderStatus.Draft);
        order.TotalAmount.Should().Be(0m);
        order.DomainEvents.Should().NotBeEmpty();
    }

    [Fact]
    public void AddItem_InDraftStatus_ShouldRecalculateTotalAmount()
    {
        // Arrange
        var order = new Order(Guid.NewGuid());
        var firstItem = new OrderItem(Guid.NewGuid(), "Coffee", "PreparedFood", 2, 30_000m);
        var secondItem = new OrderItem(Guid.NewGuid(), "Cake", "PreparedFood", 1, 45_000m);

        // Act
        order.AddItem(firstItem);
        order.AddItem(secondItem);

        // Assert
        order.Items.Should().HaveCount(2);
        order.TotalAmount.Should().Be(105_000m);
    }

    [Fact]
    public void MarkAsValidated_WithoutItems_ShouldThrowDomainException()
    {
        // Arrange
        var order = new Order(Guid.NewGuid());

        // Act
        var act = () => order.MarkAsValidated();

        // Assert
        act.Should().Throw<DomainException>()
            .WithMessage("Cannot validate order with no items");
    }

    [Fact]
    public void FullLifecycle_DraftToCompleted_ShouldUpdateStatusSequentially()
    {
        // Arrange
        var order = new Order(Guid.NewGuid());
        order.AddItem(new OrderItem(Guid.NewGuid(), "Shoes", "Physical", 1, 1_200_000m));

        // Act
        order.MarkAsValidated();
        order.MarkAsPaid("cash", "TXN-TEST-001");
        order.MarkAsProcessing();
        order.MarkAsCompleted();

        // Assert
        order.Status.Should().Be(OrderStatus.Completed);
    }

    [Fact]
    public void Cancel_CompletedOrder_ShouldThrowDomainException()
    {
        // Arrange
        var order = new Order(Guid.NewGuid());
        order.AddItem(new OrderItem(Guid.NewGuid(), "Laptop", "Physical", 1, 25_000_000m));
        order.MarkAsValidated();
        order.MarkAsPaid("cash", "TXN-TEST-001");
        order.MarkAsProcessing();
        order.MarkAsCompleted();

        // Act
        var act = () => order.Cancel("Customer changed mind");

        // Assert
        act.Should().Throw<DomainException>()
            .WithMessage("Cannot cancel completed order");
    }
}
