using System;
using System.Security.Cryptography;
using System.Text;

namespace Infrastructure.Helpers
{
    /// <summary>
    /// RSA加解密帮助类 (.NET 6 兼容版本)
    /// </summary>
    public class RsaHelper
    {
        /// <summary>
        /// 生成RSA密钥对
        /// </summary>
        /// <returns>包含公钥和私钥的元组</returns>
        public static (string publicKey, string privateKey) GenerateKeyPair()
        {
            using (var rsa = RSA.Create())
            {
                // 设置密钥大小为2048位
                rsa.KeySize = 2048;
                
                // 使用PEM格式导出密钥
                var publicKey = ExportPublicKey(rsa);
                var privateKey = ExportPrivateKey(rsa);
                return (publicKey, privateKey);
            }
        }

        /// <summary>
        /// 使用公钥加密数据
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <param name="publicKey">公钥（PEM格式）</param>
        /// <returns>Base64编码的密文</returns>
        public static string Encrypt(string plainText, string publicKey)
        {
            using (var rsa = RSA.Create())
            {
                ImportPublicKey(rsa, publicKey);
                var data = Encoding.UTF8.GetBytes(plainText);
                var encryptedData = rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1);
                return Convert.ToBase64String(encryptedData);
            }
        }

        /// <summary>
        /// 使用私钥解密数据
        /// </summary>
        /// <param name="cipherText">Base64编码的密文</param>
        /// <param name="privateKey">私钥（PEM格式）</param>
        /// <returns>解密后的明文</returns>
        public static string Decrypt(string cipherText, string privateKey)
        {
            using (var rsa = RSA.Create())
            {
                ImportPrivateKey(rsa, privateKey);
                var data = Convert.FromBase64String(cipherText);
                var decryptedData = rsa.Decrypt(data, RSAEncryptionPadding.Pkcs1);
                return Encoding.UTF8.GetString(decryptedData);
            }
        }

        /// <summary>
        /// 使用私钥签名数据
        /// </summary>
        /// <param name="data">要签名的数据</param>
        /// <param name="privateKey">私钥（PEM格式）</param>
        /// <returns>Base64编码的签名</returns>
        public static string SignData(string data, string privateKey)
        {
            using (var rsa = RSA.Create())
            {
                ImportPrivateKey(rsa, privateKey);
                var dataBytes = Encoding.UTF8.GetBytes(data);
                var signatureBytes = rsa.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
                return Convert.ToBase64String(signatureBytes);
            }
        }

        /// <summary>
        /// 使用公钥验证签名
        /// </summary>
        /// <param name="data">原始数据</param>
        /// <param name="signature">Base64编码的签名</param>
        /// <param name="publicKey">公钥（PEM格式）</param>
        /// <returns>验证是否成功</returns>
        public static bool VerifyData(string data, string signature, string publicKey)
        {
            using (var rsa = RSA.Create())
            {
                ImportPublicKey(rsa, publicKey);
                var dataBytes = Encoding.UTF8.GetBytes(data);
                var signatureBytes = Convert.FromBase64String(signature);
                return rsa.VerifyData(dataBytes, signatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            }
        }

        /// <summary>
        /// 导出公钥为PEM格式
        /// </summary>
        /// <param name="rsa">RSA实例</param>
        /// <returns>PEM格式公钥</returns>
        private static string ExportPublicKey(RSA rsa)
        {
            // 使用SubjectPublicKeyInfo格式导出公钥
            var publicKey = rsa.ExportSubjectPublicKeyInfo();
            return ExportToPem(publicKey, "PUBLIC KEY");
        }

        /// <summary>
        /// 导出私钥为PEM格式
        /// </summary>
        /// <param name="rsa">RSA实例</param>
        /// <returns>PEM格式私钥</returns>
        private static string ExportPrivateKey(RSA rsa)
        {
            // 使用Pkcs8格式导出私钥
            var privateKey = rsa.ExportPkcs8PrivateKey();
            return ExportToPem(privateKey, "PRIVATE KEY");
        }

        /// <summary>
        /// 从PEM格式导入公钥
        /// </summary>
        /// <param name="rsa">RSA实例</param>
        /// <param name="publicKey">PEM格式公钥</param>
        private static void ImportPublicKey(RSA rsa, string publicKey)
        {
            var keyData = ImportFromPem(publicKey);
            // 使用ImportSubjectPublicKeyInfo导入公钥
            rsa.ImportSubjectPublicKeyInfo(keyData, out _);
        }

        /// <summary>
        /// 从PEM格式导入私钥
        /// </summary>
        /// <param name="rsa">RSA实例</param>
        /// <param name="privateKey">PEM格式私钥</param>
        private static void ImportPrivateKey(RSA rsa, string privateKey)
        {
            var keyData = ImportFromPem(privateKey);
            // 使用ImportPkcs8PrivateKey导入私钥
            rsa.ImportPkcs8PrivateKey(keyData, out _);
        }

        /// <summary>
        /// 将字节数组导出为PEM格式
        /// </summary>
        /// <param name="keyData">密钥数据</param>
        /// <param name="type">密钥类型</param>
        /// <returns>PEM格式字符串</returns>
        private static string ExportToPem(byte[] keyData, string type)
        {
            var builder = new StringBuilder();
            builder.AppendLine($"-----BEGIN {type}-----");
            
            var base64String = Convert.ToBase64String(keyData);
            for (int i = 0; i < base64String.Length; i += 64)
            {
                builder.AppendLine(base64String.Substring(i, Math.Min(64, base64String.Length - i)));
            }
            
            builder.AppendLine($"-----END {type}-----");
            return builder.ToString();
        }

        /// <summary>
        /// 从PEM格式导入数据
        /// </summary>
        /// <param name="pemData">PEM格式数据</param>
        /// <returns>密钥字节数组</returns>
        private static byte[] ImportFromPem(string pemData)
        {
            var lines = pemData.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            var base64Data = new StringBuilder();
            
            foreach (var line in lines)
            {
                var trimmedLine = line.Trim();
                if (!trimmedLine.StartsWith("---") && !string.IsNullOrEmpty(trimmedLine))
                {
                    base64Data.Append(trimmedLine);
                }
            }
            
            return Convert.FromBase64String(base64Data.ToString());
        }
    }
}