using Microsoft.Extensions.Logging;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System;
using MS.Models;
using Microsoft.AspNetCore.Http;

namespace MS.WebApi.Middlewares
{
    public class SignatureValidator
    {
        private readonly ILogger<SignatureValidator> _logger;

        public SignatureValidator(ILogger<SignatureValidator> logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// 验证传入请求的签名是否有效。
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<bool> ValidateSignature(HttpRequest request, string Secret)
        {
            try
            {
                var signMethod = request.Headers["sign_method"].ToString();
                var secretId = request.Headers["secret_id"].ToString();
                var nonce = request.Headers["nonce"].ToString();
                var timestamp = request.Headers["timestamp"].ToString();
                var signature = request.Headers["signature"].ToString();//签名串
                string bodyContent = string.Empty;
                if (request.Body != null)
                {
                    // 将 Body 流读取为字符串
                    request.EnableBuffering(); // 允许多次读取 Body
                    using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
                    {
                        bodyContent = await reader.ReadToEndAsync();
                    }
                    request.Body.Position = 0; // 重置流的位置以便后续读取
                }
                if (string.IsNullOrEmpty(signMethod) || string.IsNullOrEmpty(secretId) ||
                    string.IsNullOrEmpty(nonce) || string.IsNullOrEmpty(timestamp) ||
                    string.IsNullOrEmpty(signature))
                {
                    _logger.LogError("缺少签名信息");
                    return false;
                }

                // 查询字符串
                //var queryString = HttpUtility.ParseQueryString(request.QueryString.ToString());
                //var queryParameters = queryString.AllKeys
                //    .OrderBy(k => k)
                //    .Select(k => $"{k}={queryString[k]}")
                //    .Aggregate((current, next) => current + "&" + next);

                // 待签字符串  
                var stringToSign = $"sign_method={signMethod}&secret_id={secretId}&nonce={nonce}&timestamp={timestamp}";
                if (!string.IsNullOrEmpty(bodyContent))
                {
                    stringToSign += "&" + bodyContent;
                }
                if (request.QueryString.Value != "")
                {
                    var querystring = request.QueryString.Value.Substring(1);
                    stringToSign += "&" + querystring;
                }
                //var sfd =  Sm4Encryptor.Encrypt(stringToSign, Secret);
                //stringToSign = Sm4Encryptor.Encrypt(stringToSign, Secret);
                stringToSign = stringToSign.SM4Encrypt_ECB(Secret);
                // 根据 RFC3986 对字符串进行 URL 编码
                var encodedString = Uri.EscapeDataString(stringToSign);

                string base64 = StringToBase64(encodedString);
                return base64.Equals(signature, StringComparison.Ordinal);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "签名验证过程中发生错误。");
                return false;
            }
        }

        public static string StringToBase64(string input)
        {
            if (string.IsNullOrEmpty(input))
                return string.Empty;

            // 将字符串转换为字节数组
            byte[] bytes = Encoding.UTF8.GetBytes(input);

            // 将字节数组转换为 Base64 字符串
            return Convert.ToBase64String(bytes);
        }

        public string Encrypt(string plainText)
        {
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            // 加密
            // byte[] encryptedBytes = sm4.EncryptECB(plainTextBytes);

            // 这里我们模拟加密过程，直接返回原始数据（你需要替换为实际的加密代码）
            byte[] encryptedBytes = plainTextBytes; // 假设加密后数据不变，仅作示例

            // 返回Base64编码的加密字符串
            return Convert.ToBase64String(encryptedBytes);
        }


        public string SM4Encrypt_ECB(string plainText, string secretKey, bool hexString = false)
        {
            Sm4Context sm4Context = new Sm4Context();
            sm4Context.isPadding = true;
            sm4Context.mode = 1;
            byte[] key = (!hexString) ? Encoding.Default.GetBytes(secretKey) : Decode(secretKey);
            Sm4 sm = new Sm4();
            sm.sm4_setkey_enc(sm4Context, key);
            byte[] data = sm.sm4_crypt_ecb(sm4Context, Encoding.Default.GetBytes(plainText));
            return Encoding.Default.GetString(Encode(data, 0, data.Length));
        }
        public byte[] Decode(string hexString)
        {
            // 确保输入字符串长度为偶数
            if (hexString.Length % 2 != 0)
            {
                throw new ArgumentException("Hexadecimal string must have an even length", nameof(hexString));
            }

            // 创建一个输出流来存储解码后的字节数据
            using (MemoryStream outputStream = new MemoryStream(hexString.Length / 2))
            {
                for (int i = 0; i < hexString.Length; i += 2)
                {
                    // 获取两个字符并将其转换为字节
                    char highNibbleChar = hexString[i];
                    char lowNibbleChar = hexString[i + 1];

                    byte highNibble = CharToByte(highNibbleChar);
                    byte lowNibble = CharToByte(lowNibbleChar);

                    if (highNibble == 0xFF || lowNibble == 0xFF)
                    {
                        throw new ArgumentException("Invalid hexadecimal character encountered.", nameof(hexString));
                    }

                    // 合并两个半字节为一个完整的字节
                    byte decodedByte = (byte)((highNibble << 4) | lowNibble);

                    // 将解码后的字节写入输出流
                    outputStream.WriteByte(decodedByte);
                }

                return outputStream.ToArray();
            }
        }

        // 私有辅助方法用于将字符转换为对应的数值
        private byte CharToByte(char c)
        {
            if (c >= '0' && c <= '9')
                return (byte)(c - '0');
            if (c >= 'A' && c <= 'F')
                return (byte)(c - 'A' + 10);
            if (c >= 'a' && c <= 'f')
                return (byte)(c - 'a' + 10);

            // 如果字符不是有效的十六进制字符，则返回0xFF作为错误标志
            return 0xFF;
        }
        // 实例方法用于编码字节数组到十六进制字符串
        public byte[] Encode(byte[] data, int offset, int length)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data), "Input data cannot be null.");
            if (offset < 0 || offset >= data.Length)
                throw new ArgumentOutOfRangeException(nameof(offset), "Offset is out of range.");
            if (length <= 0 || offset + length > data.Length)
                throw new ArgumentOutOfRangeException(nameof(length), "Length is out of range.");

            // 创建一个输出流来存储编码后的十六进制字符串
            using (MemoryStream outputStream = new MemoryStream(length * 2))
            {
                for (int i = offset; i < offset + length; i++)
                {
                    byte b = data[i];
                    // 将每个字节转换为两个十六进制字符
                    byte highNibble = (byte)((b >> 4) & 0xF);
                    byte lowNibble = (byte)(b & 0xF);

                    outputStream.WriteByte(ConvertToHexChar(highNibble));
                    outputStream.WriteByte(ConvertToHexChar(lowNibble));
                }

                return outputStream.ToArray();
            }
        }

        // 私有辅助方法用于将半字节转换为对应的十六进制字符
        private byte ConvertToHexChar(byte nibble)
        {
            if (nibble < 10)
                return (byte)('0' + nibble); // 数字 0-9
            else
                return (byte)('a' - 10 + nibble); // 字母 a-f
        }
    }
}
