using Xunit;
using IamService.Domain.AggregatesModel.UserAggregate;

namespace IamService.UnitTests.Domain;

/// <summary>
/// EN: Unit tests for ApplicationUser domain entity.
/// VI: Unit tests cho domain entity ApplicationUser.
/// </summary>
public class ApplicationUserTests
{
    [Fact]
    public void Create_WithValidData_ShouldSetProperties()
    {
        // Arrange
        var email = "test@example.com";
        var firstName = "John";
        var lastName = "Doe";

        // Act
        var user = new ApplicationUser(email, firstName, lastName);

        // Assert
        Assert.Equal(email, user.Email);
        Assert.Equal(firstName, user.FirstName);
        Assert.Equal(lastName, user.LastName);
        Assert.Equal($"{firstName} {lastName}", user.FullName);
        Assert.Equal(UserStatus.Active, user.Status);
        Assert.NotEqual(default, user.CreatedAt);
    }

    [Fact]
    public void Create_WithEmptyEmail_ShouldThrowException()
    {
        // Arrange & Act & Assert
        Assert.Throws<ArgumentException>(() => 
            new ApplicationUser("", "John", "Doe"));
    }

    [Fact]
    public void Create_WithEmptyFirstName_ShouldThrowException()
    {
        // Arrange & Act & Assert
        Assert.Throws<ArgumentException>(() => 
            new ApplicationUser("test@example.com", "", "Doe"));
    }

    [Fact]
    public void Create_WithEmptyLastName_ShouldThrowException()
    {
        // Arrange & Act & Assert
        Assert.Throws<ArgumentException>(() => 
            new ApplicationUser("test@example.com", "John", ""));
    }

    [Fact]
    public void Activate_WithPendingUser_ShouldSetStatusToActive()
    {
        // Arrange
        var user = new ApplicationUser("test@example.com", "John", "Doe");

        // Act
        user.Activate();

        // Assert
        Assert.Equal(UserStatus.Active, user.Status);
    }

    [Fact]
    public void Disable_ShouldSetStatusToDisabled()
    {
        // Arrange
        var user = new ApplicationUser("test@example.com", "John", "Doe");
        user.Activate();

        // Act
        user.Disable();

        // Assert
        Assert.Equal(UserStatus.Disabled, user.Status);
    }

    [Fact]
    public void Lock_ShouldSetStatusToLocked()
    {
        // Arrange
        var user = new ApplicationUser("test@example.com", "John", "Doe");
        user.Activate();

        // Act
        user.Lock();

        // Assert
        Assert.Equal(UserStatus.Locked, user.Status);
    }

    [Fact]
    public void UpdateProfile_WithValidData_ShouldUpdateNames()
    {
        // Arrange
        var user = new ApplicationUser("test@example.com", "John", "Doe");
        var newFirstName = "Jane";
        var newLastName = "Smith";

        // Act
        user.UpdateProfile(newFirstName, newLastName);

        // Assert
        Assert.Equal(newFirstName, user.FirstName);
        Assert.Equal(newLastName, user.LastName);
        Assert.Equal($"{newFirstName} {newLastName}", user.FullName);
    }

    [Fact]
    public void UpdateProfile_WithEmptyFirstName_ShouldThrowException()
    {
        // Arrange
        var user = new ApplicationUser("test@example.com", "John", "Doe");

        // Act & Assert
        Assert.Throws<ArgumentException>(() => 
            user.UpdateProfile("", "Smith"));
    }

    [Fact]
    public void RecordLogin_ShouldUpdateLastLoginAt()
    {
        // Arrange
        var user = new ApplicationUser("test@example.com", "John", "Doe");
        var beforeLogin = DateTime.UtcNow;

        // Act
        user.RecordLogin();

        // Assert
        Assert.NotNull(user.LastLoginAt);
        Assert.True(user.LastLoginAt >= beforeLogin);
    }
}
