using System.ComponentModel.DataAnnotations;
using FsCheck;
using FsCheck.Xunit;
using MilitaryTrainingManagement.Models.DTOs;
using MilitaryTrainingManagement.Models.Entities;

namespace MilitaryTrainingManagement.Tests.Properties;

/// <summary>
/// 必填字段验证属性测试
/// **功能：military-training-material-management，属性7：必填字段验证**
/// **验证需求：需求2.2, 6.1**
/// </summary>
public class RequiredFieldValidationPropertyTests
{
    /// <summary>
    /// 属性7：必填字段验证 - 人员数据
    /// *对于任何*人员数据提交，所有必填字段必须存在且有效，才能接受提交
    /// **验证需求：需求6.1**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Personnel_WithAllRequiredFields_ValidationPasses(
        NonEmptyString name,
        NonEmptyString position,
        NonEmptyString rank)
    {
        // 确保生成的字符串是有效的（非空白字符）
        var validName = SanitizeString(name.Get, 50, 2);
        var validPosition = SanitizeString(position.Get, 100, 1);
        var validRank = SanitizeString(rank.Get, 50, 1);
        
        var request = new CreatePersonnelRequest
        {
            Name = validName,
            Position = validPosition,
            Rank = validRank,
            IdNumber = GenerateValidIdNumber()
        };

        var validationResults = ValidateModel(request);
        return validationResults.Count == 0;
    }

    /// <summary>
    /// 属性7扩展：缺少姓名的人员数据应该验证失败
    /// **验证需求：需求6.1**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Personnel_WithoutName_ValidationFails(
        NonEmptyString position,
        NonEmptyString rank)
    {
        var request = new CreatePersonnelRequest
        {
            Name = "", // 缺少姓名
            Position = TruncateString(position.Get, 100),
            Rank = TruncateString(rank.Get, 50),
            IdNumber = GenerateValidIdNumber()
        };

        var validationResults = ValidateModel(request);
        return validationResults.Any(r => r.MemberNames.Contains("Name"));
    }


    /// <summary>
    /// 属性7扩展：缺少职位的人员数据应该验证失败
    /// **验证需求：需求6.1**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Personnel_WithoutPosition_ValidationFails(
        NonEmptyString name,
        NonEmptyString rank)
    {
        var request = new CreatePersonnelRequest
        {
            Name = TruncateString(name.Get, 50),
            Position = "", // 缺少职位
            Rank = TruncateString(rank.Get, 50),
            IdNumber = GenerateValidIdNumber()
        };

        var validationResults = ValidateModel(request);
        return validationResults.Any(r => r.MemberNames.Contains("Position"));
    }

    /// <summary>
    /// 属性7扩展：缺少军衔的人员数据应该验证失败
    /// **验证需求：需求6.1**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Personnel_WithoutRank_ValidationFails(
        NonEmptyString name,
        NonEmptyString position)
    {
        var request = new CreatePersonnelRequest
        {
            Name = TruncateString(name.Get, 50),
            Position = TruncateString(position.Get, 100),
            Rank = "", // 缺少军衔
            IdNumber = GenerateValidIdNumber()
        };

        var validationResults = ValidateModel(request);
        return validationResults.Any(r => r.MemberNames.Contains("Rank"));
    }

    /// <summary>
    /// 属性7扩展：无效身份证号的人员数据应该验证失败
    /// **验证需求：需求6.1**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Personnel_WithInvalidIdNumber_ValidationFails(
        NonEmptyString name,
        NonEmptyString position,
        NonEmptyString rank)
    {
        var request = new CreatePersonnelRequest
        {
            Name = TruncateString(name.Get, 50),
            Position = TruncateString(position.Get, 100),
            Rank = TruncateString(rank.Get, 50),
            IdNumber = "invalid123" // 无效身份证号
        };

        var validationResults = ValidateModel(request);
        return validationResults.Any(r => r.MemberNames.Contains("IdNumber"));
    }


    /// <summary>
    /// 属性7扩展：物资配额必填字段验证
    /// *对于任何*物资配额创建，物资名称、单位和总配额必须存在且有效
    /// **验证需求：需求2.2**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Allocation_WithAllRequiredFields_IsValid(
        NonEmptyString category,
        NonEmptyString materialName,
        NonEmptyString unit,
        PositiveInt totalQuotaInt)
    {
        // 确保生成的字符串是有效的（非空白字符）
        var validCategory = SanitizeString(category.Get, 100, 1);
        var validMaterialName = SanitizeString(materialName.Get, 200, 1);
        var validUnit = SanitizeString(unit.Get, 50, 1);
        
        var allocation = new MaterialAllocation
        {
            Category = validCategory,
            MaterialName = validMaterialName,
            Unit = validUnit,
            TotalQuota = totalQuotaInt.Get,
            CreatedByUnitId = 1,
            CreatedAt = DateTime.UtcNow
        };

        // 验证所有必填字段都存在且有效
        return !string.IsNullOrWhiteSpace(allocation.Category) &&
               !string.IsNullOrWhiteSpace(allocation.MaterialName) &&
               !string.IsNullOrWhiteSpace(allocation.Unit) &&
               allocation.TotalQuota > 0;
    }

    /// <summary>
    /// 属性7扩展：缺少物资名称的配额应该无效
    /// **验证需求：需求2.2**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Allocation_WithoutMaterialName_IsInvalid(
        NonEmptyString category,
        NonEmptyString unit,
        PositiveInt totalQuotaInt)
    {
        var allocation = new MaterialAllocation
        {
            Category = TruncateString(category.Get, 100),
            MaterialName = "", // 缺少物资名称
            Unit = TruncateString(unit.Get, 50),
            TotalQuota = totalQuotaInt.Get,
            CreatedByUnitId = 1,
            CreatedAt = DateTime.UtcNow
        };

        // 缺少物资名称应该无效
        return string.IsNullOrWhiteSpace(allocation.MaterialName);
    }

    /// <summary>
    /// 属性7扩展：缺少单位的配额应该无效
    /// **验证需求：需求2.2**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Allocation_WithoutUnit_IsInvalid(
        NonEmptyString category,
        NonEmptyString materialName,
        PositiveInt totalQuotaInt)
    {
        var allocation = new MaterialAllocation
        {
            Category = TruncateString(category.Get, 100),
            MaterialName = TruncateString(materialName.Get, 200),
            Unit = "", // 缺少单位
            TotalQuota = totalQuotaInt.Get,
            CreatedByUnitId = 1,
            CreatedAt = DateTime.UtcNow
        };

        // 缺少单位应该无效
        return string.IsNullOrWhiteSpace(allocation.Unit);
    }

    /// <summary>
    /// 属性7扩展：总配额为零或负数的配额应该无效
    /// **验证需求：需求2.2**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Allocation_WithZeroOrNegativeQuota_IsInvalid(
        NonEmptyString category,
        NonEmptyString materialName,
        NonEmptyString unit,
        NegativeInt negativeQuotaInt)
    {
        var allocation = new MaterialAllocation
        {
            Category = TruncateString(category.Get, 100),
            MaterialName = TruncateString(materialName.Get, 200),
            Unit = TruncateString(unit.Get, 50),
            TotalQuota = negativeQuotaInt.Get, // 负数配额
            CreatedByUnitId = 1,
            CreatedAt = DateTime.UtcNow
        };

        // 负数或零配额应该无效
        return allocation.TotalQuota <= 0;
    }

    /// <summary>
    /// 验证模型并返回验证结果
    /// </summary>
    private static List<ValidationResult> ValidateModel(object model)
    {
        var validationResults = new List<ValidationResult>();
        var validationContext = new ValidationContext(model);
        Validator.TryValidateObject(model, validationContext, validationResults, true);
        return validationResults;
    }

    /// <summary>
    /// 生成有效的身份证号（18位）
    /// </summary>
    private static string GenerateValidIdNumber()
    {
        var random = new Random();
        var areaCode = random.Next(110000, 659999).ToString();
        var birthDate = $"{random.Next(1960, 2005)}{random.Next(1, 13):D2}{random.Next(1, 29):D2}";
        var sequence = random.Next(100, 999).ToString();
        var checkDigit = random.Next(0, 10).ToString();
        return areaCode + birthDate + sequence + checkDigit;
    }

    /// <summary>
    /// 截断字符串到指定长度
    /// </summary>
    private static string TruncateString(string input, int maxLength)
    {
        if (string.IsNullOrEmpty(input))
            return input;
        return input.Length <= maxLength ? input : input.Substring(0, maxLength);
    }

    /// <summary>
    /// 清理字符串：移除控制字符，确保最小长度，截断到最大长度
    /// </summary>
    private static string SanitizeString(string input, int maxLength, int minLength)
    {
        if (string.IsNullOrEmpty(input))
            return new string('a', minLength);
        
        // 移除控制字符和空白字符
        var sanitized = new string(input.Where(c => !char.IsControl(c) && !char.IsWhiteSpace(c)).ToArray());
        
        // 如果清理后为空，使用默认值
        if (string.IsNullOrEmpty(sanitized))
            return new string('a', minLength);
        
        // 确保最小长度
        if (sanitized.Length < minLength)
            sanitized = sanitized.PadRight(minLength, 'a');
        
        // 截断到最大长度
        return sanitized.Length <= maxLength ? sanitized : sanitized.Substring(0, maxLength);
    }
}
