using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using Newtonsoft.Json;
using SGModule.Common.Helper;

namespace SGModule.Common.Extensions {
    /// <summary>
    ///     提供通用对象类型转换的扩展方法，支持数值类型、字符串、枚举、集合、时间等多种类型间的智能转换。
    /// </summary>
    public static class ObjectExtensions {
        /// <summary>
        ///     将对象强制转换为目标类型 <typeparamref name="T" />，转换失败时返回默认值。
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="value">待转换的对象</param>
        /// <param name="defaultValue">转换失败时返回的默认值</param>
        /// <param name="format">可选格式字符串（如用于时间或数值格式化）</param>
        /// <param name="formatProvider">格式化提供者，默认为当前区域设置</param>
        /// <returns>转换后的目标类型值，或 <paramref name="defaultValue" />。</returns>
        /// <example>
        ///     字符串到基本类型
        ///     <code>
        /// "123".As&lt;int&gt;();                   // 输出 123
        /// "45.67".As&lt;float&gt;();               // 输出 45.67f
        /// "true".As&lt;bool&gt;();                 // 输出 true
        /// "2023-01-01".As&lt;DateTime&gt;();       // 输出 2023-01-01
        /// "".As&lt;int&gt;();                      // 输出 0
        /// ((string)null).As&lt;int&gt;();          // 输出 0
        /// "abc".As&lt;int&gt;();                   // 输出 0（无法转换）
        /// "1.23E+5".As&lt;float&gt;();             // 输出 123000f
        /// .....
        /// </code>
        /// </example>
        public static T As<T>(this object value, T defaultValue = default, string format = null, IFormatProvider formatProvider = null) {
            return (T) As(value, typeof(T), defaultValue, format, formatProvider);
        }

        /// <summary>
        ///     将对象转换为指定的目标类型。
        ///     支持基础类型转换、字符串与 JSON 互转、枚举解析、集合映射、Base64 处理等。
        /// </summary>
        /// <param name="value">要转换的对象</param>
        /// <param name="targetType">目标类型</param>
        /// <param name="defaultValue">转换失败时的返回值</param>
        /// <param name="format">可选的格式字符串（用于时间、数字格式化）</param>
        /// <param name="formatProvider">格式提供者（区域信息），默认为当前区域</param>
        /// <returns>转换结果或默认值</returns>
        public static object As(this object value, Type targetType, object defaultValue = null, string format = null, IFormatProvider formatProvider = null) {
            if (value == null || value == DBNull.Value) {
                return defaultValue;
            }

            formatProvider ??= CultureInfo.CurrentCulture;

            try {
                // 1. 类型兼容直接返回
                if (targetType.IsInstanceOfType(value)) {
                    return value;
                }

                // 2. 数值类型之间转换（int, float, decimal 等）
                if (value.IsNumericType() && targetType.IsNumericType()) {
                    return Convert.ChangeType(value, targetType, formatProvider);
                }

                // 3. 字符串 ⇄ 字节数组
                if (targetType == typeof(byte[]) && value is string str) {
                    return Encoding.UTF8.GetBytes(str);
                }

                if (targetType == typeof(string) && value is byte[] bytes) {
                    return Encoding.UTF8.GetString(bytes);
                }

                // 4. 转为字符串
                if (targetType == typeof(string)) {
                    if (value is string s) {
                        return s;
                    }

                    if (value.IsNumericType()) {
                        return string.Format(formatProvider, format ?? "{0}", value);
                    }

                    if (value is DateTime dt) {
                        return string.IsNullOrEmpty(format) ? dt.ToString(formatProvider) : dt.ToString(format, formatProvider);
                    }

                    try {
                        return JsonConvert.SerializeObject(value);
                    }
                    catch {
                        return defaultValue;
                    }
                }

                // 5. 从字符串解析为目标类型
                if (value is string strValue) {
                    if (string.IsNullOrWhiteSpace(strValue)) {
                        return defaultValue;
                    }

                    // 字符串 → 枚举
                    if (targetType.IsEnum) {
                        try {
                            return Enum.Parse(targetType, strValue, true);
                        }
                        catch {
                            return defaultValue;
                        }
                    }

                    // 字符串 → 数值
                    if (targetType.IsNumericType()) {
                        return Convert.ChangeType(strValue, targetType, formatProvider);
                    }

                    // 字符串 → 时间
                    if (targetType == typeof(DateTime)) {
                        return string.IsNullOrEmpty(format)
                            ? DateTime.Parse(strValue, formatProvider)
                            : DateTime.ParseExact(strValue, format, formatProvider);
                    }

                    // 字符串 → 自定义类（JSON）
                    if (targetType.IsClass && targetType != typeof(string)) {
                        try {
                            return JsonConvert.DeserializeObject(strValue, targetType);
                        }
                        catch {
                            return defaultValue;
                        }
                    }
                }

                // 6. 集合类型转换（如 List<string> -> List<int>）
                if (targetType.IsGenericListOrArray() && value is IEnumerable enumerable) {
                    var elementType = targetType.GetElementType() ?? targetType.GetGenericArguments()[0];
                    var list = (IList) Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType));

