using Xunit;
using FluentAssertions;
using IamService.Domain.AggregatesModel.GroupAggregate;

namespace IamService.UnitTests.Domain.Groups;

/// <summary>
/// EN: Unit tests for GroupMember entity.
/// VI: Kiểm thử đơn vị cho entity GroupMember.
/// </summary>
public class GroupMemberTests
{
    private readonly Guid _validGroupId = Guid.NewGuid();
    private readonly Guid _validUserId = Guid.NewGuid();

    #region Creation Tests

    [Fact]
    public void Create_ValidParameters_CreatesGroupMemberWithDefaults()
    {
        // Arrange & Act
        var member = new GroupMember(_validGroupId, _validUserId, GroupRole.Member);

        // Assert
        member.Id.Should().NotBeEmpty();
        member.GroupId.Should().Be(_validGroupId);
        member.UserId.Should().Be(_validUserId);
        member.Role.Should().Be(GroupRole.Member);
        member.JoinedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
        member.AddedByUserId.Should().BeNull();
    }

    [Fact]
    public void Create_WithAddedByUser_SetsAddedByUserId()
    {
        // Arrange
        var addedByUserId = Guid.NewGuid();

        // Act
        var member = new GroupMember(_validGroupId, _validUserId, GroupRole.Member, addedByUserId);

        // Assert
        member.AddedByUserId.Should().Be(addedByUserId);
    }

    [Fact]
    public void Create_WithNullRole_DefaultsToMember()
    {
        // Arrange & Act
        var member = new GroupMember(_validGroupId, _validUserId, null!);

        // Assert
        member.Role.Should().Be(GroupRole.Member);
    }

    [Fact]
    public void Create_EmptyGroupId_ThrowsArgumentException()
    {
        // Arrange & Act
        var act = () => new GroupMember(Guid.Empty, _validUserId, GroupRole.Member);

        // Assert
        act.Should().Throw<ArgumentException>()
            .WithMessage("*Group ID*empty*");
    }

    [Fact]
    public void Create_EmptyUserId_ThrowsArgumentException()
    {
        // Arrange & Act
        var act = () => new GroupMember(_validGroupId, Guid.Empty, GroupRole.Member);

        // Assert
        act.Should().Throw<ArgumentException>()
            .WithMessage("*User ID*empty*");
    }

    #endregion

    #region ChangeRole Tests

    [Fact]
    public void ChangeRole_ValidRole_ChangesRoleAndRoleId()
    {
        // Arrange
        var member = new GroupMember(_validGroupId, _validUserId, GroupRole.Member);

        // Act
        member.ChangeRole(GroupRole.Admin);

        // Assert
        member.Role.Should().Be(GroupRole.Admin);
        member.RoleId.Should().Be(GroupRole.Admin.Id);
    }

    [Fact]
    public void ChangeRole_NullRole_ThrowsArgumentNullException()
    {
        // Arrange
        var member = new GroupMember(_validGroupId, _validUserId, GroupRole.Member);

        // Act
        var act = () => member.ChangeRole(null!);

        // Assert
        act.Should().Throw<ArgumentNullException>();
    }

    #endregion

    #region IsOwner Tests

    [Fact]
    public void IsOwner_WhenOwner_ReturnsTrue()
    {
        // Arrange
        var member = new GroupMember(_validGroupId, _validUserId, GroupRole.Owner);

        // Act & Assert
        member.IsOwner().Should().BeTrue();
    }

    [Theory]
    [InlineData(1)] // Member
    [InlineData(2)] // Admin
    public void IsOwner_WhenNotOwner_ReturnsFalse(int roleId)
    {
        // Arrange
        var role = GroupRole.FromId(roleId);
        var member = new GroupMember(_validGroupId, _validUserId, role!);

        // Act & Assert
        member.IsOwner().Should().BeFalse();
    }

    #endregion

    #region IsAdminOrOwner Tests

    [Theory]
    [InlineData(2)] // Admin
    [InlineData(3)] // Owner
    public void IsAdminOrOwner_WhenAdminOrOwner_ReturnsTrue(int roleId)
    {
        // Arrange
        var role = GroupRole.FromId(roleId);
        var member = new GroupMember(_validGroupId, _validUserId, role!);

        // Act & Assert
        member.IsAdminOrOwner().Should().BeTrue();
    }

    [Fact]
    public void IsAdminOrOwner_WhenMember_ReturnsFalse()
    {
        // Arrange
        var member = new GroupMember(_validGroupId, _validUserId, GroupRole.Member);

        // Act & Assert
        member.IsAdminOrOwner().Should().BeFalse();
    }

    #endregion
}
