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

namespace IamService.UnitTests.Domain.Organizations;

/// <summary>
/// EN: Unit tests for OrganizationSettings value object.
/// VI: Kiểm thử đơn vị cho OrganizationSettings value object.
/// </summary>
public class OrganizationSettingsTests
{
    #region Creation Tests

    [Fact]
    public void Create_DefaultValues_CreatesSettingsWithDefaults()
    {
        // Arrange & Act
        var settings = new OrganizationSettings();

        // Assert
        settings.AllowUserRegistration.Should().BeTrue();
        settings.RequireEmailVerification.Should().BeTrue();
        settings.Require2FA.Should().BeFalse();
        settings.MaxUsersLimit.Should().Be(100);
        settings.CustomDomain.Should().BeNull();
        settings.SessionTimeoutMinutes.Should().Be(60);
    }

    [Fact]
    public void Create_CustomValues_CreatesSettingsWithCustomValues()
    {
        // Arrange & Act
        var settings = new OrganizationSettings(
            allowUserRegistration: false,
            requireEmailVerification: false,
            require2FA: true,
            maxUsersLimit: 500,
            customDomain: "auth.company.com",
            sessionTimeoutMinutes: 30
        );

        // Assert
        settings.AllowUserRegistration.Should().BeFalse();
        settings.RequireEmailVerification.Should().BeFalse();
        settings.Require2FA.Should().BeTrue();
        settings.MaxUsersLimit.Should().Be(500);
        settings.CustomDomain.Should().Be("auth.company.com");
        settings.SessionTimeoutMinutes.Should().Be(30);
    }

    [Fact]
    public void Create_NegativeMaxUsersLimit_ThrowsArgumentException()
    {
        // Arrange & Act
        var act = () => new OrganizationSettings(maxUsersLimit: -1);

        // Assert
        act.Should().Throw<ArgumentException>()
            .WithMessage("*Max users limit*negative*");
    }

    [Theory]
    [InlineData(0)]
    [InlineData(-1)]
    [InlineData(-100)]
    public void Create_InvalidSessionTimeout_ThrowsArgumentException(int timeout)
    {
        // Arrange & Act
        var act = () => new OrganizationSettings(sessionTimeoutMinutes: timeout);

        // Assert
        act.Should().Throw<ArgumentException>()
            .WithMessage("*Session timeout*at least 1 minute*");
    }

    #endregion

    #region Static Factory Tests

    [Fact]
    public void Default_ReturnsDefaultSettings()
    {
        // Arrange & Act
        var settings = OrganizationSettings.Default;

        // Assert
        settings.AllowUserRegistration.Should().BeTrue();
        settings.RequireEmailVerification.Should().BeTrue();
        settings.Require2FA.Should().BeFalse();
        settings.MaxUsersLimit.Should().Be(100);
        settings.CustomDomain.Should().BeNull();
        settings.SessionTimeoutMinutes.Should().Be(60);
    }

    [Fact]
    public void Enterprise_ReturnsEnterpriseSettings()
    {
        // Arrange & Act
        var settings = OrganizationSettings.Enterprise;

        // Assert
        settings.AllowUserRegistration.Should().BeFalse();
        settings.RequireEmailVerification.Should().BeTrue();
        settings.Require2FA.Should().BeTrue();
        settings.MaxUsersLimit.Should().Be(1000);
        settings.CustomDomain.Should().BeNull();
        settings.SessionTimeoutMinutes.Should().Be(30);
    }

    #endregion

    #region Equality Tests (Value Object)

    [Fact]
    public void Equals_SameValues_ReturnsTrue()
    {
        // Arrange
        var settings1 = new OrganizationSettings(
            allowUserRegistration: true,
            requireEmailVerification: true,
            require2FA: false,
            maxUsersLimit: 100,
            customDomain: null,
            sessionTimeoutMinutes: 60
        );
        var settings2 = new OrganizationSettings(
            allowUserRegistration: true,
            requireEmailVerification: true,
            require2FA: false,
            maxUsersLimit: 100,
            customDomain: null,
            sessionTimeoutMinutes: 60
        );

        // Assert
        settings1.Should().Be(settings2);
        settings1.GetHashCode().Should().Be(settings2.GetHashCode());
    }

    [Fact]
    public void Equals_DifferentMaxUsers_ReturnsFalse()
    {
        // Arrange
        var settings1 = new OrganizationSettings(maxUsersLimit: 100);
        var settings2 = new OrganizationSettings(maxUsersLimit: 200);

        // Assert
        settings1.Should().NotBe(settings2);
    }

    [Fact]
    public void Equals_DifferentRequire2FA_ReturnsFalse()
    {
        // Arrange
        var settings1 = new OrganizationSettings(require2FA: true);
        var settings2 = new OrganizationSettings(require2FA: false);

        // Assert
        settings1.Should().NotBe(settings2);
    }

    [Fact]
    public void Equals_DifferentCustomDomain_ReturnsFalse()
    {
        // Arrange
        var settings1 = new OrganizationSettings(customDomain: "domain1.com");
        var settings2 = new OrganizationSettings(customDomain: "domain2.com");

        // Assert
        settings1.Should().NotBe(settings2);
    }

    [Fact]
    public void Equals_DefaultAndEnterprise_ReturnsFalse()
    {
        // Arrange
        var defaultSettings = OrganizationSettings.Default;
        var enterpriseSettings = OrganizationSettings.Enterprise;

        // Assert
        defaultSettings.Should().NotBe(enterpriseSettings);
    }

    #endregion

    #region Immutability Tests

    [Fact]
    public void Settings_AreImmutable()
    {
        // Arrange
        var settings = OrganizationSettings.Default;

        // Act & Assert - Properties should be read-only
        // This test documents that OrganizationSettings is immutable
        settings.AllowUserRegistration.Should().BeTrue();
        // Cannot reassign: settings.AllowUserRegistration = false; // Compile error
    }

    #endregion
}
