using System.Globalization;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Text;
using System.Xml.Serialization;
using Newtonsoft.Json;

namespace Exam.Infrastructure.Extensions
{
    public static class StringExtension
    {
        public static bool IsNullOrEmpty(this string source)
        {
            return string.IsNullOrEmpty(source);
        }

        public static bool IsNotNullOrEmpty(this string source)
        {
            return !string.IsNullOrEmpty(source);
        }

        public static bool IsNullOrWhiteSpace(this string source)
        {
            return string.IsNullOrWhiteSpace(source);
        }

        public static bool IsNumericOnly(this string source)
        {
            if (string.IsNullOrEmpty(source))
            {
                return false;
            }

            return source.All(Char.IsDigit);
        }

        /// <summary>
        /// Ensure that a string is not null
        /// </summary>
        /// <param name="source">Input string</param>
        /// <returns>Result</returns>
        public static string EnsureNotNull(this string source)
        {
            return source ?? String.Empty;
        }

        public static string EnsureTrim(this string str, params char[] trimChars)
        {
            if (str == null)
            {
                return null;
            }

            if (trimChars == null || trimChars.Length == 0)
            {
                return str.Trim();
            }

            return str.Trim(trimChars);

        }


        public static bool? ToBoolean(this string source)
        {
            if (string.Compare(source, "true", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                return true;
            }

            if (String.Compare(source, "false", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                return false;
            }

            return null;
        }


        public static float? ToFloat(this string source)
        {
            if (float.TryParse(source, out var result))
            {
                return result;
            }

            return null;
        }


        public static int? ToInt32(this string source)
        {
            if (int.TryParse(source, out var result))
            {
                return result;
            }

            return null;
        }

        public static DateTime? ToDateTime(this string source)
        {
            if (DateTime.TryParse(source, out var result))
            {
                return result;
            }

            return null;
        }

        public static DateTime? ToDateTime(this string source, string format)
        {
            string[] formats = { format };

            if (DateTime.TryParseExact(source,
                                       formats,
                                       CultureInfo.InvariantCulture,
                                       DateTimeStyles.None,
                                       out var result))
            {
                return result;
            }

            return null;
        }

        public static DateTime ToNotNullDateTime(this string source)
        {
            if (DateTime.TryParse(source, out var result))
            {
                return result;
            }

            return DateTime.MinValue;
        }

        /// <summary>
        /// 将特定字符分隔的字符串转换为INT数组
        /// </summary>
        public static int[] ToIntArray(this string strObj, char splitChar)
        {
            if (strObj.Length == 0)
            {
                return new int[] { };
            }

            var strArray = strObj.Split(new char[] { splitChar }, StringSplitOptions.RemoveEmptyEntries);
            var intArray = new int[strArray.Length];

            for (var i = 0; i < strArray.Length; i++)
                intArray[i] = int.Parse(strArray[i]);

            return intArray;
        }

        /// <summary>
        /// 获取字符串左边指定的字节个数
        /// </summary>
        public static string Left(this string strObj, int leftCount, string appendString = "")
        {
            if (string.IsNullOrEmpty(strObj))
                return string.Empty;
            int i = 0, j = 0;
            foreach (char c in strObj)
            {
                if (c > 127)
                {
                    i += 2;
                }
                else
                {
                    i++;
                }

                if (i > leftCount)
                {
                    return strObj.Substring(0, j) + appendString;
                }

                j++;
            }

            return strObj;
        }

        /// <summary>
        /// 字符串真实长度 如:一个汉字为两个字节
        /// </summary>
        public static int GetSize(this string strObj)
        {
            return Encoding.Default.GetBytes(strObj).Length;
        }

        /// <summary>
        /// 序列化为报文内容
        /// </summary>
        /// <param name="xml">以<packet>标签开始的xml内容</param>
        /// <returns></returns>
        public static T FromXml<T>(this string xml)
        {
            int index;
            if (xml.Trim().StartsWith("<?xml") && (index = xml.IndexOf("?>")) != -1)
            {
                xml = xml.Substring(index + 2).Trim('\r', '\n', ' ');
            }
            try
            {
                using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(T));
                    try
                    {
                        return (T)serializer.Deserialize(stream);
                    }
                    catch
                    {
                        return default(T);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"反序列化对象信息异常:{ex.Message}", ex);
            }
        }


        /// <summary>
        /// JSON字符反序列化为对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="str"></param>
        /// <returns></returns>
        public static T JsonToObj<T>(this string str)
        {
            try
            {
                return JsonConvert.DeserializeObject<T>(str);
            }
            catch (Exception ex)
            {
                throw new Exception($"无法将字符串 {str} 反序列化为 {typeof(T)} 类型的对象", ex);
            }
        }


        public static bool TryJsonToObj<T>(this string str, out T result)
        {
            try
            {
                result = JsonConvert.DeserializeObject<T>(str);

                return true;
            }
            catch
            {
                result = default(T);
                return false;
            }
        }

        /// <summary>
        /// 将首字母转换为小写字符
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public static string ToTitileLower(this string content)
        {
            if (string.IsNullOrEmpty(content))
                return content;

            return content.Substring(0, 1).ToLower() + content.Substring(1);
        }

        /// <summary>
        /// 将首字母转换为大写字符
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public static string ToTitileUpper(this string content)
        {
            if (string.IsNullOrEmpty(content))
                return content;

            return content.Substring(0, 1).ToUpper() + content.Substring(1);
        }

        public static string EncryptStr(this string content, string desKey)
        {
            try
            {
                if (string.IsNullOrEmpty(desKey))
                {
                    return content;
                }
                DESCryptoServiceProvider provider = new DESCryptoServiceProvider
                {
                    Mode = CipherMode.ECB
                };
                byte[] buffer = new byte[8];
                if (desKey.Length < 8)
                {
                    byte[] buffer2 = Encoding.UTF8.GetBytes(desKey);
                    for (int i = 0; i < buffer.Length; i++)
                    {
                        if (buffer2.Length > i)
                        {
                            buffer[i] = buffer2[i];
                        }
                        else
                        {
                            buffer[i] = 0;
                        }
                    }
                }
                else
                {
                    buffer = Encoding.UTF8.GetBytes(desKey.Substring(0, 8));
                }
                provider.Key = buffer;
                provider.IV = provider.Key;
                byte[] bytes = Encoding.UTF8.GetBytes(content);
                MemoryStream stream = new MemoryStream();
                CryptoStream stream2 = new CryptoStream(stream, provider.CreateEncryptor(), CryptoStreamMode.Write);
                stream2.Write(bytes, 0, bytes.Length);
                stream2.FlushFinalBlock();
                StringBuilder builder = new StringBuilder();
                foreach (byte num2 in stream.ToArray())
                {
                    builder.Append(num2.ToString());
                    builder.Append("_");
                }
                if (builder.Length > 0)
                {
                    builder = builder.Remove(builder.Length - 1, 1);
                }
                return builder.ToString();
            }
            catch (Exception)
            {
                return content;
            }
        }


        /// <summary>
        /// 尝试分隔字符串，分隔失败时返回空集合
        /// </summary>
        /// <param name="str"></param>
        /// <param name="separato"></param>
        /// <param name="removeEmptyItems"></param>
        /// <returns></returns>
        public static List<string> TrySplit(this string str, bool removeEmptyItems = false, params char[] separato)
        {
            if (str.IsNullOrEmpty())
                return new List<string>();

            return str.Split(separato).Where(x => removeEmptyItems ? x.IsNotNullOrEmpty() : true).ToList();
        }

        /// <summary>
        /// 消除数据库中直接存储的数组格式
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string DislodgeArray(this string str)
        {
            var value = str.Replace("[", "");
            value = value.Replace("]", "");
            value = value.Replace("\"", "");
            return value;
        }

        /// <summary>
        /// 处理application/x-www-form-urlencoded请求参数
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static IEnumerable<KeyValuePair<string?, string?>> ToKeyValuePairs(this string str)
        {
            var result = new List<KeyValuePair<string?, string?>>();
            if (str.Contains('&') && str.Contains('='))
            {
                var keyValues = str.Split('&');

                foreach (var item in keyValues)
                {
                    var keyValuePairs = item.Split('=');
                    result.Add(new KeyValuePair<string?, string?>(keyValuePairs[0], keyValuePairs[1]));
                }
            }

            if (str.Contains(',') && str.Contains(':'))
            {
                var dictionary = str.ToEntity<Dictionary<string, string>>();

                foreach (var item in dictionary)
                {
                    //var keyValuePairs = item.Split(':');
                    result.Add(new KeyValuePair<string?, string?>(item.Key, item.Value));
                }
            }

            return result;
        }

        /// <summary>
        /// 字符串转换为字典
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="content"></param>
        /// <param name="fisrt"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this string content, char fisrt, char second)
        {
            var result = new Dictionary<TKey, TValue>();

            var firstLayer = content.Split(fisrt);

            foreach (var item in firstLayer)
            {
                var secondLayer = item.Split(second);

                if (secondLayer.Count() >= 2)
                {
                    var key = (TKey)Convert.ChangeType(secondLayer[0], typeof(TKey));

                    if (!result.ContainsKey(key))
                    {
                        var value = (TValue)Convert.ChangeType(secondLayer[1], typeof(TValue));

                        result.Add(key, value);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 转换为AscII字符串
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ToAscIIString(this string str)
        {
            // ASCII码本身并不支持中国的汉字，那么我们需要将汉字转换成对应的16进制码，然后取出对应的ASCII16进制码组成汉字编码。


            //这里我们将采用2字节一个汉字的方法来取出汉字的16进制码

            byte[] textbuf = Encoding.GetEncoding("GB2312").GetBytes(str);

            //将字节转化成汉字

            var textStr = Encoding.GetEncoding("GB2312").GetString(textbuf);

            return textStr;
        }

        public static IList<T> ToExtensionList<T>(this IList<string> source)
        {
            var result = new List<T>();

            try
            {
                foreach (var item in source)
                {
                    result.Add((T)Convert.ChangeType(item, typeof(T)));
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return result;
        }

        /// <summary>
        /// 获取字符串中的中文
        /// </summary>
        public static string GetChineseWord(this string source)
        {
            string expression = @"[\u4E00-\u9FFF]+";

            MatchCollection Matches = Regex.Matches(source, expression, RegexOptions.IgnoreCase);
            StringBuilder sb = new StringBuilder();

            foreach (Match match in Matches)
            {
                sb.Append(match.Value);
            }

            return sb.ToString();
        }

        /// <summary>
        /// 处理超长字长
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <typeparam name="TParams"></typeparam>
        /// <param name="content"></param>
        /// <param name="maxinum"></param>
        /// <param name="resolve"></param>
        /// <returns></returns>
        public static List<TResult> ResolveMaxinumString<TResult>(this string content, int maxinum, Func<string, int, TResult> resolve)
        {
            var results = new List<TResult>();
            if (content.Length > maxinum)
            {
                var repeat = content.Length / maxinum;

                repeat += content.Length % maxinum != 0 ? 0 : 1;

                for (var i = 0; i < repeat; i++)
                {
                    results.Add(resolve(content.Substring(i * maxinum, maxinum), i));
                }
            }
            else
            {
                results.Add(resolve(content, 0));
            }
            return results;
        }
    }
}
