using System.Security.Cryptography;
using System.Text;
using FsCheck;
using FsCheck.Xunit;
using HoneyBox.Core.Interfaces;
using HoneyBox.Core.Services;
using HoneyBox.Model.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;

namespace HoneyBox.Tests.Services;

/// <summary>
/// 微信支付 V3 解密属性测试
/// **Feature: wechat-pay-v3-upgrade**
/// </summary>
public class WechatPayV3DecryptionPropertyTests
{
    /// <summary>
    /// 生成有效的 32 字节 APIv3 密钥
    /// </summary>
    private static string GenerateApiV3Key()
    {
        const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var random = new Random();
        var result = new char[32];
        for (int i = 0; i < 32; i++)
        {
            result[i] = chars[random.Next(chars.Length)];
        }
        return new string(result);
    }

    /// <summary>
    /// 生成有效的 12 字节 nonce
    /// </summary>
    private static string GenerateNonce()
    {
        const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var random = new Random();
        var result = new char[12];
        for (int i = 0; i < 12; i++)
        {
            result[i] = chars[random.Next(chars.Length)];
        }
        return new string(result);
    }

    private IWechatPayV3Service CreateService()
    {
        var options = new DbContextOptionsBuilder<HoneyBoxDbContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .Options;
        var dbContext = new HoneyBoxDbContext(options);
        var httpClient = new HttpClient();
        var logger = Mock.Of<ILogger<WechatPayV3Service>>();
        var configService = Mock.Of<IWechatPayConfigService>();

        return new WechatPayV3Service(dbContext, httpClient, logger, configService);
    }

    #region Property 9: V3 回调解密 Round-Trip

