using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants;
using ColaFlow.Modules.Identity.Domain.Aggregates.Users;
using FluentAssertions;
using Xunit;

namespace ColaFlow.Modules.Identity.Domain.Tests.Entities;

public sealed class UserTenantRoleTests
{
    private readonly UserId _userId = UserId.CreateUnique();
    private readonly TenantId _tenantId = TenantId.CreateUnique();
    private readonly Guid _assignedByUserId = Guid.NewGuid();

    [Fact]
    public void Create_WithValidData_ShouldSucceed()
    {
        // Arrange & Act
        var userTenantRole = UserTenantRole.Create(
            _userId,
            _tenantId,
            TenantRole.TenantMember,
            _assignedByUserId);

        // Assert
        userTenantRole.Should().NotBeNull();
        userTenantRole.Id.Should().NotBe(Guid.Empty);
        userTenantRole.UserId.Should().Be(_userId);
        userTenantRole.TenantId.Should().Be(_tenantId);
        userTenantRole.Role.Should().Be(TenantRole.TenantMember);
        userTenantRole.AssignedByUserId.Should().Be(_assignedByUserId);
        userTenantRole.AssignedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
    }

    [Fact]
    public void Create_WithoutAssignedByUserId_ShouldSucceed()
    {
        // Arrange & Act
        var userTenantRole = UserTenantRole.Create(
            _userId,
            _tenantId,
            TenantRole.TenantAdmin);

        // Assert
        userTenantRole.Should().NotBeNull();
        userTenantRole.AssignedByUserId.Should().BeNull();
    }

    [Fact]
    public void UpdateRole_WithValidRole_ShouldUpdate()
    {
        // Arrange
        var userTenantRole = UserTenantRole.Create(
            _userId,
            _tenantId,
            TenantRole.TenantMember);
        var originalAssignedAt = userTenantRole.AssignedAt;
        var updatedByUserId = Guid.NewGuid();

        // Act
        userTenantRole.UpdateRole(TenantRole.TenantAdmin, updatedByUserId);

        // Assert
        userTenantRole.Role.Should().Be(TenantRole.TenantAdmin);
        userTenantRole.AssignedByUserId.Should().Be(updatedByUserId);
        userTenantRole.AssignedAt.Should().Be(originalAssignedAt); // AssignedAt should NOT change
    }

    [Fact]
    public void UpdateRole_WithSameRole_ShouldBeIdempotent()
    {
        // Arrange
        var userTenantRole = UserTenantRole.Create(
            _userId,
            _tenantId,
            TenantRole.TenantMember,
            _assignedByUserId);
        var originalAssignedByUserId = userTenantRole.AssignedByUserId;
        var originalRole = userTenantRole.Role;

        // Act
        userTenantRole.UpdateRole(TenantRole.TenantMember, Guid.NewGuid());

        // Assert - Should not update if role is the same
        userTenantRole.Role.Should().Be(originalRole);
        userTenantRole.AssignedByUserId.Should().Be(originalAssignedByUserId);
    }

    [Fact]
    public void HasPermission_WithTenantOwner_ShouldReturnTrueForAllPermissions()
    {
        // Arrange
        var userTenantRole = UserTenantRole.Create(
            _userId,
            _tenantId,
            TenantRole.TenantOwner);

        // Act & Assert
        userTenantRole.HasPermission("read_projects").Should().BeTrue();
        userTenantRole.HasPermission("write_projects").Should().BeTrue();
        userTenantRole.HasPermission("delete_projects").Should().BeTrue();
        userTenantRole.HasPermission("any_permission").Should().BeTrue();
    }

    [Fact]
    public void HasPermission_WithAIAgent_ShouldReturnTrueForReadAndPreview()
    {
        // Arrange
        var userTenantRole = UserTenantRole.Create(
            _userId,
            _tenantId,
            TenantRole.AIAgent);

        // Act & Assert
        userTenantRole.HasPermission("read_projects").Should().BeTrue();
        userTenantRole.HasPermission("read_users").Should().BeTrue();
        userTenantRole.HasPermission("write_preview_changes").Should().BeTrue();
        userTenantRole.HasPermission("write_direct_changes").Should().BeFalse();
        userTenantRole.HasPermission("delete_projects").Should().BeFalse();
    }
}
