using System;
using System.ComponentModel;
using System.Globalization;
namespace Masuit.Tools;
public static class IConvertibleExtensions
{
    public static bool IsNumeric(this Type type)
    {
        switch (Type.GetTypeCode(type))
        {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Single:
                return true;
            default:
                return false;
        }
    }
    /// 
    /// 类型直转
    /// 
    /// 
    /// 
    /// 
    public static T ConvertTo(this IConvertible value) where T : IConvertible
    {
        if (value != null)
        {
            var type = typeof(T);
            if (value.GetType() == type)
            {
                return (T)value;
            }
            if (type.IsNumeric())
            {
                return (T)value.ToType(type, new NumberFormatInfo());
            }
            if (value == DBNull.Value)
            {
                return default;
            }
            if (type.IsEnum)
            {
                return (T)Enum.Parse(type, value.ToString(CultureInfo.InvariantCulture));
            }
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                var underlyingType = Nullable.GetUnderlyingType(type);
                return (T)(underlyingType!.IsEnum ? Enum.Parse(underlyingType, value.ToString(CultureInfo.CurrentCulture)) : Convert.ChangeType(value, underlyingType));
            }
            TypeConverter converter = TypeDescriptor.GetConverter(value);
            if (converter != null)
            {
                if (converter.CanConvertTo(type))
                {
                    return (T)converter.ConvertTo(value, type);
                }
            }
            converter = TypeDescriptor.GetConverter(type);
            if (converter != null)
            {
                if (converter.CanConvertFrom(value.GetType()))
                {
                    return (T)converter.ConvertFrom(value);
                }
            }
            return (T)Convert.ChangeType(value, type);
        }
        return (T)value;
    }
    /// 
    /// 类型直转
    /// 
    /// 
    /// 
    /// 转换失败的默认值
    /// 
    public static T TryConvertTo(this IConvertible value, T defaultValue = default) where T : IConvertible
    {
        try
        {
            return ConvertTo(value);
        }
        catch
        {
            return defaultValue;
        }
    }
    /// 
    /// 类型直转
    /// 
    /// 
    /// 
    /// 转换失败的默认值
    /// 
    public static bool TryConvertTo(this IConvertible value, out T result) where T : IConvertible
    {
        try
        {
            result = ConvertTo(value);
            return true;
        }
        catch
        {
            result = default;
            return false;
        }
    }
    /// 
    /// 类型直转
    /// 
    /// 
    /// 目标类型
    /// 转换失败的默认值
    /// 
    public static bool TryConvertTo(this IConvertible value, Type type, out object result)
    {
        try
        {
            result = ConvertTo(value, type);
            return true;
        }
        catch
        {
            result = default;
            return false;
        }
    }
    /// 
    /// 类型直转
    /// 
    /// 
    /// 目标类型
    /// 
    public static object ConvertTo(this IConvertible value, Type type)
    {
        if (value == null)
        {
            return default;
        }
        if (value.GetType() == type)
        {
            return value;
        }
        if (value == DBNull.Value)
        {
            return null;
        }
        if (type.IsEnum)
        {
            return Enum.Parse(type, value.ToString(CultureInfo.InvariantCulture));
        }
        if (type.IsNumeric())
        {
            return value.ToType(type, new NumberFormatInfo());
        }
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            var underlyingType = Nullable.GetUnderlyingType(type);
            return underlyingType!.IsEnum ? Enum.Parse(underlyingType, value.ToString(CultureInfo.CurrentCulture)) : Convert.ChangeType(value, underlyingType);
        }
        var converter = TypeDescriptor.GetConverter(value);
        if (converter != null)
        {
            if (converter.CanConvertTo(type))
            {
                return converter.ConvertTo(value, type);
            }
        }
        converter = TypeDescriptor.GetConverter(type);
        if (converter != null)
        {
            if (converter.CanConvertFrom(value.GetType()))
            {
                return converter.ConvertFrom(value);
            }
        }
        return Convert.ChangeType(value, type);
    }
}