    /// <summary>
    /// **Feature: wechat-pay-v3-upgrade, Property 9: V3 回调解密 Round-Trip**
    /// *For any* 有效的支付结果数据，使用 AES-256-GCM 加密后再解密，
    /// 应该得到与原始数据等价的结果。
    /// **Validates: Requirements 4.3**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool DecryptRoundTrip_ShouldReturnOriginalData(NonEmptyString plaintext, PositiveInt seed)
    {
        var service = CreateService();

        // 生成固定的密钥和 nonce（基于 seed 确保可重复）
        var random = new Random(seed.Get);
        var apiV3Key = GenerateApiV3KeyWithSeed(random);
        var nonce = GenerateNonceWithSeed(random);
        var associatedData = "transaction";

        // 清理输入（移除可能导致问题的字符）
        var cleanPlaintext = plaintext.Get.Replace("\0", "");
        if (string.IsNullOrEmpty(cleanPlaintext))
        {
            return true; // 跳过空字符串
        }

        try
        {
            // 加密
            var ciphertext = service.EncryptNotifyResource(cleanPlaintext, nonce, associatedData, apiV3Key);

            // 解密
            var decrypted = service.DecryptNotifyResource(ciphertext, nonce, associatedData, apiV3Key);

            // 验证 round-trip
            return cleanPlaintext == decrypted;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// **Feature: wechat-pay-v3-upgrade, Property 9: V3 回调解密 Round-Trip**
    /// *For any* JSON 格式的支付结果数据，加密后再解密应该保持 JSON 结构不变。
    /// **Validates: Requirements 4.3**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool DecryptRoundTrip_JsonData_ShouldPreserveStructure(
        NonEmptyString orderNo,
        NonEmptyString transactionId,
        PositiveInt amount,
        PositiveInt seed)
    {
        var service = CreateService();

        var random = new Random(seed.Get);
        var apiV3Key = GenerateApiV3KeyWithSeed(random);
        var nonce = GenerateNonceWithSeed(random);
        var associatedData = "transaction";

        // 构建类似微信支付回调的 JSON 数据
        var cleanOrderNo = orderNo.Get.Replace("\"", "").Replace("\\", "").Replace("\n", "").Replace("\r", "");
        var cleanTransactionId = transactionId.Get.Replace("\"", "").Replace("\\", "").Replace("\n", "").Replace("\r", "");
        
        var jsonData = $"{{\"out_trade_no\":\"{cleanOrderNo}\",\"transaction_id\":\"{cleanTransactionId}\",\"trade_state\":\"SUCCESS\",\"amount\":{{\"total\":{amount.Get}}}}}";

        try
        {
            // 加密
            var ciphertext = service.EncryptNotifyResource(jsonData, nonce, associatedData, apiV3Key);

            // 解密
            var decrypted = service.DecryptNotifyResource(ciphertext, nonce, associatedData, apiV3Key);

            // 验证 round-trip
            return jsonData == decrypted;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// **Feature: wechat-pay-v3-upgrade, Property 9: V3 回调解密 Round-Trip**
    /// *For any* 有效数据，使用不同的密钥解密应该失败。
    /// **Validates: Requirements 4.3**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Decrypt_WithWrongKey_ShouldFail(NonEmptyString plaintext, PositiveInt seed)
    {
        var service = CreateService();

        var random = new Random(seed.Get);
        var apiV3Key1 = GenerateApiV3KeyWithSeed(random);
        var apiV3Key2 = GenerateApiV3KeyWithSeed(new Random(seed.Get + 1)); // 不同的密钥
        var nonce = GenerateNonceWithSeed(random);
        var associatedData = "transaction";

        // 确保两个密钥不同
        if (apiV3Key1 == apiV3Key2)
        {
            return true; // 跳过相同密钥的情况
        }

        var cleanPlaintext = plaintext.Get.Replace("\0", "");
        if (string.IsNullOrEmpty(cleanPlaintext))
        {
            return true;
        }

        try
        {
            // 使用密钥1加密
            var ciphertext = service.EncryptNotifyResource(cleanPlaintext, nonce, associatedData, apiV3Key1);

            // 使用密钥2解密应该失败
            try
            {
                service.DecryptNotifyResource(ciphertext, nonce, associatedData, apiV3Key2);
                return false; // 如果没有抛出异常，测试失败
            }
            catch (InvalidOperationException)
            {
                return true; // 预期的异常
            }
            catch (CryptographicException)
            {
                return true; // 预期的异常
            }
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// **Feature: wechat-pay-v3-upgrade, Property 9: V3 回调解密 Round-Trip**
    /// *For any* 有效数据，使用不同的 nonce 解密应该失败。
    /// **Validates: Requirements 4.3**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Decrypt_WithWrongNonce_ShouldFail(NonEmptyString plaintext, PositiveInt seed)
    {
        var service = CreateService();

        var random = new Random(seed.Get);
        var apiV3Key = GenerateApiV3KeyWithSeed(random);
        var nonce1 = GenerateNonceWithSeed(random);
        var nonce2 = GenerateNonceWithSeed(new Random(seed.Get + 1)); // 不同的 nonce
        var associatedData = "transaction";

        // 确保两个 nonce 不同
        if (nonce1 == nonce2)
        {
            return true;
        }

        var cleanPlaintext = plaintext.Get.Replace("\0", "");
        if (string.IsNullOrEmpty(cleanPlaintext))
        {
            return true;
        }

        try
        {
            // 使用 nonce1 加密
            var ciphertext = service.EncryptNotifyResource(cleanPlaintext, nonce1, associatedData, apiV3Key);

            // 使用 nonce2 解密应该失败
            try
            {
                service.DecryptNotifyResource(ciphertext, nonce2, associatedData, apiV3Key);
                return false;
            }
            catch (InvalidOperationException)
            {
                return true;
            }
            catch (CryptographicException)
            {
                return true;
            }
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// **Feature: wechat-pay-v3-upgrade, Property 9: V3 回调解密 Round-Trip**
    /// *For any* 有效数据，篡改密文后解密应该失败。
    /// **Validates: Requirements 4.3**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool Decrypt_WithTamperedCiphertext_ShouldFail(NonEmptyString plaintext, PositiveInt seed)
    {
        var service = CreateService();

        var random = new Random(seed.Get);
        var apiV3Key = GenerateApiV3KeyWithSeed(random);
        var nonce = GenerateNonceWithSeed(random);
        var associatedData = "transaction";

        var cleanPlaintext = plaintext.Get.Replace("\0", "");
        if (string.IsNullOrEmpty(cleanPlaintext))
        {
            return true;
        }

        try
        {
            // 加密
            var ciphertext = service.EncryptNotifyResource(cleanPlaintext, nonce, associatedData, apiV3Key);

            // 篡改密文（修改一个字符）
            var ciphertextBytes = Convert.FromBase64String(ciphertext);
            if (ciphertextBytes.Length > 0)
            {
                ciphertextBytes[0] = (byte)(ciphertextBytes[0] ^ 0xFF);
            }
            var tamperedCiphertext = Convert.ToBase64String(ciphertextBytes);

            // 解密篡改后的密文应该失败
            try
            {
                service.DecryptNotifyResource(tamperedCiphertext, nonce, associatedData, apiV3Key);
                return false;
            }
            catch (InvalidOperationException)
            {
                return true;
            }
            catch (CryptographicException)
            {
                return true;
            }
        }
        catch
        {
            return false;
        }
    }

    #endregion

    #region 辅助方法

    private static string GenerateApiV3KeyWithSeed(Random random)
    {
        const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var result = new char[32];
        for (int i = 0; i < 32; i++)
        {
            result[i] = chars[random.Next(chars.Length)];
        }
        return new string(result);
    }

    private static string GenerateNonceWithSeed(Random random)
    {
        const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var result = new char[12];
        for (int i = 0; i < 12; i++)
        {
            result[i] = chars[random.Next(chars.Length)];
        }
        return new string(result);
    }

    #endregion

    #region 边界情况测试

    /// <summary>
    /// **Feature: wechat-pay-v3-upgrade, Property 9: V3 回调解密 Round-Trip**
    /// 空的 associated data 应该正常工作。
    /// **Validates: Requirements 4.3**
    /// </summary>
    [Fact]
    public void DecryptRoundTrip_EmptyAssociatedData_ShouldWork()
    {
        var service = CreateService();
        var apiV3Key = "d1cxc0vXCUH2984901DxddPJMYqcwcnd";
        var nonce = "abcdefghijkl";
        var plaintext = "{\"out_trade_no\":\"TEST123\",\"trade_state\":\"SUCCESS\"}";

        // 加密（空 associated data）
        var ciphertext = service.EncryptNotifyResource(plaintext, nonce, "", apiV3Key);

        // 解密
        var decrypted = service.DecryptNotifyResource(ciphertext, nonce, "", apiV3Key);

        Assert.Equal(plaintext, decrypted);
    }

    /// <summary>
    /// **Feature: wechat-pay-v3-upgrade, Property 9: V3 回调解密 Round-Trip**
    /// 中文内容应该正常加解密。
    /// **Validates: Requirements 4.3**
    /// </summary>
    [Fact]
    public void DecryptRoundTrip_ChineseContent_ShouldWork()
    {
        var service = CreateService();
        var apiV3Key = "d1cxc0vXCUH2984901DxddPJMYqcwcnd";
        var nonce = "abcdefghijkl";
        var plaintext = "{\"description\":\"商品购买-测试商品\",\"trade_state_desc\":\"支付成功\"}";

        // 加密
        var ciphertext = service.EncryptNotifyResource(plaintext, nonce, "transaction", apiV3Key);

        // 解密
        var decrypted = service.DecryptNotifyResource(ciphertext, nonce, "transaction", apiV3Key);

        Assert.Equal(plaintext, decrypted);
    }

    /// <summary>
    /// **Feature: wechat-pay-v3-upgrade, Property 9: V3 回调解密 Round-Trip**
    /// 无效的 APIv3 密钥长度应该抛出异常。
    /// **Validates: Requirements 4.3**
    /// </summary>
    [Fact]
    public void Decrypt_InvalidKeyLength_ShouldThrow()
    {
        var service = CreateService();
        var invalidKey = "shortkey"; // 不是 32 字节
        var nonce = "abcdefghijkl";
        var ciphertext = "dGVzdA=="; // 随便一个 base64

        Assert.Throws<ArgumentException>(() =>
            service.DecryptNotifyResource(ciphertext, nonce, "transaction", invalidKey));
    }

    /// <summary>
    /// **Feature: wechat-pay-v3-upgrade, Property 9: V3 回调解密 Round-Trip**
    /// 空密文应该抛出异常。
    /// **Validates: Requirements 4.3**
    /// </summary>
    [Fact]
    public void Decrypt_EmptyCiphertext_ShouldThrow()
    {
        var service = CreateService();
        var apiV3Key = "d1cxc0vXCUH2984901DxddPJMYqcwcnd";
        var nonce = "abcdefghijkl";

        Assert.Throws<ArgumentException>(() =>
            service.DecryptNotifyResource("", nonce, "transaction", apiV3Key));
    }

    #endregion
}
