using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace StandardLibrary
{
    public static class PropertyPathExtractor
    {
        /// <summary>
        /// 获得类型下的所有基本类型的访问路径
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<string> GetLeafPropertyPaths(Type type)
        {
            if (type == null) return new List<string>();
            var visited = new HashSet<Type>();
            var paths = new List<string>();
            Traverse(type, "", paths, visited);
            return paths;
        }

        private static void Traverse(Type type, string prefix, List<string> paths, HashSet<Type> visited)
        {
            if (type == null || IsSimpleType(type)) return;

            if (!visited.Add(type)) // 防止循环引用
                return;

            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var prop in properties)
            {
                if (prop.GetIndexParameters().Length > 0) continue; // 跳过索引器

                string currentPath = string.IsNullOrEmpty(prefix)
                    ? prop.Name
                    : $"{prefix}.{prop.Name}";

                if (IsSimpleType(prop.PropertyType))
                {
                    // 只有叶子节点（基本类型）才加入路径
                    paths.Add(currentPath);
                }
                else
                {
                    // 非简单类型：继续递归，但不记录 currentPath 本身
                    Traverse(prop.PropertyType, currentPath, paths, visited);
                }
            }

            visited.Remove(type); // 回溯（可选）
        }

        private static bool IsSimpleType(Type type)
        {
            if (type == null) return true;
            if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal))
                return true;
            if (type.IsEnum)
                return true;
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                return IsSimpleType(type.GetGenericArguments()[0]);
            return false;
        }
    }

    public static class PropertyPathHelper
    {
        //PropertyPathHelper.GetPath(()=>a.b.c)，输出a.b.c 
        public static string GetPath<T>(Expression<Func<T>> expression)
        {
            return GetMemberPath(expression.Body);
        }

        private static string GetMemberPath(Expression expression)
        {
            switch (expression)
            {
                case MemberExpression memberExpr:
                    if (memberExpr.Expression is ParameterExpression)
                        return memberExpr.Member.Name; // 顶层变量（实际不会出现，因为是 Func<T>）

                    string parentPath = GetMemberPath(memberExpr.Expression);
                    return parentPath + "." + memberExpr.Member.Name;

                case ConstantExpression constExpr:
                    // 静态成员或 null 常量，无法构成路径
                    //throw new ArgumentException("表达式不能包含常量或静态成员");
                    return constExpr.Value.ToString();
                default:
                    throw new ArgumentException($"不支持的表达式类型: {expression.GetType().Name}");
            }
        }
    }

    public static class PropertyFinder
    {
        /// <summary>
        /// 查找指定对象的（非静态）属性中，值为 T 类型（或其派生类）的所有实例。
        /// 不递归，仅检查当前对象的属性。
        /// </summary>
        public static List<T> FindPropertiesOfType<T>(object obj) where T : class
        {
            if (obj == null)
                return new List<T>();

            var result = new List<T>();
            var type = obj.GetType();

            // 获取所有实例属性（包括私有属性，如不需要可调整 BindingFlags）
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            foreach (var prop in properties)
            {
                if (!prop.CanRead)
                    continue;

                // 跳过索引器（如 this[int i]）
                if (prop.GetIndexParameters().Length > 0)
                    continue;

                try
                {
                    var value = prop.GetValue(obj) as T;
                    if (value != null)
                    {
                        result.Add(value);
                    }
                }
                catch (Exception)
                {
                    // 忽略无法读取的属性（如抛异常的 lazy 属性等）
                }
            }

            return result;
        }
    }
    public static class ObjectPropertySetter
    {
        /// <summary>
        /// Sets the value of a nested property on the specified target object, navigating through the property path.
        /// </summary>
        /// <remarks>This method supports setting values on nested properties by navigating through the
        /// specified property path. If any intermediate property in the path is <see langword="null"/>, an instance of
        /// the corresponding type will be created, provided the type has a parameterless constructor. The final
        /// property in the path will be assigned the specified value, which will be converted to the property's type if
        /// necessary.</remarks>
        /// <param name="target">The object on which the property value will be set. Cannot be <see langword="null"/>.</param>
        /// <param name="propertyPath">The dot-separated path of the property to set. Each segment represents a property name in the hierarchy.</param>
        /// <param name="value">The value to assign to the specified property. The value will be converted to the property's type if
        /// necessary.</param>
        /// <exception cref="ArgumentException">Thrown if a property in the path does not exist on the corresponding object type.</exception>
        /// <exception cref="InvalidOperationException">Thrown if an intermediate property in the path is <see langword="null"/> and cannot be instantiated due to
        /// the absence of a parameterless constructor.</exception>
        public static void SetPropertyValue(object target, string propertyPath, object value)
        {
            var parts = propertyPath.Split('.');
            object current = target;

            for (int i = 0; i < parts.Length; i++)
            {
                var propName = parts[i];
                var prop = current.GetType().GetProperty(propName,
                    BindingFlags.Public | BindingFlags.Instance);

                if (prop == null)
                    throw new ArgumentException($"Property '{propName}' not found on type {current.GetType()}.");

                if (i == parts.Length - 1)
                {
                    // 最后一级：赋值
                    var convertedValue = ConvertValue(value, prop.PropertyType);
                    prop.SetValue(current, convertedValue);
                }
                else
                {
                    // 中间级：获取子对象，若为 null 则创建（仅支持无参构造）
                    var subObject = prop.GetValue(current);
                    if (subObject == null)
                    {
                        var subType = prop.PropertyType;
                        if (subType.GetConstructor(Type.EmptyTypes) == null)
                            throw new InvalidOperationException($"Cannot create instance of {subType} (no parameterless constructor).");
                        subObject = Activator.CreateInstance(subType);
                        prop.SetValue(current, subObject);
                    }
                    current = subObject;
                }
            }
        }
        /// <summary>
        /// Converts the specified value to the specified target type.
        /// </summary>
        /// <remarks>This method supports conversion between compatible types, including basic types and
        /// enums. If the target type is an enumeration, the method attempts to convert the value to the corresponding
        /// enum value.</remarks>
        /// <param name="value">The value to convert. Can be null.</param>
        /// <param name="targetType">The type to which the value should be converted. Must not be null.</param>
        /// <returns>The converted value as an object of the specified target type, or null if <paramref name="value"/> is null.</returns>
        /// <exception cref="InvalidOperationException">Thrown if the conversion cannot be performed, such as when the value is incompatible with the target type.</exception>
        private static object ConvertValue(object value, Type targetType)
        {
            if (value == null)
            {
                // 返回 targetType 的 default 值，而不是简单返回 null
                return GetDefaultValue(targetType);
            }

            var sourceType = value.GetType();
            if (targetType.IsAssignableFrom(sourceType))
                return value;

            // 尝试类型转换（支持基本类型）
            try
            {
                if (targetType.IsEnum)
                    return Enum.ToObject(targetType, value);

                return Convert.ChangeType(value, targetType);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"Cannot convert {value} ({sourceType}) to {targetType}", ex);
            }
        }
        public static object GetDefaultValue(Type type)
        {
            if (type == null) throw new ArgumentNullException(nameof(type));

            // 引用类型（包括 string）或可空值类型（如 int?）的 default 是 null
            if (!type.IsValueType)
                return null;

            // 值类型：使用 Activator.CreateInstance 返回其零初始化值
            return Activator.CreateInstance(type);
        }
    }
}
