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

namespace IamService.UnitTests.Domain.Groups;

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

    #region Creation Tests

    [Fact]
    public void Create_ValidParameters_CreatesGroupPermission()
    {
        // Arrange & Act
        var permission = new GroupPermission(_validGroupId, "read", "projects/*");

        // Assert
        permission.Id.Should().NotBeEmpty();
        permission.GroupId.Should().Be(_validGroupId);
        permission.Permission.Should().Be("read");
        permission.Resource.Should().Be("projects/*");
        permission.GrantedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
        permission.GrantedByUserId.Should().BeNull();
    }

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

        // Act
        var permission = new GroupPermission(_validGroupId, "write", null, grantedByUserId);

        // Assert
        permission.GrantedByUserId.Should().Be(grantedByUserId);
    }

    [Fact]
    public void Create_NormalizesPermissionToLowercase()
    {
        // Arrange & Act
        var permission = new GroupPermission(_validGroupId, "READ");

        // Assert
        permission.Permission.Should().Be("read");
    }

    [Fact]
    public void Create_TrimsPermissionAndResource()
    {
        // Arrange & Act
        var permission = new GroupPermission(_validGroupId, "  write  ", "  projects/*  ");

        // Assert
        permission.Permission.Should().Be("write");
        permission.Resource.Should().Be("projects/*");
    }

    [Fact]
    public void Create_EmptyGroupId_ThrowsArgumentException()
    {
        // Arrange & Act
        var act = () => new GroupPermission(Guid.Empty, "read");

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

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public void Create_InvalidPermission_ThrowsArgumentException(string? permissionName)
    {
        // Arrange & Act
        var act = () => new GroupPermission(_validGroupId, permissionName!);

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

    #endregion

    #region Matches Tests

    [Fact]
    public void Matches_ExactPermissionMatch_ReturnsTrue()
    {
        // Arrange
        var permission = new GroupPermission(_validGroupId, "read");

        // Act & Assert
        permission.Matches("read").Should().BeTrue();
        permission.Matches("READ").Should().BeTrue(); // Case insensitive
    }

    [Fact]
    public void Matches_DifferentPermission_ReturnsFalse()
    {
        // Arrange
        var permission = new GroupPermission(_validGroupId, "read");

        // Act & Assert
        permission.Matches("write").Should().BeFalse();
    }

    [Fact]
    public void Matches_NoResourceRestriction_MatchesAnyResource()
    {
        // Arrange
        var permission = new GroupPermission(_validGroupId, "read");

        // Act & Assert
        permission.Matches("read", "any/resource").Should().BeTrue();
        permission.Matches("read", "another/path").Should().BeTrue();
    }

    [Fact]
    public void Matches_WildcardResource_MatchesPrefix()
    {
        // Arrange
        var permission = new GroupPermission(_validGroupId, "read", "projects/*");

        // Act & Assert
        permission.Matches("read", "projects/123").Should().BeTrue();
        permission.Matches("read", "projects/456/tasks").Should().BeTrue();
        permission.Matches("read", "users/123").Should().BeFalse();
    }

    [Fact]
    public void Matches_ExactResourceMatch_ReturnsTrue()
    {
        // Arrange
        var permission = new GroupPermission(_validGroupId, "read", "projects/123");

        // Act & Assert
        permission.Matches("read", "projects/123").Should().BeTrue();
        permission.Matches("read", "projects/124").Should().BeFalse();
    }

    [Fact]
    public void Matches_NoResourceRequested_MatchesAny()
    {
        // Arrange
        var permission = new GroupPermission(_validGroupId, "read", "projects/*");

        // Act & Assert
        permission.Matches("read").Should().BeTrue();
        permission.Matches("read", null).Should().BeTrue();
        permission.Matches("read", "").Should().BeTrue();
    }

    #endregion
}
