using FsCheck;
using FsCheck.Xunit;
using HoneyBox.Admin.Business.Models;
using System.Text.Json;
using Xunit;

namespace HoneyBox.Tests.Services;

/// <summary>
/// 响应格式属性测试
/// Property 16: API Response Format Consistency - API响应格式一致性
/// Property 17: Paginated Response Format - 分页响应格式一致性
/// </summary>
public class ResponseFormatPropertyTests
{
    /// <summary>
    /// Property 16: ApiResponse 成功响应格式一致性
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Property16_ApiResponse_Success_HasConsistentFormat(PositiveInt seed)
    {
        var messages = new[] { "success", "操作成功", "OK", "完成" };
        var message = messages[seed.Get % messages.Length];
        
        var response = ApiResponse.Success(message);
        
        return response.Code == 0 &&
               response.Message == message &&
               response.Data == null;
    }

    /// <summary>
    /// Property 16: ApiResponse 带数据的成功响应格式一致性
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Property16_ApiResponse_SuccessWithData_HasConsistentFormat(PositiveInt seed)
    {
        var data = seed.Get;
        var messages = new[] { "success", "操作成功", "OK" };
        var message = messages[seed.Get % messages.Length];
        
        var response = ApiResponse.Success(data, message);
        
        return response.Code == 0 &&
               response.Message == message &&
               response.Data != null &&
               (int)response.Data == data;
    }

    /// <summary>
    /// Property 16: ApiResponse 错误响应格式一致性
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Property16_ApiResponse_Error_HasConsistentFormat(PositiveInt seed)
    {
        var code = (seed.Get % 1000) + 1; // Non-zero code
        var messages = new[] { "error", "失败", "错误" };
        var message = messages[seed.Get % messages.Length];
        
        var response = ApiResponse.Error(code, message);
        
        return response.Code == code &&
               response.Message == message &&
               response.Data == null;
    }

    /// <summary>
    /// Property 16: ApiResponse<T> 泛型成功响应格式一致性
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Property16_GenericApiResponse_Success_HasConsistentFormat(PositiveInt seed)
    {
        var data = seed.Get;
        
        var response = ApiResponse<int>.Success(data);
        
        return response.Code == 0 &&
               response.Message == "success" &&
               response.Data == data;
    }

    /// <summary>
    /// Property 16: ApiResponse<T> 泛型错误响应格式一致性
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Property16_GenericApiResponse_Error_HasConsistentFormat(PositiveInt seed)
    {
        var code = (seed.Get % 1000) + 1;
        var messages = new[] { "error", "失败", "错误" };
        var message = messages[seed.Get % messages.Length];
        
        var response = ApiResponse<int>.Error(code, message);
        
        return response.Code == code &&
               response.Message == message &&
               EqualityComparer<int>.Default.Equals(response.Data, default);
    }

    /// <summary>
    /// Property 17: PagedResult 分页响应格式一致性
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Property17_PagedResult_HasConsistentFormat(PositiveInt seed)
    {
        var page = (seed.Get % 10) + 1;
        var pageSize = (seed.Get % 50) + 1;
        var total = seed.Get % 1000;
        
        var items = Enumerable.Range(1, Math.Min(pageSize, Math.Max(0, total - (page - 1) * pageSize))).ToList();
        var result = new PagedResult<int>
        {
            Page = page,
            PageSize = pageSize,
            Total = total,
            List = items
        };

        // 验证分页结果格式
        return result.Page == page &&
               result.PageSize == pageSize &&
               result.Total == total &&
               result.List != null &&
               result.List.Count <= pageSize;
    }

    /// <summary>
    /// Property 17: PagedResult 总页数计算正确性
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Property17_PagedResult_TotalPages_CalculatedCorrectly(PositiveInt seed)
    {
        var pageSize = (seed.Get % 100) + 1;
        var total = seed.Get % 10000;
        
        var result = new PagedResult<int>
        {
            Page = 1,
            PageSize = pageSize,
            Total = total,
            List = new List<int>()
        };

        var expectedTotalPages = (int)Math.Ceiling((double)total / pageSize);
        return result.TotalPages == expectedTotalPages;
    }

