using Newtonsoft.Json;
using SqlSugar;

namespace Tiobon.Core;

/// <summary>
/// 
/// </summary>
public static class UtilHelper
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <returns></returns>
    public static int ObjToInt(this object thisValue)
    {
        int reval = 0;
        if (thisValue == null) return 0;
        if (thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
        {
            return reval;
        }

        return reval;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <param name="errorValue"></param>
    /// <returns></returns>
    public static int ObjToInt(this object thisValue, int errorValue)
    {
        int reval = 0;
        if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
        {
            return reval;
        }

        return errorValue;
    }

    public static long ObjToLong(this object thisValue)
    {
        long reval = 0;
        if (thisValue == null) return 0;
        if (thisValue != DBNull.Value && long.TryParse(thisValue.ToString(), out reval))
        {
            return reval;
        }

        return reval;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <returns></returns>
    public static double ObjToMoney(this object thisValue)
    {
        double reval = 0;
        if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
        {
            return reval;
        }

        return 0;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <param name="errorValue"></param>
    /// <returns></returns>
    public static double ObjToMoney(this object thisValue, double errorValue)
    {
        double reval = 0;
        if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
        {
            return reval;
        }

        return errorValue;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <returns></returns>
    public static string ObjToString(this object thisValue)
    {
        if (thisValue != null) return thisValue.ToString().Trim();
        return "";
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <returns></returns>
    public static bool IsNotEmptyOrNull(this object thisValue)
    {
        return ObjToString(thisValue) != "" && ObjToString(thisValue) != "undefined" &&
               ObjToString(thisValue) != "null";
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <param name="errorValue"></param>
    /// <returns></returns>
    public static string ObjToString(this object thisValue, string errorValue)
    {
        if (thisValue != null) return thisValue.ToString().Trim();
        return errorValue;
    }

    public static bool IsNullOrEmpty(this object thisValue) => thisValue == null || thisValue == DBNull.Value ||
                                                               string.IsNullOrWhiteSpace(thisValue.ToString());

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <returns></returns>
    public static Decimal ObjToDecimal(this object thisValue)
    {
        Decimal reval = 0;
        if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
        {
            return reval;
        }

        return 0;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <param name="errorValue"></param>
    /// <returns></returns>
    public static Decimal ObjToDecimal(this object thisValue, decimal errorValue)
    {
        Decimal reval = 0;
        if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
        {
            return reval;
        }

        return errorValue;
    }



    #region 去除后面多余的零
    /// <summary>
    /// 去除后面多余的零
    /// </summary>
    /// <param name="dValue"></param>
    /// <returns></returns>
    public static string RemoveZero(this decimal? dValue)
    {
        if (dValue.IsNullOrEmpty())
            return null;
        return RemoveZero(dValue.Value);
    }
    ///// <summary>
    ///// 去除后面多余的零
    ///// </summary>
    ///// <param name="dValue"></param>
    ///// <returns></returns>
    //public static string RemoveZero(decimal? dValue)
    //{
    //    if (dValue.IsNullOrEmpty())
    //        return null;
    //    return RemoveZero(dValue.Value);
    //}
    /// <summary>
    /// 去除后面多余的零
    /// </summary>
    /// <param name="dValue"></param>
    /// <returns></returns>
    public static string RemoveZero(decimal dValue)
    {
        string sResult = dValue.ToString();
        if (sResult.IndexOf(".") < 0)
            return sResult;
        int iIndex = sResult.Length - 1;
        for (int i = sResult.Length - 1; i >= 0; i--)
        {
            if (sResult.Substring(i, 1) != "0")
            {
                iIndex = i;
                break;
            }
        }
        sResult = sResult.Substring(0, iIndex + 1);
        if (sResult.EndsWith("."))
            sResult = sResult.Substring(0, sResult.Length - 1);
        return sResult;
    }

    public static string TrimDecimalString(this decimal? value1, int reservedDigit)
    {
        try
        {
            var value = value1.RemoveZero();
            string result = string.Empty;
            if (!string.IsNullOrEmpty(value))
            {
                Decimal tmp = Decimal.Parse(value);
                if (reservedDigit == -1)
                    result = string.Format("{0:#0.##########}", tmp);
                else
                {
                    result = String.Format("{0:N" + reservedDigit.ToString() + "}", tmp);
                    result = result.Replace(",", "");
                }
            }
            return result;
        }
        catch (Exception) { return null; }
    }
    public static decimal? TrimDecimal(this decimal? value1, int reservedDigit)
    {
        try
        {
            var value = value1.TrimDecimalString(reservedDigit);
            string result = string.Empty;
            if (!string.IsNullOrEmpty(value))
            {
                Decimal tmp = Decimal.Parse(value);
                if (reservedDigit == -1)
                    result = string.Format("{0:#0.##########}", tmp);
                else
                {
                    result = String.Format("{0:N" + reservedDigit.ToString() + "}", tmp);
                    result = result.Replace(",", "");
                }
            }
            return Convert.ToDecimal(result);
        }
        catch (Exception) { return null; }
    }
    #endregion

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <returns></returns>
    public static DateTime ObjToDate(this object thisValue)
    {
        DateTime reval = DateTime.MinValue;
        if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
        {
            reval = Convert.ToDateTime(thisValue);
        }
        else
        {
            //时间戳转为时间
            var seconds = ObjToLong(thisValue);
            if (seconds > 0)
            {
                var startTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Local);
                reval = startTime.AddSeconds(Convert.ToDouble(thisValue));
            }
        }

        return reval;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <param name="errorValue"></param>
    /// <returns></returns>
    public static DateTime ObjToDate(this object thisValue, DateTime errorValue)
    {
        DateTime reval = DateTime.MinValue;
        if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
        {
            return reval;
        }

        return errorValue;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisValue"></param>
    /// <returns></returns>
    public static bool ObjToBool(this object thisValue)
    {
        bool reval = false;
        if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval))
        {
            return reval;
        }

        return reval;
    }


    /// <summary>
    /// 获取当前时间的时间戳
    /// </summary>
    /// <param name="thisValue"></param>
    /// <returns></returns>
    public static string DateToTimeStamp(this DateTime thisValue)
    {
        TimeSpan ts = thisValue - new DateTime(1970, 1, 1, 0, 0, 0, 0);
        return Convert.ToInt64(ts.TotalSeconds).ToString();
    }

    public static object ChangeType(this object value, Type type)
    {
        if (value == null && type.IsGenericType) return Activator.CreateInstance(type);
        if (value == null) return null;
        if (type == value.GetType()) return value;
        if (type.IsEnum)
        {
            if (value is string)
                return Enum.Parse(type, value as string);
            else
                return Enum.ToObject(type, value);
        }

        if (!type.IsInterface && type.IsGenericType)
        {
            Type innerType = type.GetGenericArguments()[0];
            object innerValue = ChangeType(value, innerType);
            return Activator.CreateInstance(type, new object[] { innerValue });
        }

        if (value is string && type == typeof(Guid)) return new Guid(value as string);
        if (value is string && type == typeof(Version)) return new Version(value as string);
        if (!(value is IConvertible)) return value;
        return Convert.ChangeType(value, type);
    }

    public static object ChangeTypeList(this object value, Type type)
    {
        if (value == null) return default;

        var gt = typeof(List<>).MakeGenericType(type);
        dynamic lis = Activator.CreateInstance(gt);

        var addMethod = gt.GetMethod("Add");
        string values = value.ToString();
        if (values != null && values.StartsWith("(") && values.EndsWith(")"))
        {
            string[] splits;
            if (values.Contains("\",\""))
            {
                splits = values.Remove(values.Length - 2, 2)
                    .Remove(0, 2)
                    .Split("\",\"");
            }
            else
            {
                splits = values.Remove(0, 1)
                    .Remove(values.Length - 2, 1)
                    .Split(",");
            }

            foreach (var split in splits)
            {
                var str = split;
                if (split.StartsWith("\"") && split.EndsWith("\""))
                {
                    str = split.Remove(0, 1)
                        .Remove(split.Length - 2, 1);
                }

                addMethod.Invoke(lis, new object[] { ChangeType(str, type) });
            }
        }

        return lis;
    }

    public static string ToJson(this object value)
    {
        return JsonConvert.SerializeObject(value);
    }

    public static bool AnyNoException<T>(this ICollection<T> source)
    {
        if (source == null) return false;

        return source.Any() && source.All(s => s != null);
    }

    public static bool IsNull(this long? thisValue)
    {
        return thisValue is null;
    }
    public static bool IsNull(this int? thisValue)
    {
        return thisValue is null;
    }
    public static bool IsNull(this decimal? thisValue)
    {
        return thisValue is null;
    }
    public static bool IsNull(this string thisValue)
    {
        return string.IsNullOrWhiteSpace(thisValue);
    }
    public static bool IsNull(this DateTime? thisValue)
    {
        return thisValue is null;
    }
    public static bool IsNull<T>(this T entity) where T : class
    {
        return entity == null;
    }

    public static long GetSysId() => SnowFlakeSingle.instance.getID();

}