using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OASystem.Domain.ViewModels.Groups;
using System.Collections;
using System.Globalization;
using System.Reflection;
using TinyPinyin;

namespace OASystem.Infrastructure.Tools;

/// <summary>
/// 工具类
/// </summary>
public static class CommonFun
{
    public static string GUID => Guid.NewGuid().ToString("N");
    public static bool IsNull(this string s)
    {
        return string.IsNullOrWhiteSpace(s);
    }
    public static bool NotNull(this string s)
    {
        return !string.IsNullOrWhiteSpace(s);
    }
    public static int GetRandom(int minNum, int maxNum)
    {
        var seed = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0);
        return new Random(seed).Next(minNum, maxNum);
    }
    public static string GetSerialNumber(string prefix = "")
    {
        return prefix + DateTime.Now.ToString("yyyyMMddHHmmssfff") + GetRandom(1000, 9999).ToString();
    }
    public static string ToJson(this object obj)
    {
        return System.Text.Json.JsonSerializer.Serialize(obj);
    }
    public static T ToObject<T>(this string json)
    {
        return System.Text.Json.JsonSerializer.Deserialize<T>(json);
    }
    public static object GetDefaultVal(string typename)
    {
        return typename switch
        {
            "Boolean" => false,
            "DateTime" => default(DateTime),
            "Date" => default(DateTime),
            "Double" => 0.0,
            "Single" => 0f,
            "Int32" => 0,
            "String" => string.Empty,
            "Decimal" => 0m,
            _ => null,
        };
    }
    public static void CoverNull<T>(T model) where T : class
    {
        if (model == null)
        {
            return;
        }
        var typeFromHandle = typeof(T);
        var properties = typeFromHandle.GetProperties();
        var array = properties;
        for (var i = 0; i < array.Length; i++)
        {
            var propertyInfo = array[i];
            if (propertyInfo.GetValue(model, null) == null)
            {
                propertyInfo.SetValue(model, GetDefaultVal(propertyInfo.PropertyType.Name), null);
            }
        }
    }
    public static void CoverNull<T>(List<T> models) where T : class
    {
        if (models.Count == 0)
        {
            return;
        }
        foreach (var model in models)
        {
            CoverNull(model);
        }
    }
    public static bool ToBool(this object thisValue, bool errorvalue = false)
    {
        if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out bool reval))
        {
            return reval;
        }
        return errorvalue;
    }

    #region 文件操作
    public static FileInfo[] GetFiles(string directoryPath)
    {
        if (!IsExistDirectory(directoryPath))
        {
            throw new DirectoryNotFoundException();
        }
        var root = new DirectoryInfo(directoryPath);
        return root.GetFiles();
    }
    public static bool IsExistDirectory(string directoryPath)
    {
        return Directory.Exists(directoryPath);
    }
    public static string ReadFile(string Path)
    {
        string s;
        if (!File.Exists(Path))
            s = "不存在相应的目录";
        else
        {
            var f2 = new StreamReader(Path, Encoding.Default);
            s = f2.ReadToEnd();
            f2.Close();
            f2.Dispose();
        }
        return s;
    }
    public static void FileMove(string OrignFile, string NewFile)
    {
        File.Move(OrignFile, NewFile);
    }
    public static void CreateDir(string dir)
    {
        if (dir.Length == 0) return;
        if (!Directory.Exists(dir))
            Directory.CreateDirectory(dir);
    }

    /// <summary>
    /// 验证文件名称
    /// </summary>
    /// <param name="fileName"></param>
    /// <returns></returns>
    public static string ValidFileName(string fileName)
    {
        if (string.IsNullOrEmpty(fileName)) return Guid.NewGuid().ToString();

        // 获取非法文件名字符
        char[] invalidChars = Path.GetInvalidFileNameChars();

        return new string(fileName.Where(c => !invalidChars.Contains(c)).ToArray());
    }
    #endregion

    #region IP
    /// <summary>
    /// 是否为ip
    /// </summary>
    /// <param name="ip"></param>
    /// <returns></returns>
    public static bool IsIP(string ip)
    {
        return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
    }
    public static string GetIP(HttpRequest request)
    {
        if (request == null) return "";

        var ip = request.Headers["X-Real-IP"].FirstOrDefault();
        if (ip.IsNull())
        {
            ip = request.Headers["X-Forwarded-For"].FirstOrDefault();
        }
        if (ip.IsNull())
        {
            ip = request.HttpContext?.Connection?.RemoteIpAddress?.ToString();
        }
        if (ip.IsNull() || !IsIP(ip))
        {
            ip = "127.0.0.1";
        }

        return ip;
    }
    #endregion

    #region 随机数

    /// <summary>
    /// 根据自定义随机包含的字符获取指定长度的随机字符
    /// </summary>
    /// <param name="length">随机字符长度</param>
    /// <returns>随机字符</returns>
    public static string GetRandomStr(int length)
    {
        string a = "ABCDEFGHJKLMNPQRSTUVWXYZ012356789";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++)
        {
            sb.Append(a[new Random(Guid.NewGuid().GetHashCode()).Next(0, a.Length - 1)]);
        }

        return sb.ToString();
    }

    /// <summary>
    /// 根据自定义随机包含的字符获取指定长度的随机字符
    /// </summary>
    /// <param name="length">随机字符长度</param>
    /// <returns>随机字符</returns>
    public static string GetRandomAllStr(int length)
    {
        string a = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjklmnpqrstuvwxyz012356789";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++)
        {
            sb.Append(a[new Random(Guid.NewGuid().GetHashCode()).Next(0, a.Length - 1)]);
        }

        return sb.ToString();
    }


    /// <summary>
    /// 根据自定义随机包含的字符获取指定长度的随机字母(含大小写)
    /// </summary>
    /// <param name="length">随机字符长度</param>
    /// <returns>随机字符</returns>
    public static string GetRandomLetter(int length)
    {
        string a = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjklmnpqrstuvwxyz";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++)
        {
            sb.Append(a[new Random(Guid.NewGuid().GetHashCode()).Next(0, a.Length - 1)]);
        }

        return sb.ToString();
    }

    /// <summary>
    /// 生成不重复随机数字
    /// 操作者:037
    /// 2021-07-26 15:39
    /// </summary>
    /// <param name="CodeCount">输入字符串长度</param>
    /// <returns>字符串</returns>
    public static string GetRandomNumber(int len)
    {
        string allChar = "0,1,2,3,4,5,6,7,8,9";
        string[] allCharArray = allChar.Split(',');
        string RandomCode = "";
        int temp = -1;
        Random rand = new Random();

        for (int i = 0; i < len; i++)
        {
            if (temp != -1)
            {
                rand = new Random(temp * i * ((int)DateTime.Now.Ticks));
            }
            int t = rand.Next(allCharArray.Length - 1);
            while (temp == t)

            {
                t = rand.Next(allCharArray.Length - 1);
            }
            temp = t;
            RandomCode += allCharArray[t];
        }
        return RandomCode;
    }

    #endregion

    #region decimal 截取
    /// <summary>
    /// 
    /// </summary>
    /// <param name="d"></param>
    /// <param name="n"></param>
    /// <returns></returns>
    public static decimal CutDecimalWithN(decimal d, int n)
    {
        string strDecimal = d.ToString();
        int index = strDecimal.IndexOf(".");
        if (index == -1 || strDecimal.Length < index + n + 1)
        {
            strDecimal = string.Format("{0:F" + n + "}", d);
        }
        else
        {
            int length = index;
            if (n != 0)
            {
                length = index + n + 1;
            }
            strDecimal = strDecimal.Substring(0, length);
        }
        return Decimal.Parse(strDecimal);
    }


    /// <summary>
    /// decimal 保留小数,不四舍五入
    /// </summary>
    /// <param name="value"></param>
    /// <param name="decimalPlaces"></param>
    /// <returns></returns>
    public static decimal TruncDecimals(this decimal value, int decimalPlaces)
    {
        decimal scaleFactor = (decimal)Math.Pow(10, decimalPlaces);
        var truncated = Math.Truncate(scaleFactor * value) / scaleFactor;

        // 检查是否需要补零
        if (GetDecimalDigits(value) < decimalPlaces)
        {
            string format = "0." + new string('0', decimalPlaces);
            truncated = decimal.Parse(truncated.ToString(format));
        }

        return truncated;
    }
    private static int GetDecimalDigits(decimal number)
    {
        string[] parts = number.ToString().Split('.');
        return parts.Length > 1 ? parts[1].Length : 0;
    }

    #endregion

    #region decimal 保留两位小数

    /// <summary>
    /// decimal 保留两位小数 不四舍五入
    /// </summary>
    /// <param name="number"></param>
    /// <returns></returns>
    public static decimal DecimalsKeepTwo(this decimal myDecimal)
    {
        var subDecimal = Math.Floor(myDecimal * 100) / 100;//保留两位小数,直接截取
        return subDecimal;
    }

    #endregion

    #region 团组模块 - 汇率相关存储解析
    /// <summary>
    /// 团组模块 - 汇率相关 To List
    /// </summary>
    /// <param name="rateStr"></param>
    /// <returns></returns>
    public static List<CurrencyInfo> GetCurrencyChinaToList(string? rateStr)
    {
        List<CurrencyInfo> currencyInfos = new List<CurrencyInfo>();

        if (string.IsNullOrEmpty(rateStr)) return currencyInfos;

        if (rateStr.Contains("|"))
        {
            string[] currencyArr = rateStr.Split("|");
            foreach (string currency in currencyArr)
            {
                string[] currency1 = currency.Split(":");
                string[] currency2 = currency1[0].Split("(");

                CurrencyInfo rateInfo = new CurrencyInfo()
                {
                    CurrencyCode = currency2[1].Replace(")", "").TrimEnd(),
                    CurrencyName = currency2[0],
                    Rate = decimal.Parse(currency1[1]),
                };
                currencyInfos.Add(rateInfo);
            }
        }
        return currencyInfos;
    }

    /// <summary>
    /// 团组模块 - 汇率相关存储解析 To String
    /// </summary>
    /// <param name="rates"></param>
    /// <returns></returns>
    public static string GetCurrencyChinaToString(List<CurrencyInfo>? rates)
    {
        string rateStr = string.Empty;
        if (rates == null) return rateStr;
        if (rates.Count <= 0) return rateStr;

        if (rates.Count == 1)
        {
            var rate = rates[0];
            return string.Format("{0}({1}):{2}|", rate.CurrencyName, rate.CurrencyCode, rate.Rate);
        }

        foreach (CurrencyInfo rate in rates)
        {
            //存储方式: 美元(USD):6.2350|.......|墨西哥比索(MXN):1.0000
            rateStr += string.Format("{0}({1}):{2}|", rate.CurrencyName, rate.CurrencyCode, rate.Rate);
        }

        if (rateStr.Length > 0)
        {
            rateStr = rateStr.Substring(0, rateStr.Length - 1);
        }

        return rateStr;
    }
    #endregion

    #region 验证身份证号码
    /// <summary>
    /// 正则表达式
    /// 验证身份证号码
    /// </summary>
    /// <param name="idNumber"></param>
    /// <returns></returns>
    public static bool IsValidChineseId(this string idNumber)
    {
        string pattern = @"^[1-9]\d{5}(18|19|20|21|22)?\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}(\d|[Xx])$";
        Regex regex = new Regex(pattern);
        return regex.IsMatch(idNumber);
    }

    /// <summary>
    /// 通过身份证提取生日
    /// </summary>
    /// <param name="identityCard"></param>
    /// <returns></returns>
    public static DateTime? GetBirthDateFromIdentityCard(string identityCard)
    {
        // 身份证号码正则表达式验证,支持18位身份证号码
        if (!Regex.IsMatch(identityCard, @"^\d{17}(\d|X|x)$"))
        {
            return null;
        }

        // 获取出生日期(8位数字)
        string birthDateString = identityCard.Substring(6, 8);

        // 尝试将出生日期字符串转换为DateTime类型
        if (DateTime.TryParse(birthDateString, out DateTime birthDate))
        {
            return birthDate;
        }

        return null;
    }

    /// <summary>
    /// 通过身份证判断性别
    /// </summary>
    /// <param name="idNumber"></param>
    /// <returns>0 男1 女 -1 未设置</returns>
    /// <exception cref="ArgumentException"></exception>
    public static int GetGenderFromIdentityCard(string idNumber)
    {
        if (string.IsNullOrEmpty(idNumber) || idNumber.Length != 18)
            return -1;

        char genderChar = idNumber[16];
        return int.Parse(genderChar.ToString()) % 2 == 0 ? 1 : 0;
    }


    #endregion

    #region string格式日期格式化

    /// <summary>
    /// string格式日期格式化
    /// </summary>
    /// <param name="dateStr"></param>
    /// <param name="format">
    /// 格式化标准
    /// yyyy-MM-dd  yyyy/MM/dd
    /// </param>
    /// <returns></returns>
    public static string DateFormat(this string dateStr, string format)
    {
        if (!string.IsNullOrEmpty(dateStr))
        {
            if (!string.IsNullOrEmpty(format))
            {
                DateTime result;
                if (DateTime.TryParse(dateStr, out result))
                {
                    return result.ToString(format);
                }
            }
        }

        return "";
    }

    #endregion

    /// <summary>
    /// List to DataTable
    /// 集合转换成datatable
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="aIList"></param>
    /// <returns></returns>
    public static DataTable GetDataTableFromIList<T>(List<T> aIList)
    {

        DataTable _returnTable = new DataTable();

        if (aIList != null && aIList.Count > 0)
        {

            object _baseObj = aIList[0];

            Type objectType = _baseObj.GetType();

            PropertyInfo[] properties = objectType.GetProperties();

            DataColumn _col;

            foreach (PropertyInfo property in properties)
            {

                _col = new DataColumn();

                _col.ColumnName = (string)property.Name;

                _col.DataType = property.PropertyType;

                _returnTable.Columns.Add(_col);

            }

            //Adds the rows to the table

            DataRow _row;

            foreach (object objItem in aIList)
            {

                _row = _returnTable.NewRow();

                foreach (PropertyInfo property in properties)
                {

                    _row[property.Name] = property.GetValue(objItem, null);

                }

                _returnTable.Rows.Add(_row);

            }

        }

        return _returnTable;

    }

    /// <summary>
    /// List to DataTable
    /// 集合转换成datatable
    /// </summary>
    public static DataTable ToDataTableArray(IList list)
    {
        DataTable result = new DataTable();
        if (list.Count > 0)
        {
            PropertyInfo[] propertys = list[0].GetType().GetProperties();
            foreach (PropertyInfo pi in propertys)
            {
                try
                {
                    result.Columns.Add(pi.Name, pi.PropertyType);
                }
                catch (Exception ex)
                {

                    Console.WriteLine($"{pi.Name}:{ex.Message}");
                }


            }
            for (int i = 0; i < list.Count; i++)
            {
                ArrayList tempList = new ArrayList();
                foreach (PropertyInfo pi in propertys)
                {
                    object obj = pi.GetValue(list[i], null);
                    tempList.Add(obj);
                }
                object?[] array = tempList.ToArray();
                result.LoadDataRow(array, true);
            }
        }
        return result;
    }

    /// <summary>
    ///获取指定月份起止日期
    /// </summary>
    /// <param name="year"></param>
    /// <param name="month"></param>
    /// <returns></returns>
    public static (DateTime StartDate, DateTime EndDate) GetMonthStartAndEndDates(int year, int month)
    {
        var calendar = new GregorianCalendar();
        var daysInMonth = calendar.GetDaysInMonth(year, month);
        var startDate = new DateTime(year, month, 1);
        var endDate = new DateTime(year, month, daysInMonth);
        return (startDate, endDate);
    }


    /// <summary>
    /// 验证json字符串是否合法
    /// </summary>
    /// <param name="jsonString"></param>
    /// <returns></returns>
    public static bool IsValidJson(string jsonString)
    {
        try
        {
            JToken.Parse(jsonString);
            return true;
        }
        catch (JsonReaderException)
        {
            return false;
        }
    }


    /// <summary>
    /// 常见的双字姓氏列表
    /// </summary>
    private static readonly HashSet<string> commonDoubleSurnames = new HashSet<string>
    {
        "欧阳", "司马", "上官", "夏侯", "诸葛", "东方", "赫连", "皇甫", "尉迟", "公羊",
        "澹台", "公冶", "宗政", "濮阳", "淳于", "单于", "太叔", "申屠", "公孙", "仲孙",
        "轩辕", "令狐", "钟离", "宇文", "长孙", "慕容", "鲜于", "闾丘", "司徒", "司空",
        "亓官", "司寇", "仉督", "子车", "颛孙", "端木", "巫马", "公西", "漆雕", "乐正",
        "壤驷", "公良", "拓跋", "夹谷", "宰父", "谷梁", "晋楚", "闫法", "汝鄢", "涂钦",
        "段干", "百里", "东郭", "南门", "呼延", "归海", "羊舌", "微生", "岳帅", "缑亢",
        "况后", "有琴", "梁丘", "左丘", "东门", "西门", "商牟", "佘佴", "伯赏", "南宫"
    };

    /// <summary>
    /// 中文名字取姓氏和名字
    /// </summary>
    /// <param name="fullName"></param>
    /// <returns>姓:lastName 名:firstName</returns>
    public static (string lastName, string firstName) GetLastNameAndFirstName(string fullName)
    {
        if (string.IsNullOrEmpty(fullName) || fullName.Length < 2) return ("", "");

        // 尝试匹配双字姓氏
        if (fullName.Length > 2)
        {
            string potentialDoubleSurname = fullName.Substring(0, 2);
            if (commonDoubleSurnames.Contains(potentialDoubleSurname))
            {
                string lastName = potentialDoubleSurname;
                string firstName = fullName.Substring(2);
                return (lastName, firstName);
            }
        }

        // 默认单字姓氏
        string singleSurname = fullName.Substring(0, 1);
        string remainingName = fullName.Substring(1);
        return (singleSurname, remainingName);
    }

    /// <summary>
    /// 中文名字转拼音
    /// </summary>
    /// <param name="chineseName"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static string ConvertToPinyin(string chineseName)
    {
        if (string.IsNullOrEmpty(chineseName)) return "";

        return PinyinHelper.GetPinyin(chineseName, "").ToUpper();
    }

    #region stringBuilder 扩展

    /// <summary>
    /// StringBuilder 验证是否有值
    /// </summary>
    /// <param name="sb"></param>
    /// <returns></returns>
    public static bool HasValue(this StringBuilder sb)
    {
        return sb != null && sb.Length > 0;
    }
    #endregion

}