    /// <summary>
    /// Property 17: PagedResult 空结果处理
    /// </summary>
    [Fact]
    public void Property17_PagedResult_EmptyResult_HasCorrectFormat()
    {
        var result = new PagedResult<int>
        {
            Page = 1,
            PageSize = 20,
            Total = 0,
            List = new List<int>()
        };

        Assert.Equal(1, result.Page);
        Assert.Equal(20, result.PageSize);
        Assert.Equal(0, result.Total);
        Assert.Equal(0, result.TotalPages);
        Assert.Empty(result.List);
    }

    /// <summary>
    /// Property 16: BusinessErrorCodes 错误码唯一性
    /// </summary>
    [Fact]
    public void Property16_BusinessErrorCodes_AreUnique()
    {
        var errorCodes = new[]
        {
            BusinessErrorCodes.ValidationFailed,
            BusinessErrorCodes.NotFound,
            BusinessErrorCodes.AuthenticationFailed,
            BusinessErrorCodes.PermissionDenied,
            BusinessErrorCodes.InternalError
        };

        var uniqueCodes = errorCodes.Distinct().ToList();
        Assert.Equal(errorCodes.Length, uniqueCodes.Count);
    }

    /// <summary>
    /// Property 16: BusinessErrorCodes 错误码非零
    /// </summary>
    [Fact]
    public void Property16_BusinessErrorCodes_AreNonZero()
    {
        var errorCodes = new[]
        {
            BusinessErrorCodes.ValidationFailed,
            BusinessErrorCodes.NotFound,
            BusinessErrorCodes.AuthenticationFailed,
            BusinessErrorCodes.PermissionDenied,
            BusinessErrorCodes.InternalError
        };

        foreach (var code in errorCodes)
        {
            Assert.NotEqual(0, code);
        }
    }

    /// <summary>
    /// Property 16: ApiResponse JSON 序列化格式一致性
    /// </summary>
    [Fact]
    public void Property16_ApiResponse_JsonSerialization_HasExpectedFormat()
    {
        var response = ApiResponse.Success("test data", "操作成功");
        var json = JsonSerializer.Serialize(response, new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });

        var doc = JsonDocument.Parse(json);
        var root = doc.RootElement;

        Assert.True(root.TryGetProperty("code", out var codeElement));
        Assert.True(root.TryGetProperty("message", out var messageElement));
        Assert.True(root.TryGetProperty("data", out var dataElement));

        Assert.Equal(0, codeElement.GetInt32());
        Assert.Equal("操作成功", messageElement.GetString());
        Assert.Equal("test data", dataElement.GetString());
    }

    /// <summary>
    /// Property 17: PagedResult JSON 序列化格式一致性
    /// </summary>
    [Fact]
    public void Property17_PagedResult_JsonSerialization_HasExpectedFormat()
    {
        var result = new PagedResult<string>
        {
            Page = 1,
            PageSize = 10,
            Total = 100,
            List = new List<string> { "item1", "item2" }
        };

        var json = JsonSerializer.Serialize(result, new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });

        var doc = JsonDocument.Parse(json);
        var root = doc.RootElement;

        Assert.True(root.TryGetProperty("page", out var pageElement));
        Assert.True(root.TryGetProperty("pageSize", out var pageSizeElement));
        Assert.True(root.TryGetProperty("total", out var totalElement));
        Assert.True(root.TryGetProperty("totalPages", out var totalPagesElement));
        Assert.True(root.TryGetProperty("list", out var listElement));

        Assert.Equal(1, pageElement.GetInt32());
        Assert.Equal(10, pageSizeElement.GetInt32());
        Assert.Equal(100, totalElement.GetInt32());
        Assert.Equal(10, totalPagesElement.GetInt32());
        Assert.Equal(2, listElement.GetArrayLength());
    }
}
