using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using HoneyBox.Model.Models.Payment;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Core.Services;

/// <summary>
/// 微信支付 V3 服务实现
/// 提供基于 RSA-SHA256 签名和 AES-256-GCM 加密的 V3 版本支付功能
/// </summary>
public class WechatPayV3Service : IWechatPayV3Service
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly HttpClient _httpClient;
    private readonly ILogger<WechatPayV3Service> _logger;
    private readonly IWechatPayConfigService _configService;

    /// <summary>
    /// V3 JSAPI 下单 API 地址
    /// </summary>
    private const string V3_JSAPI_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";

    /// <summary>
    /// V3 订单查询 API 地址（商户订单号）
    /// </summary>
    private const string V3_QUERY_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{0}";

    /// <summary>
    /// V3 关闭订单 API 地址
    /// </summary>
    private const string V3_CLOSE_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{0}/close";

    /// <summary>
    /// V3 退款 API 地址
    /// </summary>
    private const string V3_REFUND_URL = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";

    /// <summary>
    /// 随机字符串字符集
    /// </summary>
    private const string NONCE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    public WechatPayV3Service(
        HoneyBoxDbContext dbContext,
        HttpClient httpClient,
        ILogger<WechatPayV3Service> logger,
        IWechatPayConfigService configService)
    {
        _dbContext = dbContext;
        _httpClient = httpClient;
        _logger = logger;
        _configService = configService;
    }

    #region 下单接口

    /// <inheritdoc />
    public async Task<WechatPayResult> CreateJsapiOrderAsync(WechatPayRequest request)
    {
        try
        {
            _logger.LogInformation("开始创建 V3 JSAPI 支付订单: OrderNo={OrderNo}, UserId={UserId}, Amount={Amount}",
                request.OrderNo, request.UserId, request.Amount);

            // 1. 获取用户信息和 OpenId
            var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == request.UserId);
            if (user == null)
            {
                _logger.LogWarning("用户不存在: UserId={UserId}", request.UserId);
                return new WechatPayResult { Status = 0, Msg = "用户不存在" };
            }

            var openId = string.IsNullOrEmpty(request.OpenId) ? user.OpenId : request.OpenId;
            if (string.IsNullOrEmpty(openId))
            {
                _logger.LogWarning("用户 OpenId 为空: UserId={UserId}", request.UserId);
                return new WechatPayResult { Status = 0, Msg = "用户 OpenId 不存在" };
            }

            // 2. 获取商户配置
            var merchantConfig = _configService.GetMerchantByOrderNo(request.OrderNo);
            
            // 验证 V3 配置
            if (string.IsNullOrEmpty(merchantConfig.ApiV3Key) ||
                string.IsNullOrEmpty(merchantConfig.CertSerialNo) ||
                string.IsNullOrEmpty(merchantConfig.PrivateKeyPath))
            {
                _logger.LogError("V3 配置不完整: MchId={MchId}", merchantConfig.MchId);
                return new WechatPayResult { Status = 0, Msg = "V3 支付配置不完整" };
            }

            _logger.LogDebug("使用 V3 商户配置: MchId={MchId}, AppId={AppId}", merchantConfig.MchId, merchantConfig.AppId);

            // 3. 读取私钥
            var privateKey = ReadPrivateKey(merchantConfig.PrivateKeyPath);
            if (string.IsNullOrEmpty(privateKey))
            {
                _logger.LogError("读取私钥失败: Path={Path}", merchantConfig.PrivateKeyPath);
                return new WechatPayResult { Status = 0, Msg = "读取商户私钥失败" };
            }

            // 4. 构建 V3 请求
            var totalFee = (int)Math.Round(request.Amount * 100); // 转换为分
            var v3Request = new WechatPayV3JsapiRequest
            {
                AppId = merchantConfig.AppId,
                MchId = merchantConfig.MchId,
                Description = TruncateDescription(request.Body, 127),
                OutTradeNo = request.OrderNo,
                NotifyUrl = merchantConfig.NotifyUrl,
                Amount = new WechatPayV3Amount { Total = totalFee, Currency = "CNY" },
                Payer = new WechatPayV3Payer { OpenId = openId },
                Attach = request.Attach
            };

            var requestBody = JsonSerializer.Serialize(v3Request, new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
                DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
            });

            // 5. 生成签名并发送请求
            var timestamp = GetTimestamp();
            var nonceStr = GenerateNonceStr();
            var url = "/v3/pay/transactions/jsapi";
            var signature = GenerateSignature("POST", url, timestamp, nonceStr, requestBody, privateKey);

            // 6. 构建 Authorization 头
            var authorization = $"WECHATPAY2-SHA256-RSA2048 mchid=\"{merchantConfig.MchId}\",nonce_str=\"{nonceStr}\",timestamp=\"{timestamp}\",serial_no=\"{merchantConfig.CertSerialNo}\",signature=\"{signature}\"";

            // 7. 发送请求
            using var httpRequest = new HttpRequestMessage(HttpMethod.Post, V3_JSAPI_URL);
            httpRequest.Headers.Add("Authorization", authorization);
            httpRequest.Headers.Add("Accept", "application/json");
            httpRequest.Headers.Add("User-Agent", "HoneyBox/1.0");
            httpRequest.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");

            _logger.LogDebug("V3 下单请求: URL={Url}, Body={Body}", V3_JSAPI_URL, requestBody);

            var response = await _httpClient.SendAsync(httpRequest);
            var responseContent = await response.Content.ReadAsStringAsync();

            _logger.LogDebug("V3 下单响应: StatusCode={StatusCode}, Body={Body}", response.StatusCode, responseContent);

            // 8. 处理响应
            if (!response.IsSuccessStatusCode)
            {
                var errorResponse = JsonSerializer.Deserialize<WechatPayV3ErrorResponse>(responseContent);
                var errorMsg = GetV3ErrorMessage(errorResponse?.Code ?? "UNKNOWN", errorResponse?.Message ?? "未知错误");
                _logger.LogWarning("V3 下单失败: Code={Code}, Message={Message}", errorResponse?.Code, errorResponse?.Message);
                return new WechatPayResult { Status = 0, Msg = $"支付失败({errorMsg})" };
            }

            var v3Response = JsonSerializer.Deserialize<WechatPayV3JsapiResponse>(responseContent);
            if (v3Response == null || string.IsNullOrEmpty(v3Response.PrepayId))
            {
                _logger.LogError("V3 下单成功但 prepay_id 为空");
                return new WechatPayResult { Status = 0, Msg = "网络故障，请稍后重试(prepay_id为空)" };
            }

            // 9. 保存订单通知记录
            await SaveOrderNotifyAsync(request.OrderNo, merchantConfig.NotifyUrl, nonceStr, request.Amount, request.Attach, openId);

            // 10. 构建返回给前端的支付参数（V3 使用 RSA 签名）
            var payTimestamp = GetTimestamp();
            var payNonceStr = GenerateNonceStr();
            var packageStr = $"prepay_id={v3Response.PrepayId}";
            var paySign = GeneratePaySign(merchantConfig.AppId, payTimestamp, payNonceStr, v3Response.PrepayId, privateKey);

            _logger.LogInformation("V3 支付订单创建成功: OrderNo={OrderNo}, PrepayId={PrepayId}", request.OrderNo, v3Response.PrepayId);

            return new WechatPayResult
            {
                Status = 1,
                Msg = "success",
                Data = new WechatPayData
                {
                    AppId = merchantConfig.AppId,
                    TimeStamp = payTimestamp,
                    NonceStr = payNonceStr,
                    Package = packageStr,
                    SignType = "RSA",
                    PaySign = paySign,
                    IsWeixin = 1
                }
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "创建 V3 支付订单异常: OrderNo={OrderNo}", request.OrderNo);
            return new WechatPayResult { Status = 0, Msg = "系统错误，请稍后重试" };
        }
    }

    #endregion

    #region 订单管理接口

    /// <inheritdoc />
    public async Task<WechatPayV3QueryResult> QueryOrderAsync(string orderNo)
    {
        try
        {
            _logger.LogInformation("开始查询 V3 订单: OrderNo={OrderNo}", orderNo);

            var merchantConfig = _configService.GetMerchantByOrderNo(orderNo);
            var privateKey = ReadPrivateKey(merchantConfig.PrivateKeyPath!);

            var url = $"/v3/pay/transactions/out-trade-no/{orderNo}?mchid={merchantConfig.MchId}";
            var fullUrl = string.Format(V3_QUERY_URL, orderNo) + $"?mchid={merchantConfig.MchId}";

            var timestamp = GetTimestamp();
            var nonceStr = GenerateNonceStr();
            var signature = GenerateSignature("GET", url, timestamp, nonceStr, "", privateKey);

            var authorization = $"WECHATPAY2-SHA256-RSA2048 mchid=\"{merchantConfig.MchId}\",nonce_str=\"{nonceStr}\",timestamp=\"{timestamp}\",serial_no=\"{merchantConfig.CertSerialNo}\",signature=\"{signature}\"";

            using var httpRequest = new HttpRequestMessage(HttpMethod.Get, fullUrl);
            httpRequest.Headers.Add("Authorization", authorization);
            httpRequest.Headers.Add("Accept", "application/json");

            var response = await _httpClient.SendAsync(httpRequest);
            var responseContent = await response.Content.ReadAsStringAsync();

            _logger.LogDebug("V3 订单查询响应: StatusCode={StatusCode}, Body={Body}", response.StatusCode, responseContent);

            if (!response.IsSuccessStatusCode)
            {
                var errorResponse = JsonSerializer.Deserialize<WechatPayV3ErrorResponse>(responseContent);
                return new WechatPayV3QueryResult
                {
                    Success = false,
                    ErrorCode = errorResponse?.Code,
                    ErrorMessage = errorResponse?.Message
                };
            }

            var queryResponse = JsonSerializer.Deserialize<WechatPayV3QueryResponse>(responseContent);
            return new WechatPayV3QueryResult
            {
                Success = true,
                TradeState = queryResponse?.TradeState ?? "",
                TradeStateDesc = queryResponse?.TradeStateDesc ?? "",
                TransactionId = queryResponse?.TransactionId,
                OutTradeNo = queryResponse?.OutTradeNo,
                TotalAmount = queryResponse?.Amount?.Total,
                SuccessTime = queryResponse?.SuccessTime
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "查询 V3 订单异常: OrderNo={OrderNo}", orderNo);
            return new WechatPayV3QueryResult
            {
                Success = false,
                ErrorCode = "SYSTEM_ERROR",
                ErrorMessage = ex.Message
            };
        }
    }

    /// <inheritdoc />
    public async Task<WechatPayV3CloseResult> CloseOrderAsync(string orderNo)
    {
        try
        {
            _logger.LogInformation("开始关闭 V3 订单: OrderNo={OrderNo}", orderNo);

            var merchantConfig = _configService.GetMerchantByOrderNo(orderNo);
            var privateKey = ReadPrivateKey(merchantConfig.PrivateKeyPath!);

            var url = $"/v3/pay/transactions/out-trade-no/{orderNo}/close";
            var fullUrl = string.Format(V3_CLOSE_URL, orderNo);

            var requestBody = JsonSerializer.Serialize(new WechatPayV3CloseRequest { MchId = merchantConfig.MchId });

            var timestamp = GetTimestamp();
            var nonceStr = GenerateNonceStr();
            var signature = GenerateSignature("POST", url, timestamp, nonceStr, requestBody, privateKey);

            var authorization = $"WECHATPAY2-SHA256-RSA2048 mchid=\"{merchantConfig.MchId}\",nonce_str=\"{nonceStr}\",timestamp=\"{timestamp}\",serial_no=\"{merchantConfig.CertSerialNo}\",signature=\"{signature}\"";

            using var httpRequest = new HttpRequestMessage(HttpMethod.Post, fullUrl);
            httpRequest.Headers.Add("Authorization", authorization);
            httpRequest.Headers.Add("Accept", "application/json");
            httpRequest.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");

            var response = await _httpClient.SendAsync(httpRequest);

            _logger.LogDebug("V3 关闭订单响应: StatusCode={StatusCode}", response.StatusCode);

            // HTTP 204 表示成功
            if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
            {
                _logger.LogInformation("V3 订单关闭成功: OrderNo={OrderNo}", orderNo);
                return new WechatPayV3CloseResult { Success = true };
            }

            var responseContent = await response.Content.ReadAsStringAsync();
            var errorResponse = JsonSerializer.Deserialize<WechatPayV3ErrorResponse>(responseContent);
            return new WechatPayV3CloseResult
            {
                Success = false,
                ErrorCode = errorResponse?.Code,
                ErrorMessage = errorResponse?.Message
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "关闭 V3 订单异常: OrderNo={OrderNo}", orderNo);
            return new WechatPayV3CloseResult
            {
                Success = false,
                ErrorCode = "SYSTEM_ERROR",
                ErrorMessage = ex.Message
            };
        }
    }

    #endregion

    #region 退款接口

    /// <inheritdoc />
    public async Task<WechatPayV3RefundResult> RefundAsync(WechatPayV3RefundRequest request)
    {
        try
        {
            _logger.LogInformation("开始 V3 退款: OrderNo={OrderNo}, RefundNo={RefundNo}, RefundAmount={RefundAmount}",
                request.OrderNo, request.RefundNo, request.RefundAmount);

            var merchantConfig = _configService.GetMerchantByOrderNo(request.OrderNo);
            var privateKey = ReadPrivateKey(merchantConfig.PrivateKeyPath!);

            var apiRequest = new WechatPayV3RefundApiRequest
            {
                OutTradeNo = request.OrderNo,
                TransactionId = request.TransactionId,
                OutRefundNo = request.RefundNo,
                Reason = request.Reason,
                NotifyUrl = request.NotifyUrl,
                Amount = new WechatPayV3RefundAmount
                {
                    Refund = request.RefundAmount,
                    Total = request.TotalAmount,
                    Currency = "CNY"
                }
            };

            var requestBody = JsonSerializer.Serialize(apiRequest, new JsonSerializerOptions
            {
                DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
            });

            var url = "/v3/refund/domestic/refunds";
            var timestamp = GetTimestamp();
            var nonceStr = GenerateNonceStr();
            var signature = GenerateSignature("POST", url, timestamp, nonceStr, requestBody, privateKey);

            var authorization = $"WECHATPAY2-SHA256-RSA2048 mchid=\"{merchantConfig.MchId}\",nonce_str=\"{nonceStr}\",timestamp=\"{timestamp}\",serial_no=\"{merchantConfig.CertSerialNo}\",signature=\"{signature}\"";

            using var httpRequest = new HttpRequestMessage(HttpMethod.Post, V3_REFUND_URL);
            httpRequest.Headers.Add("Authorization", authorization);
            httpRequest.Headers.Add("Accept", "application/json");
            httpRequest.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");

            var response = await _httpClient.SendAsync(httpRequest);
            var responseContent = await response.Content.ReadAsStringAsync();

            _logger.LogDebug("V3 退款响应: StatusCode={StatusCode}, Body={Body}", response.StatusCode, responseContent);

            if (!response.IsSuccessStatusCode)
            {
                var errorResponse = JsonSerializer.Deserialize<WechatPayV3ErrorResponse>(responseContent);
                return new WechatPayV3RefundResult
                {
                    Success = false,
                    ErrorCode = errorResponse?.Code,
                    ErrorMessage = errorResponse?.Message
                };
            }

            var refundResponse = JsonSerializer.Deserialize<WechatPayV3RefundApiResponse>(responseContent);
            return new WechatPayV3RefundResult
            {
                Success = true,
                RefundId = refundResponse?.RefundId,
                OutRefundNo = refundResponse?.OutRefundNo,
                Status = refundResponse?.Status,
                RefundAmount = refundResponse?.Amount?.Refund
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "V3 退款异常: OrderNo={OrderNo}", request.OrderNo);
            return new WechatPayV3RefundResult
            {
                Success = false,
                ErrorCode = "SYSTEM_ERROR",
                ErrorMessage = ex.Message
            };
        }
    }

    #endregion

    #region 签名与验签

    /// <inheritdoc />
    public string GenerateSignature(string method, string url, string timestamp, string nonce, string body, string privateKey)
    {
        // 构建签名字符串
        // 格式：HTTP方法\nURL\n时间戳\n随机串\n请求体\n
        var signatureString = $"{method}\n{url}\n{timestamp}\n{nonce}\n{body}\n";

        // 使用 RSA-SHA256 签名
        using var rsa = RSA.Create();
        rsa.ImportFromPem(privateKey);

        var signatureBytes = rsa.SignData(
            Encoding.UTF8.GetBytes(signatureString),
            HashAlgorithmName.SHA256,
            RSASignaturePadding.Pkcs1);

        return Convert.ToBase64String(signatureBytes);
    }

    /// <inheritdoc />
    public bool VerifyNotifySignature(string timestamp, string nonce, string body, string signature, string serialNo)
    {
        try
        {
            _logger.LogDebug("开始验证 V3 回调签名: Timestamp={Timestamp}, Nonce={Nonce}, SerialNo={SerialNo}",
                timestamp, nonce, serialNo);

            // 参数验证
            if (string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce) ||
                string.IsNullOrEmpty(body) || string.IsNullOrEmpty(signature))
            {
                _logger.LogWarning("V3 回调签名验证参数不完整");
                return false;
            }

            // 获取商户配置
            var merchantConfig = _configService.GetDefaultConfig();
            
            if (string.IsNullOrEmpty(merchantConfig.WechatPublicKeyPath))
            {
                _logger.LogError("微信支付公钥路径未配置");
                return false;
            }

            // 验证公钥ID是否匹配（如果配置了）
            if (!string.IsNullOrEmpty(merchantConfig.WechatPublicKeyId) &&
                !string.IsNullOrEmpty(serialNo) &&
                merchantConfig.WechatPublicKeyId != serialNo)
            {
                _logger.LogWarning("微信支付公钥ID不匹配: Expected={Expected}, Actual={Actual}",
                    merchantConfig.WechatPublicKeyId, serialNo);
                // 继续验证，因为可能是微信更换了公钥
            }

            var publicKey = ReadPublicKey(merchantConfig.WechatPublicKeyPath);
            if (string.IsNullOrEmpty(publicKey))
            {
                _logger.LogError("读取微信支付公钥失败: Path={Path}", merchantConfig.WechatPublicKeyPath);
                return false;
            }

            // 构建验签字符串
            // 格式：时间戳\n随机串\n请求体\n
            var verifyString = $"{timestamp}\n{nonce}\n{body}\n";

            using var rsa = RSA.Create();
            rsa.ImportFromPem(publicKey);

            var signatureBytes = Convert.FromBase64String(signature);
            var isValid = rsa.VerifyData(
                Encoding.UTF8.GetBytes(verifyString),
                signatureBytes,
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pkcs1);

            if (isValid)
            {
                _logger.LogDebug("V3 回调签名验证成功");
            }
            else
            {
                _logger.LogWarning("V3 回调签名验证失败");
            }

            return isValid;
        }
        catch (FormatException ex)
        {
            _logger.LogError(ex, "V3 回调签名 Base64 解码失败");
            return false;
        }
        catch (CryptographicException ex)
        {
            _logger.LogError(ex, "V3 回调签名验证加密异常");
            return false;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "验证回调签名异常");
            return false;
        }
    }

    /// <summary>
    /// 使用指定的公钥验证回调签名
    /// </summary>
    /// <param name="timestamp">时间戳</param>
    /// <param name="nonce">随机串</param>
    /// <param name="body">请求体</param>
    /// <param name="signature">签名</param>
    /// <param name="publicKey">公钥 PEM 内容</param>
    /// <returns>签名是否有效</returns>
    public bool VerifyNotifySignatureWithPublicKey(string timestamp, string nonce, string body, string signature, string publicKey)
    {
        try
        {
            if (string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce) ||
                string.IsNullOrEmpty(body) || string.IsNullOrEmpty(signature) ||
                string.IsNullOrEmpty(publicKey))
            {
                return false;
            }

            // 构建验签字符串
            var verifyString = $"{timestamp}\n{nonce}\n{body}\n";

            using var rsa = RSA.Create();
            rsa.ImportFromPem(publicKey);

            var signatureBytes = Convert.FromBase64String(signature);
            return rsa.VerifyData(
                Encoding.UTF8.GetBytes(verifyString),
                signatureBytes,
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pkcs1);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "使用指定公钥验证签名异常");
            return false;
        }
    }

    #endregion

    #region 加解密

    /// <inheritdoc />
    public string DecryptNotifyResource(string ciphertext, string nonce, string associatedData, string apiV3Key)
    {
        try
        {
            _logger.LogDebug("开始解密 V3 回调数据: Nonce={Nonce}, AssociatedData={AssociatedData}",
                nonce, associatedData);

            // 参数验证
            if (string.IsNullOrEmpty(ciphertext))
            {
                throw new ArgumentException("密文不能为空", nameof(ciphertext));
            }
            if (string.IsNullOrEmpty(nonce))
            {
                throw new ArgumentException("随机串不能为空", nameof(nonce));
            }
            if (string.IsNullOrEmpty(apiV3Key))
            {
                throw new ArgumentException("APIv3 密钥不能为空", nameof(apiV3Key));
            }
            if (apiV3Key.Length != 32)
            {
                throw new ArgumentException("APIv3 密钥长度必须为 32 字节", nameof(apiV3Key));
            }

            var ciphertextBytes = Convert.FromBase64String(ciphertext);
            var nonceBytes = Encoding.UTF8.GetBytes(nonce);
            var associatedDataBytes = string.IsNullOrEmpty(associatedData)
                ? Array.Empty<byte>()
                : Encoding.UTF8.GetBytes(associatedData);
            var keyBytes = Encoding.UTF8.GetBytes(apiV3Key);

            // AES-256-GCM 解密
            // 密文最后 16 字节是 authentication tag
            const int tagLength = 16;
            
            if (ciphertextBytes.Length < tagLength)
            {
                throw new ArgumentException("密文长度不足，无法提取认证标签", nameof(ciphertext));
            }

            var actualCiphertext = ciphertextBytes[..^tagLength];
            var tag = ciphertextBytes[^tagLength..];

            using var aesGcm = new AesGcm(keyBytes, tagLength);
            var plaintext = new byte[actualCiphertext.Length];
            aesGcm.Decrypt(nonceBytes, actualCiphertext, tag, plaintext, associatedDataBytes);

            var result = Encoding.UTF8.GetString(plaintext);
            _logger.LogDebug("V3 回调数据解密成功");
            return result;
        }
        catch (FormatException ex)
        {
            _logger.LogError(ex, "V3 回调数据 Base64 解码失败");
            throw new InvalidOperationException("密文 Base64 解码失败", ex);
        }
        catch (CryptographicException ex)
        {
            _logger.LogError(ex, "V3 回调数据解密失败（可能是密钥错误或数据被篡改）");
            throw new InvalidOperationException("解密失败，可能是密钥错误或数据被篡改", ex);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "解密回调数据失败");
            throw;
        }
    }

    /// <summary>
    /// 使用 AES-256-GCM 加密数据（用于测试）
    /// </summary>
    /// <param name="plaintext">明文</param>
    /// <param name="nonce">随机串（12 字节）</param>
    /// <param name="associatedData">附加数据</param>
    /// <param name="apiV3Key">APIv3 密钥（32 字节）</param>
    /// <returns>Base64 编码的密文（包含认证标签）</returns>
    public string EncryptNotifyResource(string plaintext, string nonce, string associatedData, string apiV3Key)
    {
        if (string.IsNullOrEmpty(plaintext))
        {
            throw new ArgumentException("明文不能为空", nameof(plaintext));
        }
        if (string.IsNullOrEmpty(nonce))
        {
            throw new ArgumentException("随机串不能为空", nameof(nonce));
        }
        if (string.IsNullOrEmpty(apiV3Key) || apiV3Key.Length != 32)
        {
            throw new ArgumentException("APIv3 密钥长度必须为 32 字节", nameof(apiV3Key));
        }

        var plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
        var nonceBytes = Encoding.UTF8.GetBytes(nonce);
        var associatedDataBytes = string.IsNullOrEmpty(associatedData)
            ? Array.Empty<byte>()
            : Encoding.UTF8.GetBytes(associatedData);
        var keyBytes = Encoding.UTF8.GetBytes(apiV3Key);

        const int tagLength = 16;
        var ciphertext = new byte[plaintextBytes.Length];
        var tag = new byte[tagLength];

        using var aesGcm = new AesGcm(keyBytes, tagLength);
        aesGcm.Encrypt(nonceBytes, plaintextBytes, ciphertext, tag, associatedDataBytes);

        // 将密文和标签合并
        var result = new byte[ciphertext.Length + tag.Length];
        ciphertext.CopyTo(result, 0);
        tag.CopyTo(result, ciphertext.Length);

        return Convert.ToBase64String(result);
    }

    #endregion

    #region 回调格式识别

    /// <summary>
    /// 检测回调数据是否为 V3 格式
    /// V3 格式特征：JSON 格式且包含 resource 字段
    /// </summary>
    /// <param name="notifyBody">回调请求体</param>
    /// <returns>是否为 V3 格式</returns>
    public bool IsV3NotifyFormat(string notifyBody)
    {
        if (string.IsNullOrWhiteSpace(notifyBody))
        {
            return false;
        }

        var trimmedBody = notifyBody.TrimStart();

        // V3 格式是 JSON，以 { 开头
        if (!trimmedBody.StartsWith('{'))
        {
            return false;
        }

        try
        {
            // 尝试解析为 JSON 并检查是否包含 resource 字段
            using var doc = JsonDocument.Parse(notifyBody);
            var root = doc.RootElement;

            // V3 回调必须包含 resource 字段
            return root.TryGetProperty("resource", out _);
        }
        catch (JsonException)
        {
            // JSON 解析失败，不是 V3 格式
            return false;
        }
    }

    /// <summary>
    /// 检测回调数据是否为 V2 格式
    /// V2 格式特征：XML 格式，以 &lt;xml&gt; 开头
    /// </summary>
    /// <param name="notifyBody">回调请求体</param>
    /// <returns>是否为 V2 格式</returns>
    public bool IsV2NotifyFormat(string notifyBody)
    {
        if (string.IsNullOrWhiteSpace(notifyBody))
        {
            return false;
        }

        var trimmedBody = notifyBody.TrimStart();

        // V2 格式是 XML，以 < 开头
        if (!trimmedBody.StartsWith('<'))
        {
            return false;
        }

        // 检查是否包含 <xml> 标签（不区分大小写）
        return trimmedBody.Contains("<xml>", StringComparison.OrdinalIgnoreCase) ||
               trimmedBody.Contains("<xml ", StringComparison.OrdinalIgnoreCase);
    }

    /// <summary>
    /// 检测回调格式并返回版本
    /// </summary>
    /// <param name="notifyBody">回调请求体</param>
    /// <returns>回调版本：V3、V2 或 Unknown</returns>
    public NotifyVersion DetectNotifyVersion(string notifyBody)
    {
        if (IsV3NotifyFormat(notifyBody))
        {
            return NotifyVersion.V3;
        }

        if (IsV2NotifyFormat(notifyBody))
        {
            return NotifyVersion.V2;
        }

        return NotifyVersion.Unknown;
    }

    #endregion

    #region 辅助方法

    /// <inheritdoc />
    public string GeneratePaySign(string appId, string timestamp, string nonceStr, string prepayId, string privateKey)
    {
        // 小程序调起支付签名字符串
        // 格式：appId\n时间戳\n随机串\nprepay_id=xxx\n
        var signatureString = $"{appId}\n{timestamp}\n{nonceStr}\nprepay_id={prepayId}\n";

        using var rsa = RSA.Create();
        rsa.ImportFromPem(privateKey);

        var signatureBytes = rsa.SignData(
            Encoding.UTF8.GetBytes(signatureString),
            HashAlgorithmName.SHA256,
            RSASignaturePadding.Pkcs1);

        return Convert.ToBase64String(signatureBytes);
    }

    /// <inheritdoc />
    public string GenerateNonceStr(int length = 32)
    {
        var random = new Random();
        var result = new char[length];

        for (int i = 0; i < length; i++)
        {
            result[i] = NONCE_CHARS[random.Next(NONCE_CHARS.Length)];
        }

        return new string(result);
    }

    /// <inheritdoc />
    public string GetTimestamp()
    {
        return DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
    }

    /// <inheritdoc />
    public string ReadPrivateKey(string privateKeyPath)
    {
        try
        {
            // 支持相对路径和绝对路径
            var fullPath = Path.IsPathRooted(privateKeyPath)
                ? privateKeyPath
                : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, privateKeyPath);

            if (!File.Exists(fullPath))
            {
                _logger.LogError("私钥文件不存在: {Path}", fullPath);
                return string.Empty;
            }

            return File.ReadAllText(fullPath);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "读取私钥文件失败: {Path}", privateKeyPath);
            return string.Empty;
        }
    }

    /// <inheritdoc />
    public string ReadPublicKey(string publicKeyPath)
    {
        try
        {
            var fullPath = Path.IsPathRooted(publicKeyPath)
                ? publicKeyPath
                : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, publicKeyPath);

            if (!File.Exists(fullPath))
            {
                _logger.LogError("公钥文件不存在: {Path}", fullPath);
                return string.Empty;
            }

            return File.ReadAllText(fullPath);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "读取公钥文件失败: {Path}", publicKeyPath);
            return string.Empty;
        }
    }

    /// <summary>
    /// 截断商品描述（V3 限制最大 127 字符）
    /// </summary>
    private static string TruncateDescription(string description, int maxLength)
    {
        if (string.IsNullOrEmpty(description))
        {
            return "商品购买";
        }

        return description.Length <= maxLength ? description : description[..maxLength];
    }

    /// <summary>
    /// 保存订单通知记录
    /// </summary>
    private async Task SaveOrderNotifyAsync(string orderNo, string notifyUrl, string nonceStr, decimal amount, string attach, string openId)
    {
        var orderNotify = new OrderNotify
        {
            OrderNo = orderNo,
            NotifyUrl = notifyUrl,
            NonceStr = nonceStr,
            PayTime = DateTime.Now,
            PayAmount = amount,
            Status = 0,
            RetryCount = 0,
            Attach = attach,
            OpenId = openId,
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now
        };

        _dbContext.OrderNotifies.Add(orderNotify);
        await _dbContext.SaveChangesAsync();

        _logger.LogDebug("保存订单通知记录: OrderNo={OrderNo}, NotifyUrl={NotifyUrl}", orderNo, notifyUrl);
    }

    /// <summary>
    /// 获取 V3 错误消息
    /// </summary>
    private static string GetV3ErrorMessage(string code, string message)
    {
        var errorMessages = new Dictionary<string, string>
        {
            { "PARAM_ERROR", "参数错误" },
            { "OUT_TRADE_NO_USED", "订单号已使用" },
            { "ORDER_NOT_EXIST", "订单不存在" },
            { "ORDER_CLOSED", "订单已关闭" },
            { "SIGN_ERROR", "签名错误" },
            { "MCH_NOT_EXISTS", "商户号不存在" },
            { "APPID_MCHID_NOT_MATCH", "AppID和商户号不匹配" },
            { "FREQUENCY_LIMITED", "请求频率超限" },
            { "SYSTEM_ERROR", "系统错误" },
            { "INVALID_REQUEST", "请求参数无效" },
            { "OPENID_MISMATCH", "OpenID不匹配" },
            { "NOAUTH", "商户未开通此接口权限" },
            { "NOT_ENOUGH", "用户账户余额不足" },
            { "TRADE_ERROR", "交易错误" }
        };

        return errorMessages.TryGetValue(code, out var msg) ? msg : message;
    }

    #endregion
}