                    foreach (var item in enumerable) {
                        var converted = typeof(ObjectExtensions)
                            .GetMethod("As", new[] { typeof(object), typeof(Type), typeof(object), typeof(string), typeof(IFormatProvider) })
                            ?.Invoke(null, new[] { item, elementType, null, format, formatProvider });

                        list.Add(converted);
                    }

                    return targetType.IsArray ? list.ToArray(elementType) : list;
                }

                // 7. 尝试通过 TypeConverter 转换（主要处理结构体、基础类型）
                if (targetType.IsValueType || targetType == typeof(string)) {
                    var strVal = value.ToString();
                    if (!string.IsNullOrWhiteSpace(strVal)) {
                        var converter = TypeDescriptor.GetConverter(targetType);
                        if (converter.CanConvertFrom(typeof(string))) {
                            return converter.ConvertFrom(null, formatProvider as CultureInfo, strVal);
                        }
                    }
                }

                // 8. Fallback：通过 JSON 转换
                return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), targetType);
            }
            catch {
                return defaultValue;
            }
        }

        #region 🔧 辅助方法

        private static bool IsNumericType(this Type type) {
            return Type.GetTypeCode(type) switch {
                TypeCode.Byte or TypeCode.SByte or TypeCode.UInt16 or TypeCode.UInt32 or
                    TypeCode.UInt64 or TypeCode.Int16 or TypeCode.Int32 or TypeCode.Int64 or
                    TypeCode.Decimal or TypeCode.Double or TypeCode.Single => true,
                _ => false
            };
        }

        private static bool IsNumericType(this object value) {
            return value?.GetType().IsNumericType() ?? false;
        }

        private static bool IsGenericListOrArray(this Type type) {
            return type != null && (type.IsArray ||
                                    (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List<>)
                                                            || type.GetGenericTypeDefinition() == typeof(IList<>))));
        }

        private static Array ToArray(this IList list, Type elementType) {
            var array = Array.CreateInstance(elementType, list.Count);
            list.CopyTo(array, 0);
            return array;
        }

        #endregion
    }

    public static class ObjectExtensionsTest {
        public static void AsTestRun() {
            TestCase("int 到 int", 123.As<int>(), 123);
            TestCase("float 到 int", 123.1f.As<int>(), 123);
            TestCase("double 到 decimal", 99.99.As<decimal>(), 99.99m);
            TestCase("int 到 long", 100.As<long>(), 100L);

            TestCase("字符串 到 int", "123".As<int>(), 123);
            TestCase("字符串 到 float", "45.67".As<float>(), 45.67f);
            TestCase("字符串 到 bool", "true".As<bool>(), true);
            TestCase("字符串 到 DateTime", "2023-01-01".As<DateTime>(), new DateTime(2023, 1, 1));
            TestCase("空字符串 到 int", "".As<int>(), 0);
            TestCase("null字符串 到 int", ((string) null).As<int>(), 0);
            TestCase("非法字符串 到 int", "abc".As<int>(), 0);
            TestCase("科学计数法字符串 到 float", "1.23E+5".As<float>(), 123000f);

            TestCase("int 到 字符串", 42.As<string>(), "42");
            TestCase("float 到 字符串（en-US）", 3.14159f.As<string>(formatProvider: new CultureInfo("en-US")), "3.14159");
            TestCase("float 到 字符串（de-DE）", 3.14159f.As<string>(formatProvider: new CultureInfo("de-DE")), "3,14159");
            TestCase("DateTime 到 字符串（格式化）", new DateTime(2024, 5, 1).As<string>(format: "yyyy-MM-dd"), "2024-05-01");

            TestCase("null 到 int", ((object) null).As<int>(), 0);
            TestCase("null 到 string", ((object) null).As<string>(), null);
            TestCase("DBNull 到 int", DBNull.Value.As<int>(), 0);

            TestCase("枚举 到 string", Color.Red.As<string>(), "Red");
            TestCase("字符串 到 枚举", "Green".As<Color>(), Color.Green);

            var json = "{\"Name\":\"Alice\",\"Age\":30}";
            TestCase("JSON 字符串 到 Person", json.As<Person>().Name, "Alice");
            TestCase("对象 到 JSON 字符串", new Person { Name = "Alice", Age = 30 }.As<string>(), JsonConvert.SerializeObject(new Person { Name = "Alice", Age = 30 }));

            TestCase("字符串数组 到 List<int>", new[] { "1", "2", "3" }.As<List<int>>(), new List<int> { 1, 2, 3 });
            TestCase("List<float> 到 float[]", new List<float> { 1.1f, 2.2f }.As<float[]>(), new[] { 1.1f, 2.2f });
            TestCase("空集合 到 int[]", new string[] { }.As<int[]>(), new int[] { });

            var str = "hello";
            var bytes = Encoding.UTF8.GetBytes(str);
            TestCase("byte[] 到 base64 string", bytes.As<string>(), str);
            TestCase("base64 string 到 byte[]", BitConverter.ToString(str.As<byte[]>()), BitConverter.ToString(bytes));

            TestCase("字符串小数（德语） 到 float", "1,23".As<float>(formatProvider: new CultureInfo("de-DE")), 1.23f);
            TestCase("字符串小数（英语） 到 float", "1.23".As<float>(formatProvider: new CultureInfo("en-US")), 1.23f);

            TestCase("非法 JSON 到 Person（失败返回 null）", "{invalid}".As<Person>(), null);
            TestCase("不能转的对象 到 int", new Person { Name = "A" }.As<int>(), 0);
            TestCase("不能转的对象 到 string（fallback 到 JsonConvert）", new Person { Name = "A", Age = 20 }.As<string>(), JsonConvert.SerializeObject(new Person { Name = "A", Age = 20 }));
        }

        private static void TestCase<T>(string description, T actual, T expected) {
            var isSuccess = CommonUtils.DeepEquals(actual, expected);

            var actualStr = FormatValue(actual);
            var expectedStr = FormatValue(expected);
            var msg = $"{description} => 结果: {actualStr}, 期望: {expectedStr}";
            if (isSuccess) {
                Log.Info("As<T>()", msg);
            }
            else {
                Log.Warning("As<T>()", msg);
            }
        }

        private static string FormatValue<T>(T value) {
            if (value == null) {
                return "null";
            }

            if (value is byte[] byteArray) {
                return $"[{string.Join(", ", byteArray)}]";
            }

            if (value is int[] intArray) {
                return $"[{string.Join(", ", intArray)}]";
            }

            return value.ToString();
        }

        private enum Color {
            Red,
            Green,
            Blue
        }

        private class Person {
            public string Name {
                get;
                set;
            }

            public int Age {
                get;
                set;
            }
        }
    }
}
