using FsCheck;
using FsCheck.Xunit;
using HoneyBox.Admin.Business.Services;
using Xunit;

namespace HoneyBox.Tests.Services;

/// <summary>
/// UploadService 属性测试
/// **Validates: Requirements 1.2, 1.3, 1.4, 1.5**
/// </summary>
public class UploadServicePropertyTests
{
    /// <summary>
    /// 允许的图片扩展名
    /// </summary>
    private static readonly string[] AllowedExtensions = { ".jpg", ".jpeg", ".png", ".gif", ".webp" };

    /// <summary>
    /// 不允许的扩展名示例
    /// </summary>
    private static readonly string[] DisallowedExtensions = { ".txt", ".pdf", ".exe", ".doc", ".html", ".js", ".css", ".zip", ".rar", ".mp4" };

    #region Property 1: 文件格式验证

    /// <summary>
    /// **Feature: image-upload-feature, Property 1: 文件格式验证**
    /// *For any* 上传的文件，如果文件扩展名不在允许列表(jpg, jpeg, png, gif, webp)中，
    /// THE Upload_Service SHALL 返回格式错误。
    /// **Validates: Requirements 1.2, 1.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool InvalidExtension_ShouldBeRejected(PositiveInt seed)
    {
        // 从不允许的扩展名中选择一个
        var extension = DisallowedExtensions[seed.Get % DisallowedExtensions.Length];
        
        // 验证该扩展名被拒绝
        return !UploadService.IsValidExtension(extension);
    }

    /// <summary>
    /// **Feature: image-upload-feature, Property 1: 文件格式验证**
    /// *For any* 允许的图片扩展名，THE Upload_Service SHALL 接受该格式。
    /// **Validates: Requirements 1.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool ValidExtension_ShouldBeAccepted(PositiveInt seed)
    {
        // 从允许的扩展名中选择一个
        var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length];
        
        // 验证该扩展名被接受
        return UploadService.IsValidExtension(extension);
    }

    /// <summary>
    /// **Feature: image-upload-feature, Property 1: 文件格式验证**
    /// *For any* 允许的图片扩展名（大写形式），THE Upload_Service SHALL 接受该格式（大小写不敏感）。
    /// **Validates: Requirements 1.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool ValidExtension_CaseInsensitive_ShouldBeAccepted(PositiveInt seed)
    {
        // 从允许的扩展名中选择一个并转为大写
        var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length].ToUpperInvariant();
        
        // 验证大写扩展名也被接受
        return UploadService.IsValidExtension(extension);
    }

    #endregion

    #region Property 2: 文件大小验证

    /// <summary>
    /// **Feature: image-upload-feature, Property 2: 文件大小验证**
    /// *For any* 上传的文件，如果文件大小超过10MB，THE Upload_Service SHALL 返回大小超限错误。
    /// **Validates: Requirements 1.3**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool FileSizeExceeding10MB_ShouldBeRejected(PositiveInt extraBytes)
    {
        // 10MB + 额外字节
        var maxSize = 10L * 1024 * 1024;
        var fileSize = maxSize + extraBytes.Get;
        
        // 验证超过10MB的文件被拒绝
        return !UploadService.IsValidFileSize(fileSize);
    }

    /// <summary>
    /// **Feature: image-upload-feature, Property 2: 文件大小验证**
    /// *For any* 文件大小在1字节到10MB之间，THE Upload_Service SHALL 接受该文件。
    /// **Validates: Requirements 1.3**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool FileSizeWithin10MB_ShouldBeAccepted(PositiveInt seed)
    {
        // 生成1字节到10MB之间的文件大小
        var maxSize = 10L * 1024 * 1024;
        var fileSize = (seed.Get % maxSize) + 1; // 确保至少1字节
        
        // 验证在范围内的文件被接受
        return UploadService.IsValidFileSize(fileSize);
    }

    /// <summary>
    /// **Feature: image-upload-feature, Property 2: 文件大小验证**
    /// *For any* 文件大小为0或负数，THE Upload_Service SHALL 拒绝该文件。
    /// **Validates: Requirements 1.3**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool ZeroOrNegativeFileSize_ShouldBeRejected(NegativeInt negativeSize)
    {
        // 验证0和负数被拒绝
        return !UploadService.IsValidFileSize(0) && !UploadService.IsValidFileSize(negativeSize.Get);
    }

    #endregion

    #region Property 3: 文件名唯一性

    /// <summary>
    /// **Feature: image-upload-feature, Property 3: 文件名唯一性**
    /// *For any* 两次上传操作，即使上传相同的文件，生成的文件名 SHALL 不同。
    /// **Validates: Requirements 1.5**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool GeneratedFileNames_ShouldBeUnique(PositiveInt seed)
    {
        // 使用相同的原始文件名
        var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length];
        var originalFileName = $"test_file{extension}";
        
        // 生成两个唯一文件名
        var name1 = UploadService.GenerateUniqueFileName(originalFileName);
        var name2 = UploadService.GenerateUniqueFileName(originalFileName);
        
        // 验证两个文件名不同
        return name1 != name2;
    }

    /// <summary>
    /// **Feature: image-upload-feature, Property 3: 文件名唯一性**
    /// *For any* 原始文件名，生成的唯一文件名 SHALL 保留原始扩展名。
    /// **Validates: Requirements 1.5**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool GeneratedFileName_ShouldPreserveExtension(PositiveInt seed)
    {
        // 选择一个扩展名
        var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length];
        var originalFileName = $"original_file_{seed.Get}{extension}";
        
        // 生成唯一文件名
        var uniqueName = UploadService.GenerateUniqueFileName(originalFileName);
        
        // 验证扩展名被保留（转为小写）
        return uniqueName.EndsWith(extension.ToLowerInvariant());
    }

    /// <summary>
    /// **Feature: image-upload-feature, Property 3: 文件名唯一性**
    /// *For any* 大写扩展名的文件，生成的唯一文件名 SHALL 将扩展名转为小写。
    /// **Validates: Requirements 1.5**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool GeneratedFileName_ShouldNormalizeExtensionToLowercase(PositiveInt seed)
    {
        // 选择一个扩展名并转为大写
        var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length].ToUpperInvariant();
        var originalFileName = $"FILE_{seed.Get}{extension}";
        
        // 生成唯一文件名
        var uniqueName = UploadService.GenerateUniqueFileName(originalFileName);
        
        // 验证扩展名被转为小写
        return uniqueName.EndsWith(extension.ToLowerInvariant());
    }

    /// <summary>
    /// **Feature: image-upload-feature, Property 3: 文件名唯一性**
    /// *For any* 多次生成的文件名，所有文件名 SHALL 互不相同。
    /// **Validates: Requirements 1.5**
    /// </summary>
    [Property(MaxTest = 50)]
    public bool MultipleGeneratedFileNames_ShouldAllBeUnique(PositiveInt seed)
    {
        var originalFileName = "test.jpg";
        var generatedNames = new HashSet<string>();
        
        // 生成多个文件名
        var count = (seed.Get % 10) + 5; // 5-14个文件名
        for (var i = 0; i < count; i++)
        {
            var name = UploadService.GenerateUniqueFileName(originalFileName);
            if (!generatedNames.Add(name))
            {
                return false; // 发现重复
            }
        }
        
        return true;
    }

    #endregion
}
