namespace Provider.Payment.Alipay
{
    public class AlipayUtil
    {
        /// <summary>
        /// 生成签名
        /// 相关文档:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.vwCvxF&treeId=62&articleId=104741&docType=1
        /// </summary>
        /// <param name="obj">要签名的对象</param>
        /// <param name="signKey">签名密匙</param>
        /// <returns>签名字符串</returns>
        public static string GenerateSign(object entity, string signKey)
        {
            SortedDictionary<string, object> sorted = GetSortedDictionary(entity);
            return GenerateSign(sorted, signKey);
        }
        /// <summary>
        /// 生成签名
        /// </summary>
        /// <remarks>
        /// 相关文档:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.vwCvxF&treeId=62&articleId=104741&docType=1
        /// </remarks>
        /// <param name="obj">要签名的对象</param>
        /// <param name="signKey">签名密匙</param>
        /// <returns>签名字符串</returns>
        public static string GenerateSign(SortedDictionary<string, object> sorted, string signKey)
        {
            StringBuilder builder = new StringBuilder();
            foreach (KeyValuePair<string, object> pair in sorted)
            {
                if (pair.Key != "sign" && pair.Key != "sign_type")
                {
                    object value = pair.Value;
                    Type type = pair.Value.GetType();
                    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        type = type.GetGenericArguments()[0];
                    }
                    if (type == typeof(DateTime))
                    {
                        value = Convert.ToDateTime(value).ToString("yyyy-MM-dd HH:mm:ss");
                    }
                    builder.Append(pair.Key + "=" + value + "&");
                }
            }
            string str = builder.Remove(builder.Length - 1, 1).ToString() + signKey;
            string sign = MD5Encrypt(str);
            return sign;
        }
        /// <summary>
        /// 获得属性值并排序
        /// </summary>
        /// <param name="entity">参数</param>
        /// <returns></returns>
        protected static SortedDictionary<string, object> GetSortedDictionary(object entity)
        {
            Type type = entity.GetType();
            PropertyInfo[] propertys = type.GetProperties();
            SortedDictionary<string, object> sorted = new SortedDictionary<string, object>();
            foreach (PropertyInfo property in propertys)
            {
                Type propertyType = property.GetType();
                object objValue = null;
                if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    bool HasValue = (bool)type.GetProperty("HasValue").GetValue(entity, null);
                    if (HasValue)
                    {
                        objValue = type.GetProperty("Value").GetValue(entity, null);
                    }
                }
                else
                {
                    objValue = property.GetValue(entity, null);
                }
                string value = (objValue ?? "").ToString();
                if (!String.IsNullOrEmpty(value))
                {
                    sorted.Add(property.Name, value);
                }
            }
            return sorted;
        }
        /// <summary>
        /// MD5加密
        /// </summary>
        protected static string MD5Encrypt(string input)
        {
            MD5 md5 = MD5.Create();
            byte[] bytes = Encoding.UTF8.GetBytes(input);
            byte[] buffer = md5.ComputeHash(bytes);
            StringBuilder builder = new StringBuilder();
            foreach (byte b in buffer)
            {
                builder.Append(b.ToString("x2"));
            }
            return builder.ToString();
        }
    }
}