using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Infrastructure.Helpers
{
    public class SM4CryptoHelper
    {
        const int SM4_KEY_SIZE = 128 / 8; // 16 bytes
        const int BLOCK_SIZE = 16; // SM4 block size is 16 bytes

        #region 随机密钥
        /// <summary>
        /// sm4 随机密钥
        /// </summary>
        /// <returns></returns>
        public static byte[] GenerateSM4Key()
        {
            using (var rng = RandomNumberGenerator.Create())
            {
                byte[] key = new byte[SM4_KEY_SIZE];
                rng.GetBytes(key);
                return key;
            }
        }
        #endregion

        #region CBC模式，PKCS7填充
        // 生成随机IV
        public static byte[] GenerateIV()
        {
            using (var rng = RandomNumberGenerator.Create())
            {
                byte[] iv = new byte[BLOCK_SIZE];
                rng.GetBytes(iv);
                return iv;
            }
        }

        // SM4加密 (CBC模式，PKCS7填充)
        public static byte[] SM4Encrypt(byte[] key, byte[] iv, byte[] plaintext)
        {
            // 创建加密器
            var engine = new SM4Engine();
            var blockCipher = new CbcBlockCipher(engine);
            var cipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
            var keyParam = new KeyParameter(key);
            var keyParamWithIv = new ParametersWithIV(keyParam, iv);

            // 初始化加密器
            cipher.Init(true, keyParamWithIv);

            // 处理数据
            byte[] output = new byte[cipher.GetOutputSize(plaintext.Length)];
            int len = cipher.ProcessBytes(plaintext, 0, plaintext.Length, output, 0);
            len += cipher.DoFinal(output, len);

            // 返回正确长度的密文
            if (len < output.Length)
            {
                byte[] result = new byte[len];
                Array.Copy(output, 0, result, 0, len);
                return result;
            }

            return output;
        }

        // SM4解密 (CBC模式，PKCS7填充)
        public static byte[] SM4Decrypt(byte[] key, byte[] iv, byte[] ciphertext)
        {
            // 创建解密器
            var engine = new SM4Engine();
            var blockCipher = new CbcBlockCipher(engine);
            var cipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
            var keyParam = new KeyParameter(key);
            var keyParamWithIv = new ParametersWithIV(keyParam, iv);

            // 初始化解密器
            cipher.Init(false, keyParamWithIv);

            // 处理数据
            byte[] output = new byte[cipher.GetOutputSize(ciphertext.Length)];
            int len = cipher.ProcessBytes(ciphertext, 0, ciphertext.Length, output, 0);
            len += cipher.DoFinal(output, len);

            // 返回正确长度的明文
            if (len < output.Length)
            {
                byte[] result = new byte[len];
                Array.Copy(output, 0, result, 0, len);
                return result;
            }

            return output;
        }
        #endregion

        #region ECB加密(PKCS#7填充)
        // SM4 ECB加密(PKCS#7填充)
        public static byte[] Encrypt(byte[] key, byte[] plaintext)
        {
            if (key == null || key.Length != BLOCK_SIZE)
                throw new ArgumentException("Key must be 16 bytes (128 bits)");

            // 创建加密器
            var engine = new SM4Engine();
            var cipher = new PaddedBufferedBlockCipher(engine, new Pkcs7Padding());
            cipher.Init(true, new KeyParameter(key));

            // 处理数据
            byte[] output = new byte[cipher.GetOutputSize(plaintext.Length)];
            int len = cipher.ProcessBytes(plaintext, 0, plaintext.Length, output, 0);
            len += cipher.DoFinal(output, len);

            // 返回正确长度的密文
            if (len < output.Length)
            {
                byte[] result = new byte[len];
                Buffer.BlockCopy(output, 0, result, 0, len);
                return result;
            }

            return output;
        }

        // SM4 ECB解密(PKCS#7填充)
        public static byte[] Decrypt(byte[] key, byte[] ciphertext)
        {
            if (key == null || key.Length != BLOCK_SIZE)
                throw new ArgumentException("Key must be 16 bytes (128 bits)");

            // 创建解密器
            var engine = new SM4Engine();
            var cipher = new PaddedBufferedBlockCipher(engine, new Pkcs7Padding());
            cipher.Init(false, new KeyParameter(key));

            // 处理数据
            byte[] output = new byte[cipher.GetOutputSize(ciphertext.Length)];
            int len = cipher.ProcessBytes(ciphertext, 0, ciphertext.Length, output, 0);
            len += cipher.DoFinal(output, len);

            // 返回正确长度的明文
            if (len < output.Length)
            {
                byte[] result = new byte[len];
                Buffer.BlockCopy(output, 0, result, 0, len);
                return result;
            }

            return output;
        }
        #endregion

        //// SM2加密
        //public static byte[] SM2Encrypt(byte[] publicKey, byte[] data)
        //{
        //    var curve = Org.BouncyCastle.Asn1.GM.GMNamedCurves.GetByName("sm2p256v1");
        //    var domainParams = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H);

        //    var q = curve.Curve.DecodePoint(publicKey);
        //    var pubKey = new ECPublicKeyParameters(q, domainParams);

        //    var cipher = new SM2Engine(new SM3Digest());
        //    cipher.Init(true, new ParametersWithRandom(pubKey, new SecureRandom()));

        //    return cipher.ProcessBlock(data, 0, data.Length);
        //}

        //// SM2解密
        //public static byte[] SM2Decrypt(byte[] privateKey, byte[] encryptedData)
        //{
        //    var curve = Org.BouncyCastle.Asn1.GM.GMNamedCurves.GetByName("sm2p256v1");
        //    var domainParams = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H);

        //    var d = new BigInteger(1, privateKey);
        //    var privKey = new ECPrivateKeyParameters(d, domainParams);

        //    var cipher = new SM2Engine(new SM3Digest());
        //    cipher.Init(false, privKey);

        //    return cipher.ProcessBlock(encryptedData, 0, encryptedData.Length);
        //}
    }
}
