using MiningService.Domain.AggregatesModel.CircleAggregate;
using MiningService.Domain.Exceptions;
using Xunit;

namespace MiningService.UnitTests.Domain;

/// <summary>
/// EN: Unit tests for Circle aggregate.
/// VI: Unit tests cho Circle aggregate.
/// </summary>
public class CircleAggregateTests
{
    [Fact]
    public void Create_WithValidData_ShouldCreateCircle()
    {
        // Arrange
        var ownerId = Guid.NewGuid();
        var name = "Test Circle";

        // Act
        var circle = Circle.Create(ownerId, name);

        // Assert
        Assert.NotEqual(Guid.Empty, circle.Id);
        Assert.Equal(ownerId, circle.OwnerId);
        Assert.Equal(name, circle.Name);
        Assert.Equal(CircleStatus.Incomplete, circle.Status);
        Assert.Equal(1, circle.ActiveMemberCount); // Owner is first member
        Assert.False(circle.IsValid);
    }

    [Fact]
    public void Create_WithEmptyName_ShouldThrow()
    {
        // Act & Assert
        Assert.Throws<CircleDomainException>(() => Circle.Create(Guid.NewGuid(), ""));
    }

    [Fact]
    public void AddMember_UntilValid_ShouldActivateCircle()
    {
        // Arrange
        var circle = Circle.Create(Guid.NewGuid(), "Test");

        // Act
        circle.AddMember(Guid.NewGuid());
        circle.AddMember(Guid.NewGuid());

        // Assert - 3 members (owner + 2) should be valid
        Assert.Equal(3, circle.ActiveMemberCount);
        Assert.Equal(CircleStatus.Active, circle.Status);
        Assert.True(circle.IsValid);
        Assert.Equal(0.25m, circle.BonusMultiplier);
    }

    [Fact]
    public void AddMember_BeyondMax_ShouldThrow()
    {
        // Arrange
        var circle = Circle.Create(Guid.NewGuid(), "Test");
        circle.AddMember(Guid.NewGuid());
        circle.AddMember(Guid.NewGuid());
        circle.AddMember(Guid.NewGuid());
        circle.AddMember(Guid.NewGuid()); // 5 total (max)

        // Act & Assert
        Assert.Throws<CircleDomainException>(() => circle.AddMember(Guid.NewGuid()));
    }

    [Fact]
    public void AddMember_Duplicate_ShouldThrow()
    {
        // Arrange
        var circle = Circle.Create(Guid.NewGuid(), "Test");
        var memberId = Guid.NewGuid();
        circle.AddMember(memberId);

        // Act & Assert
        Assert.Throws<CircleDomainException>(() => circle.AddMember(memberId));
    }

    [Fact]
    public void RemoveMember_ShouldDeactivateMember()
    {
        // Arrange
        var circle = Circle.Create(Guid.NewGuid(), "Test");
        var memberId = Guid.NewGuid();
        circle.AddMember(memberId);
        circle.AddMember(Guid.NewGuid()); // 3 members, now valid

        // Act
        circle.RemoveMember(memberId);

        // Assert - 2 active members, no longer valid
        Assert.Equal(2, circle.ActiveMemberCount);
        Assert.Equal(CircleStatus.Incomplete, circle.Status);
        Assert.False(circle.IsValid);
    }

    [Fact]
    public void RemoveMember_Owner_ShouldThrow()
    {
        // Arrange
        var ownerId = Guid.NewGuid();
        var circle = Circle.Create(ownerId, "Test");

        // Act & Assert
        Assert.Throws<CircleDomainException>(() => circle.RemoveMember(ownerId));
    }

    [Fact]
    public void Disband_ShouldDeactivateAll()
    {
        // Arrange
        var circle = Circle.Create(Guid.NewGuid(), "Test");
        circle.AddMember(Guid.NewGuid());
        circle.AddMember(Guid.NewGuid());

        // Act
        circle.Disband();

        // Assert
        Assert.Equal(CircleStatus.Disbanded, circle.Status);
        Assert.Equal(0, circle.BonusMultiplier);
    }
}
