using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using System;
using System.Text;

namespace Infrastructure.Helpers
{
    public class SM2CryptoHelper
    {
        private static readonly ECDomainParameters DomainParams;
        // 国标要求的默认用户ID
        private static readonly byte[] DefaultUserId = Encoding.UTF8.GetBytes("1234567812345678");

        static SM2CryptoHelper()
        {
            var curve = GMNamedCurves.GetByName("sm2p256v1");
            DomainParams = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H);
        }

        #region 生成密钥对
        // 生成SM2密钥对
        public static (byte[] privateKey, byte[] publicKey) GenerateKeyPair()
        {
            var gen = new ECKeyPairGenerator();
            gen.Init(new ECKeyGenerationParameters(DomainParams, new SecureRandom()));

            var keyPair = gen.GenerateKeyPair();
            var privKey = (ECPrivateKeyParameters)keyPair.Private;
            var pubKey = (ECPublicKeyParameters)keyPair.Public;

            return (
                AdjustTo32Bytes(privKey.D.ToByteArrayUnsigned()),
                pubKey.Q.GetEncoded(false) // 未压缩格式公钥(65字节)
            );
        }
        #endregion

        #region 签名 验签
        // SM2签名 (R|S裸编码，64字节)
        public static byte[] Sign(byte[] privateKey, byte[] data)
        {
            if (privateKey == null || privateKey.Length != 32)
                throw new ArgumentException("Private key must be 32 bytes");

            var d = new BigInteger(1, privateKey);
            var privateKeyParam = new ECPrivateKeyParameters(d, DomainParams);

            // 使用国标要求的用户ID
            var signer = new SM2Signer(new SM3Digest());
            signer.Init(true, new ParametersWithID(
                new ParametersWithRandom(privateKeyParam, new SecureRandom()),
                DefaultUserId));

            signer.BlockUpdate(data, 0, data.Length);
            byte[] derSignature = signer.GenerateSignature();

            // 解析DER格式为R|S裸编码
            //return DerToRawSignature(derSignature);
            // 使用更可靠的 DER 转裸签名方法
            return ConvertDerToRawSignature(derSignature, 32);
        }
        // SM2验签
        public static bool Verify(byte[] publicKey, byte[] data, byte[] signature)
        {
            if (signature.Length != 64)
                throw new ArgumentException("Signature must be 64 bytes raw format (R|S)");
            if (publicKey == null || (publicKey.Length != 65 && publicKey[0] == 0x04))
                throw new ArgumentException("Public key must be in uncompressed format (65 bytes)");

            try
            {
                // 将裸签名转换为DER格式
                //byte[] derSignature = RawToDerSignature(signature);
                byte[] derSignature = ConvertRawToDerSignature(signature, 32);
                ECPoint q = DomainParams.Curve.DecodePoint(publicKey);
                var pubKey = new ECPublicKeyParameters(q, DomainParams);

                var signer = new SM2Signer(new SM3Digest());
                signer.Init(false, new ParametersWithID(pubKey, DefaultUserId));
                signer.BlockUpdate(data, 0, data.Length);

                return signer.VerifySignature(derSignature);
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region 加密解密
        // SM2加密 (C1C3C2模式)
        public static byte[] Encrypt(byte[] publicKey, byte[] plaintext)
        {
            if (publicKey == null || publicKey.Length != 65)
                throw new ArgumentException("Public key must be 65 bytes uncompressed format");

            ECPoint q = DomainParams.Curve.DecodePoint(publicKey);
            var pubKey = new ECPublicKeyParameters(q, DomainParams);

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

            byte[] encrypted = cipher.ProcessBlock(plaintext, 0, plaintext.Length);

            // 转换为C1C3C2模式
            return ConvertToC1C3C2(encrypted);
            //return cipher.ProcessBlock(plaintext, 0, plaintext.Length);
        }

        /// <summary>
        /// 将C1C2C3格式转换为C1C3C2格式
        /// </summary>
        private static byte[] ConvertToC1C3C2(byte[] c1c2c3)
        {
            // 密文结构: C1(65字节) + C2(明文长度) + C3(32字节)
            int c1Length = 65;          // C1部分长度
            int c3Length = 32;          // C3部分长度
            int c2Length = c1c2c3.Length - c1Length - c3Length; // C2部分长度

            if (c2Length < 0)
                throw new ArgumentException("Invalid ciphertext length");

            // 创建新数组: C1(65) + C3(32) + C2(变长)
            byte[] c1c3c2 = new byte[c1c2c3.Length];

            // 复制C1部分 (0-65字节)
            Buffer.BlockCopy(c1c2c3, 0, c1c3c2, 0, c1Length);

            // 复制C3部分 (最后32字节)
            Buffer.BlockCopy(c1c2c3, c1Length + c2Length, c1c3c2, c1Length, c3Length);

            // 复制C2部分 (65到65+c2Length)
            Buffer.BlockCopy(c1c2c3, c1Length, c1c3c2, c1Length + c3Length, c2Length);

            return c1c3c2;
        }

        // SM2解密 (C1C3C2模式)
        public static byte[] Decrypt(byte[] privateKey, byte[] ciphertext)
        {
            if (privateKey == null || privateKey.Length != 32)
                throw new ArgumentException("Private key must be 32 bytes");

            // 先将密文转换为C1C2C3模式（BouncyCastle默认格式）
            byte[] c1c2c3 = ConvertToC1C2C3(ciphertext);

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

            // 明确指定C1C3C2模式
            var cipher = new SM2Engine(new SM3Digest());
            cipher.Init(false, privKey);

            try
            {
                return cipher.ProcessBlock(c1c2c3, 0, c1c2c3.Length);
                //return cipher.ProcessBlock(ciphertext, 0, ciphertext.Length);
            }
            catch (Exception ex)
            {
                throw new CryptoException("Decryption failed", ex);
            }
        }

        /// <summary>
        /// 将C1C3C2格式转换为C1C2C3格式
        /// </summary>
        private static byte[] ConvertToC1C2C3(byte[] c1c3c2)
        {
            // 密文结构: C1(65字节) + C3(32字节) + C2(明文长度)
            int c1Length = 65;          // C1部分长度
            int c3Length = 32;          // C3部分长度
            int c2Length = c1c3c2.Length - c1Length - c3Length; // C2部分长度

            if (c2Length < 0)
                throw new ArgumentException("Invalid ciphertext length");

            // 创建新数组: C1(65) + C2(变长) + C3(32)
            byte[] c1c2c3 = new byte[c1c3c2.Length];

            // 复制C1部分 (0-65字节)
            Buffer.BlockCopy(c1c3c2, 0, c1c2c3, 0, c1Length);

            // 复制C2部分 (65+32到结束)
            Buffer.BlockCopy(c1c3c2, c1Length + c3Length, c1c2c3, c1Length, c2Length);

            // 复制C3部分 (65到65+32)
            Buffer.BlockCopy(c1c3c2, c1Length, c1c2c3, c1Length + c2Length, c3Length);

            return c1c2c3;
        }
        #endregion

        #region 内部工具方法
        private static byte[] AdjustTo32Bytes(byte[] input)
        {
            if (input.Length == 32) return input;
            if (input.Length > 32)
                throw new ArgumentException("Input too long for 32-byte adjustment");

            byte[] output = new byte[32];
            Buffer.BlockCopy(input, 0, output, 32 - input.Length, input.Length);
            return output;
        }

        // === 新增方法：可靠的 DER 转裸签名 ===
        private static byte[] ConvertDerToRawSignature(byte[] derSignature, int partLength)
        {
            Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(derSignature);
            byte[] rBytes = PadLeadingZeros(((DerInteger)seq[0]).Value.ToByteArrayUnsigned(), partLength);
            byte[] sBytes = PadLeadingZeros(((DerInteger)seq[1]).Value.ToByteArrayUnsigned(), partLength);

            byte[] rawSig = new byte[partLength * 2];
            Buffer.BlockCopy(rBytes, 0, rawSig, 0, partLength);
            Buffer.BlockCopy(sBytes, 0, rawSig, partLength, partLength);
            return rawSig;
        }
        // === 新增方法：安全的填充处理 ===
        private static byte[] PadLeadingZeros(byte[] input, int requiredLength)
        {
            if (input.Length == requiredLength)
                return input;

            if (input.Length > requiredLength)
                throw new InvalidOperationException("Input longer than required length");

            byte[] padded = new byte[requiredLength];
            int offset = requiredLength - input.Length;
            Buffer.BlockCopy(input, 0, padded, offset, input.Length);
            return padded;
        }

        // === 新增方法：可靠的裸签名转 DER ===
        private static byte[] ConvertRawToDerSignature(byte[] rawSignature, int partLength)
        {
            if (rawSignature.Length != partLength * 2)
                throw new ArgumentException("Invalid raw signature length");

            byte[] rBytes = new byte[partLength];
            byte[] sBytes = new byte[partLength];
            Buffer.BlockCopy(rawSignature, 0, rBytes, 0, partLength);
            Buffer.BlockCopy(rawSignature, partLength, sBytes, 0, partLength);

            // 移除前导零（匹配 Java 行为）
            BigInteger r = new BigInteger(1, rBytes);
            BigInteger s = new BigInteger(1, sBytes);

            Asn1EncodableVector v = new Asn1EncodableVector();
            v.Add(new DerInteger(r));
            v.Add(new DerInteger(s));
            return new DerSequence(v).GetEncoded();
        }
        #endregion
    }
}
