{{!-- SmartStack Validator Test Template --}}
{{!-- Generates unit tests for FluentValidation validators following SmartStack conventions --}}

using FluentAssertions;
using FluentValidation.TestHelper;
using Xunit;
using {{namespace}}.Application.DTOs;
using {{namespace}}.Application.Validators;

namespace {{namespace}}.Tests.Unit.Validators;

/// <summary>
/// Unit tests for <see cref="{{name}}Validator"/>.
/// Follows SmartStack testing conventions: {Method}_When{Condition}_Should{Result}
/// </summary>
public class {{name}}ValidatorTests
{
    private readonly Create{{name}}RequestValidator _createValidator;
    private readonly Update{{name}}RequestValidator _updateValidator;

    public {{name}}ValidatorTests()
    {
        _createValidator = new Create{{name}}RequestValidator();
        _updateValidator = new Update{{name}}RequestValidator();
    }

    #region Create Request - Code Validation

    [Fact]
    public void CreateValidator_WhenCodeIsValid_ShouldNotHaveErrors()
    {
        // Arrange
        var request = new Create{{name}}Request { Code = "VALID-001" };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldNotHaveValidationErrorFor(x => x.Code);
    }

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public void CreateValidator_WhenCodeIsNullOrEmpty_ShouldHaveError(string? invalidCode)
    {
        // Arrange
        var request = new Create{{name}}Request { Code = invalidCode! };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.Code)
            .WithErrorMessage("*required*");
    }

    [Fact]
    public void CreateValidator_WhenCodeExceedsMaxLength_ShouldHaveError()
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = new string('A', 101) // Exceeds 100 char limit
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.Code)
            .WithErrorMessage("*100 characters*");
    }

    [Theory]
    [InlineData("valid-code")]
    [InlineData("VALID_CODE_123")]
    [InlineData("Code.With.Dots")]
    public void CreateValidator_WhenCodeHasValidFormat_ShouldNotHaveErrors(string validCode)
    {
        // Arrange
        var request = new Create{{name}}Request { Code = validCode };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldNotHaveValidationErrorFor(x => x.Code);
    }

    [Theory]
    [InlineData("code with spaces")]
    [InlineData("code<script>")]
    [InlineData("code;drop")]
    public void CreateValidator_WhenCodeHasInvalidCharacters_ShouldHaveError(string invalidCode)
    {
        // Arrange
        var request = new Create{{name}}Request { Code = invalidCode };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.Code)
            .WithErrorMessage("*invalid characters*");
    }

    #endregion

    #region Create Request - Name Validation

    [Fact]
    public void CreateValidator_WhenNameIsValid_ShouldNotHaveErrors()
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            Name = "Valid Name"
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldNotHaveValidationErrorFor(x => x.Name);
    }

    [Fact]
    public void CreateValidator_WhenNameExceedsMaxLength_ShouldHaveError()
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            Name = new string('A', 256) // Exceeds 255 char limit
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.Name)
            .WithErrorMessage("*255 characters*");
    }

    #endregion

    #region Update Request Validation

    [Fact]
    public void UpdateValidator_WhenValidData_ShouldNotHaveErrors()
    {
        // Arrange
        var request = new Update{{name}}Request
        {
            Name = "Updated Name",
            // Add other updatable properties
        };

        // Act
        var result = _updateValidator.TestValidate(request);

        // Assert
        result.ShouldNotHaveAnyValidationErrors();
    }

    [Fact]
    public void UpdateValidator_WhenOptionalFieldsAreNull_ShouldNotHaveErrors()
    {
        // Arrange
        var request = new Update{{name}}Request
        {
            Name = null, // Optional field can be null
        };

        // Act
        var result = _updateValidator.TestValidate(request);

        // Assert
        result.ShouldNotHaveAnyValidationErrors();
    }

    #endregion

    #region Date Validation (if applicable)

    [Fact]
    public void CreateValidator_WhenStartDateIsInPast_ShouldHaveError()
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            StartDate = DateTime.UtcNow.AddDays(-1)
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.StartDate)
            .WithErrorMessage("*future*");
    }

    [Fact]
    public void CreateValidator_WhenEndDateBeforeStartDate_ShouldHaveError()
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            StartDate = DateTime.UtcNow.AddDays(10),
            EndDate = DateTime.UtcNow.AddDays(5)
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.EndDate)
            .WithErrorMessage("*after start date*");
    }

    #endregion

    #region Numeric Validation (if applicable)

    [Theory]
    [InlineData(-1)]
    [InlineData(-100)]
    public void CreateValidator_WhenQuantityIsNegative_ShouldHaveError(int invalidQuantity)
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            Quantity = invalidQuantity
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.Quantity)
            .WithErrorMessage("*greater than*0*");
    }

    [Theory]
    [InlineData(0)]
    [InlineData(1)]
    [InlineData(1000)]
    public void CreateValidator_WhenQuantityIsValid_ShouldNotHaveErrors(int validQuantity)
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            Quantity = validQuantity
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldNotHaveValidationErrorFor(x => x.Quantity);
    }

    #endregion

    #region Email Validation (if applicable)

    [Theory]
    [InlineData("valid@example.com")]
    [InlineData("user.name@domain.org")]
    [InlineData("user+tag@example.co.uk")]
    public void CreateValidator_WhenEmailIsValid_ShouldNotHaveErrors(string validEmail)
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            Email = validEmail
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldNotHaveValidationErrorFor(x => x.Email);
    }

    [Theory]
    [InlineData("invalid")]
    [InlineData("invalid@")]
    [InlineData("@invalid.com")]
    [InlineData("invalid@.com")]
    public void CreateValidator_WhenEmailIsInvalid_ShouldHaveError(string invalidEmail)
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            Email = invalidEmail
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.Email)
            .WithErrorMessage("*valid email*");
    }

    #endregion

    #region Collection Validation (if applicable)

    [Fact]
    public void CreateValidator_WhenItemsCollectionIsEmpty_ShouldHaveError()
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            Items = new List<string>()
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.Items)
            .WithErrorMessage("*at least one item*");
    }

    [Fact]
    public void CreateValidator_WhenItemsExceedMaxCount_ShouldHaveError()
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            Items = Enumerable.Range(1, 101).Select(i => $"Item-{i}").ToList()
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.Items)
            .WithErrorMessage("*maximum*100*");
    }

    #endregion

    #region Cross-Field Validation

    [Fact]
    public void CreateValidator_WhenDependentFieldsMissing_ShouldHaveError()
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            RequiresApproval = true,
            ApproverEmail = null // Required when RequiresApproval is true
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.ApproverEmail)
            .WithErrorMessage("*required when*");
    }

    #endregion

    #region Security Validation

    [Theory]
    [InlineData("<script>alert('xss')</script>")]
    [InlineData("'; DROP TABLE Users; --")]
    [InlineData("{{'{{'}}constructor{{'}}'}}")]
    public void CreateValidator_WhenInputContainsMaliciousContent_ShouldHaveError(string maliciousInput)
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "TEST",
            Description = maliciousInput
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.ShouldHaveValidationErrorFor(x => x.Description)
            .WithErrorMessage("*invalid characters*");
    }

    #endregion

    #region Error Message Format

    [Fact]
    public void CreateValidator_WhenMultipleErrors_ShouldReturnAllErrors()
    {
        // Arrange
        var request = new Create{{name}}Request
        {
            Code = "",     // Invalid
            Name = new string('A', 500), // Too long
        };

        // Act
        var result = _createValidator.TestValidate(request);

        // Assert
        result.Errors.Should().HaveCountGreaterThan(1);
        result.ShouldHaveValidationErrorFor(x => x.Code);
        result.ShouldHaveValidationErrorFor(x => x.Name);
    }

    #endregion
}
