using FluentAssertions;
using FnbEngine.Domain.AggregatesModel.RecipeAggregate;
using Xunit;

namespace FnbEngine.UnitTests.Domain;

/// <summary>
/// EN: Unit tests for Recipe aggregate behavior.
/// VI: Unit tests cho hanh vi aggregate Recipe.
/// </summary>
public class RecipeTests
{
    private static readonly Guid ValidShopId = Guid.NewGuid();
    private static readonly Guid ValidProductId = Guid.NewGuid();

    [Fact]
    public void Constructor_WithValidData_ShouldCreateActiveRecipe()
    {
        // Act
        var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", "Boil broth for 8 hours", 480);

        // Assert
        recipe.Id.Should().NotBeEmpty();
        recipe.ShopId.Should().Be(ValidShopId);
        recipe.ProductId.Should().Be(ValidProductId);
        recipe.Name.Should().Be("Pho Bo");
        recipe.Instructions.Should().Be("Boil broth for 8 hours");
        recipe.PrepTimeMinutes.Should().Be(480);
        recipe.IsActive.Should().BeTrue();
        recipe.Ingredients.Should().BeEmpty();
        recipe.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
        recipe.UpdatedAt.Should().BeNull();
    }

    [Fact]
    public void Constructor_WithNullInstructions_ShouldAllowNull()
    {
        var recipe = new Recipe(ValidShopId, ValidProductId, "Simple Dish", null, 10);
        recipe.Instructions.Should().BeNull();
    }

    [Fact]
    public void Update_ShouldModifyAllFields()
    {
        // Arrange
        var recipe = new Recipe(ValidShopId, ValidProductId, "Old Name", "Old instructions", 30);
        var newProductId = Guid.NewGuid();

        // Act
        recipe.Update(newProductId, "New Name", "New instructions", 60);

        // Assert
        recipe.ProductId.Should().Be(newProductId);
        recipe.Name.Should().Be("New Name");
        recipe.Instructions.Should().Be("New instructions");
        recipe.PrepTimeMinutes.Should().Be(60);
        recipe.UpdatedAt.Should().NotBeNull();
    }

    [Fact]
    public void AddIngredient_ShouldAppendToIngredientsList()
    {
        // Arrange
        var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", null, 480);

        // Act
        recipe.AddIngredient("Beef bones", 2.0m, "kg", 150_000m);
        recipe.AddIngredient("Rice noodles", 0.5m, "kg", 30_000m);

        // Assert
        recipe.Ingredients.Should().HaveCount(2);
        recipe.Ingredients[0].IngredientName.Should().Be("Beef bones");
        recipe.Ingredients[0].Quantity.Should().Be(2.0m);
        recipe.Ingredients[0].Unit.Should().Be("kg");
        recipe.Ingredients[0].CostPerUnit.Should().Be(150_000m);
        recipe.Ingredients[1].IngredientName.Should().Be("Rice noodles");
    }

    [Fact]
    public void AddIngredient_WithInventoryItemId_ShouldSetCOGSFields()
    {
        // Arrange
        var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", null, 480);
        var inventoryItemId = Guid.NewGuid();

        // Act
        recipe.AddIngredient("Beef", 1.0m, "kg", 200_000m, inventoryItemId, 0.3m);

        // Assert
        var ingredient = recipe.Ingredients.Single();
        ingredient.InventoryItemId.Should().Be(inventoryItemId);
        ingredient.QuantityPerServing.Should().Be(0.3m);
    }

    [Fact]
    public void ClearIngredients_ShouldRemoveAll()
    {
        // Arrange
        var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", null, 480);
        recipe.AddIngredient("Beef bones", 2.0m, "kg", 150_000m);
        recipe.AddIngredient("Noodles", 0.5m, "kg", 30_000m);

        // Act
        recipe.ClearIngredients();

        // Assert
        recipe.Ingredients.Should().BeEmpty();
        recipe.UpdatedAt.Should().NotBeNull();
    }

    [Fact]
    public void Deactivate_ShouldSetIsActiveToFalse()
    {
        // Arrange
        var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", null, 480);

        // Act
        recipe.Deactivate();

        // Assert
        recipe.IsActive.Should().BeFalse();
        recipe.UpdatedAt.Should().NotBeNull();
    }
}
