{{!-- SmartStack Entity Test Template --}}
{{!-- Generates unit tests for domain entities following SmartStack conventions --}}

using FluentAssertions;
using Xunit;
using {{namespace}}.Domain.Entities;

namespace {{namespace}}.Tests.Unit.Domain;

/// <summary>
/// Unit tests for <see cref="{{name}}"/> entity.
/// Follows SmartStack testing conventions: {Method}_When{Condition}_Should{Result}
/// </summary>
public class {{name}}Tests
{
    #region Factory Method Tests

    [Fact]
    public void Create_WhenValidData_ShouldCreateEntity()
    {
        // Arrange
        {{#unless isSystemEntity}}
        var tenantId = Guid.NewGuid();
        {{/unless}}
        var code = "TEST-001";
        var createdBy = "test@example.com";

        // Act
        var result = {{name}}.Create({{#unless isSystemEntity}}tenantId, {{/unless}}code, createdBy);

        // Assert
        result.Should().NotBeNull();
        result.Code.Should().Be(code);
        {{#unless isSystemEntity}}
        result.TenantId.Should().Be(tenantId);
        {{/unless}}
        result.CreatedBy.Should().Be(createdBy);
        result.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
    }

    {{#unless isSystemEntity}}
    [Fact]
    public void Create_WhenEmptyTenantId_ShouldThrowException()
    {
        // Arrange
        var tenantId = Guid.Empty;
        var code = "TEST-001";

        // Act
        var act = () => {{name}}.Create(tenantId, code);

        // Assert
        act.Should().Throw<ArgumentException>()
           .WithMessage("*TenantId*");
    }
    {{/unless}}

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public void Create_WhenInvalidCode_ShouldThrowException(string? invalidCode)
    {
        // Arrange
        {{#unless isSystemEntity}}
        var tenantId = Guid.NewGuid();
        {{/unless}}

        // Act
        var act = () => {{name}}.Create({{#unless isSystemEntity}}tenantId, {{/unless}}invalidCode!);

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

    #endregion

    #region Update Tests

    [Fact]
    public void Update_WhenValidData_ShouldUpdateEntity()
    {
        // Arrange
        var entity = CreateValid{{name}}();
        var updatedBy = "updater@example.com";

        // Act
        entity.Update(updatedBy);

        // Assert
        entity.UpdatedBy.Should().Be(updatedBy);
        entity.UpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
    }

    #endregion

    {{#if includeSoftDelete}}
    #region Soft Delete Tests

    [Fact]
    public void SoftDelete_WhenNotDeleted_ShouldMarkAsDeleted()
    {
        // Arrange
        var entity = CreateValid{{name}}();
        var deletedBy = "deleter@example.com";

        // Act
        entity.SoftDelete(deletedBy);

        // Assert
        entity.IsDeleted.Should().BeTrue();
        entity.DeletedBy.Should().Be(deletedBy);
        entity.DeletedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
    }

    [Fact]
    public void SoftDelete_WhenAlreadyDeleted_ShouldThrowException()
    {
        // Arrange
        var entity = CreateValid{{name}}();
        entity.SoftDelete("first@example.com");

        // Act
        var act = () => entity.SoftDelete("second@example.com");

        // Assert
        act.Should().Throw<InvalidOperationException>()
           .WithMessage("*already deleted*");
    }

    [Fact]
    public void Restore_WhenDeleted_ShouldRestoreEntity()
    {
        // Arrange
        var entity = CreateValid{{name}}();
        entity.SoftDelete("deleter@example.com");
        var restoredBy = "restorer@example.com";

        // Act
        entity.Restore(restoredBy);

        // Assert
        entity.IsDeleted.Should().BeFalse();
        entity.DeletedBy.Should().BeNull();
        entity.DeletedAt.Should().BeNull();
        entity.UpdatedBy.Should().Be(restoredBy);
    }

    #endregion
    {{/if}}

    {{#if includeAudit}}
    #region Audit Trail Tests

    [Fact]
    public void Create_ShouldSetAuditFields()
    {
        // Arrange
        {{#unless isSystemEntity}}
        var tenantId = Guid.NewGuid();
        {{/unless}}
        var createdBy = "creator@example.com";

        // Act
        var entity = {{name}}.Create({{#unless isSystemEntity}}tenantId, {{/unless}}"TEST", createdBy);

        // Assert
        entity.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
        entity.CreatedBy.Should().Be(createdBy);
        entity.UpdatedAt.Should().BeNull();
        entity.UpdatedBy.Should().BeNull();
    }

    [Fact]
    public void Update_ShouldSetUpdateAuditFields()
    {
        // Arrange
        var entity = CreateValid{{name}}();
        var originalCreatedAt = entity.CreatedAt;
        var originalCreatedBy = entity.CreatedBy;
        var updatedBy = "updater@example.com";

        // Act
        entity.Update(updatedBy);

        // Assert
        entity.CreatedAt.Should().Be(originalCreatedAt);
        entity.CreatedBy.Should().Be(originalCreatedBy);
        entity.UpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
        entity.UpdatedBy.Should().Be(updatedBy);
    }

    #endregion
    {{/if}}

    {{#unless isSystemEntity}}
    #region Tenant Isolation Tests

    [Fact]
    public void TenantId_ShouldBeImmutable()
    {
        // Arrange
        var tenantId = Guid.NewGuid();
        var entity = {{name}}.Create(tenantId, "TEST");

        // Assert - TenantId should not have a public setter
        typeof({{name}}).GetProperty("TenantId")!
            .SetMethod.Should().BeNull("TenantId should be immutable");
    }

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

        // Act
        var entity = {{name}}.Create(tenantId, "TEST");

        // Assert
        entity.TenantId.Should().Be(tenantId);
    }

    #endregion
    {{/unless}}

    #region Helper Methods

    private static {{name}} CreateValid{{name}}()
    {
        {{#if isSystemEntity}}
        return {{name}}.Create("TEST-001", "test@example.com");
        {{else}}
        return {{name}}.Create(Guid.NewGuid(), "TEST-001", "test@example.com");
        {{/if}}
    }

    #endregion
}
