using FluentAssertions;
using MembershipService.Domain.AggregatesModel.LevelAggregate;
using Xunit;

namespace MembershipService.UnitTests.Domain;

/// <summary>
/// EN: Unit tests for LevelDefinition aggregate.
/// VI: Unit tests cho LevelDefinition aggregate.
/// </summary>
public class LevelDefinitionAggregateTests
{
    [Fact]
    public void Create_WithValidParameters_ShouldCreateLevelDefinition()
    {
        // Arrange & Act
        var level = new LevelDefinition(1, "Bronze", 0, "Starting level");

        // Assert
        level.LevelNumber.Should().Be(1);
        level.Name.Should().Be("Bronze");
        level.RequiredExp.Should().Be(0);
        level.Description.Should().Be("Starting level");
        level.IsActive.Should().BeTrue();
    }

    [Fact]
    public void Create_WithBadgeColor_ShouldSetBadgeColor()
    {
        // Arrange & Act - iconUrl is 5th param, badgeColor is 6th
        var level = new LevelDefinition(1, "Bronze", 0, "Starting level", null, "#CD7F32");

        // Assert
        level.BadgeColor.Should().Be("#CD7F32");
    }

    [Fact]
    public void Create_WithIconUrl_ShouldSetIconUrl()
    {
        // Arrange & Act
        var level = new LevelDefinition(1, "Bronze", 0, "Starting level", "/icons/bronze.png", "#CD7F32");

        // Assert
        level.IconUrl.Should().Be("/icons/bronze.png");
    }

    [Fact]
    public void Create_WithNegativeLevelNumber_ShouldThrow()
    {
        // Act & Assert
        var act = () => new LevelDefinition(-1, "Invalid", 0, "Invalid level");
        act.Should().Throw<ArgumentException>().WithMessage("*must be positive*");
    }

    [Fact]
    public void Create_WithNegativeRequiredExp_ShouldThrow()
    {
        // Act & Assert
        var act = () => new LevelDefinition(1, "Invalid", -100, "Invalid level");
        act.Should().Throw<ArgumentException>().WithMessage("*cannot be negative*");
    }

    [Fact]
    public void Create_WithEmptyName_ShouldThrow()
    {
        // Act & Assert
        var act = () => new LevelDefinition(1, "", 0, "Invalid level");
        act.Should().Throw<ArgumentException>().WithMessage("*cannot be empty*");
    }

    [Fact]
    public void AddBenefit_ValidBenefit_ShouldAddToBenefitsList()
    {
        // Arrange
        var level = new LevelDefinition(2, "Silver", 100, "Silver level");
        var benefit = new LevelBenefit(level.Id, "Discount", "10%", "10% discount on all purchases");

        // Act
        level.AddBenefit(benefit);

        // Assert
        level.Benefits.Should().HaveCount(1);
        level.Benefits.First().BenefitType.Should().Be("Discount");
        level.Benefits.First().BenefitValue.Should().Be("10%");
    }

    [Fact]
    public void AddBenefit_MultipleBenefits_ShouldAddAll()
    {
        // Arrange
        var level = new LevelDefinition(3, "Gold", 300, "Gold level");

        // Act
        level.AddBenefit(new LevelBenefit(level.Id, "Discount", "15%", "15% discount"));
        level.AddBenefit(new LevelBenefit(level.Id, "FreeShipping", "true", "Free shipping"));
        level.AddBenefit(new LevelBenefit(level.Id, "Priority", "high", "Priority support"));

        // Assert
        level.Benefits.Should().HaveCount(3);
    }

    [Fact]
    public void AddBenefit_NullBenefit_ShouldThrow()
    {
        // Arrange
        var level = new LevelDefinition(1, "Bronze", 0, "Starting level");

        // Act & Assert
        var act = () => level.AddBenefit(null!);
        act.Should().Throw<ArgumentNullException>();
    }

    [Fact]
    public void Deactivate_ActiveLevel_ShouldSetIsActiveFalse()
    {
        // Arrange
        var level = new LevelDefinition(1, "Bronze", 0, "Starting level");
        level.IsActive.Should().BeTrue();

        // Act
        level.Deactivate();

        // Assert
        level.IsActive.Should().BeFalse();
    }

    [Fact]
    public void Activate_InactiveLevel_ShouldSetIsActiveTrue()
    {
        // Arrange
        var level = new LevelDefinition(1, "Bronze", 0, "Starting level");
        level.Deactivate();
        level.IsActive.Should().BeFalse();

        // Act
        level.Activate();

        // Assert
        level.IsActive.Should().BeTrue();
    }

    [Fact]
    public void LevelOrdering_ShouldBeByLevelNumber()
    {
        // Arrange
        var levels = new List<LevelDefinition>
        {
            new(3, "Gold", 300, "Gold"),
            new(1, "Bronze", 0, "Bronze"),
            new(5, "Diamond", 1000, "Diamond"),
            new(2, "Silver", 100, "Silver"),
            new(4, "Platinum", 600, "Platinum")
        };

        // Act
        var ordered = levels.OrderBy(l => l.LevelNumber).ToList();

        // Assert
        ordered[0].Name.Should().Be("Bronze");
        ordered[1].Name.Should().Be("Silver");
        ordered[2].Name.Should().Be("Gold");
        ordered[3].Name.Should().Be("Platinum");
        ordered[4].Name.Should().Be("Diamond");
    }

    [Fact]
    public void Benefits_ShouldBeReadOnlyCollection()
    {
        // Arrange
        var level = new LevelDefinition(1, "Bronze", 0, "Starting level");

        // Assert
        level.Benefits.Should().BeAssignableTo<IReadOnlyCollection<LevelBenefit>>();
    }
}
