using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;

namespace Serein.NodeFlow.Tool;

/// <summary>
/// 节点方法描述帮助类
/// </summary>
public static class NodeMethodDetailsHelper
{

    /// <summary>
    /// 获取处理方法
    /// </summary>
    public static IEnumerable<MethodInfo> GetMethodsToProcess(Type type)
    {
        return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
                       .Where(m => m.GetCustomAttribute<NodeActionAttribute>()?.Scan == true);
    }

    /// <summary>
    /// 创建方法信息/委托信息
    /// </summary>
    /// <param name="type">方法所属的类型</param>
    /// <param name="methodInfo">方法信息</param>
    /// <param name="assemblyName">方法所属的程序集名称</param>
    /// <param name="outMethodInfo">传出的方法信息</param>
    /// <param name="methodDetails">创建的方法描述，用来生成节点信息</param>
    /// <param name="delegateDetails">方法对应的Emit动态委托</param>
    /// <returns>指示是否创建成功</returns>
    public static bool TryCreateDetails(Type type, 
                                        MethodInfo methodInfo,  
                                        string assemblyName,
                                        [NotNullWhen(true)] out MethodInfo? outMethodInfo,
                                        [NotNullWhen(true)] out MethodDetails? methodDetails,
                                        [NotNullWhen(true)] out DelegateDetails? delegateDetails)
    {
        

        var attribute = methodInfo.GetCustomAttribute<NodeActionAttribute>();
        if(attribute is null || attribute.Scan == false)
        {
            outMethodInfo = null;
            methodDetails = null;
            delegateDetails = null;
            return false;
        }
        
        var methodName = $"{assemblyName}.{type.Name}.{methodInfo.Name}";
        
        // 创建参数信息
        var explicitDataOfParameters = GetExplicitDataOfParameters(methodInfo.GetParameters());

        //// 通过表达式树生成委托
        //var methodDelegate = GenerateMethodDelegate(type,   // 方法所在的对象类型
        //                                            method, // 方法信息
        //                                            method.GetParameters(),// 方法参数
        //                                            method.ReturnType);// 返回值

        

        Type? returnType;
        bool isAsync = EmitHelper.IsGenericTask(methodInfo.ReturnType, out var taskResult);
        bool isStatic = methodInfo.IsStatic;


        if (attribute.MethodDynamicType == Library.NodeType.UI)
        {
            if (isAsync)
            {
                var innerType = methodInfo.ReturnType.GetGenericArguments()[0];
                if (innerType.IsGenericType && innerType != typeof(IEmbeddedContent))
                {
                    SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建，因为UI方法的返回值并非IEmbeddedContent，流程工作台将无法正确显示自定义控件界面以及传递数据。");
                    outMethodInfo = null;
                    methodDetails = null;
                    delegateDetails = null;
                    return false;
                }
            }
            else
            {
                if (methodInfo.ReturnType != typeof(IEmbeddedContent))
                {
                    SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建，因为UI方法的返回值并非IEmbeddedContent，流程工作台将无法正确显示自定义控件界面以及传递数据。");
                    outMethodInfo = null;
                    methodDetails = null;
                    delegateDetails = null;
                    return false;
                }
            }
          
        }

        // 对于触发器
        if (attribute.MethodDynamicType == Library.NodeType.Flipflop)
        {
            if (methodInfo.ReturnType.IsGenericType && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
            {
                // 获取 Task<> 的泛型参数类型
                var innerType = methodInfo.ReturnType.GetGenericArguments()[0];
                if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(IFlipflopContext<>))
                {
                    var flipflopType = innerType.GetGenericArguments()[0];
                    returnType = flipflopType;
                }
                else
                {
                    SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建，返回类型非预期的Task<IFlipflopContext<TResult>>。");
                    outMethodInfo = null;
                    methodDetails = null;
                    delegateDetails = null;
                    return false;
                }
            }
            else
            {
                SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建，因为触发器方法的返回值并非Task<>，将无法等待。");
                outMethodInfo = null;
                methodDetails = null;
                delegateDetails = null;
                return false;
            }
        }
        
        else if(isAsync)
        {
            returnType = taskResult is null ? typeof(Task) : taskResult;
        }
        else
        {
            returnType = methodInfo.ReturnType;
        }

        if (string.IsNullOrEmpty(attribute.AnotherName)){
            attribute.AnotherName = methodInfo.Name;
        }

        var asyncPrefix = "[异步]"; // IsGenericTask(returnType) ? "[async]" : ;
        var methodMethodAnotherName = isAsync ? asyncPrefix + attribute.AnotherName : attribute.AnotherName;

        bool hasParamsArg = false;
        if (explicitDataOfParameters.Length > 0)
        {
            hasParamsArg = explicitDataOfParameters[^1].IsParams; // 取最后一个参数描述，判断是否为params 入参
        }

        var md = new MethodDetails() // 从DLL生成方法描述（元数据）
        {
            ActingInstanceType = type,
            // ActingInstance = instance, 
            MethodName = NodeMethodDetailsHelper.GetMethodSignature(methodInfo),
            AssemblyName = assemblyName,
            MethodDynamicType = attribute.MethodDynamicType,
            MethodLockName = attribute.LockName,
            MethodAnotherName = methodMethodAnotherName,
            ParameterDetailss = explicitDataOfParameters,
            ReturnType = returnType,
            // 如果存在可变参数，取最后一个元素的下标，否则为-1；
            ParamsArgIndex = hasParamsArg ? explicitDataOfParameters.Length - 1 : -1,
            IsAsync = isAsync,
            IsStatic = isStatic,
        };

        //var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var methodDelegate);// 返回值


        var dd = new DelegateDetails(methodInfo) ; // 构造委托
        outMethodInfo = methodInfo;
        methodDetails = md;
        delegateDetails = dd;
        return true;

    }

    /// <summary>
    /// 获取方法签名
    /// </summary>
    /// <param name="method"></param>
    /// <returns></returns>
    public static string GetMethodSignature(MethodInfo method)
    {
        if (method == null) return string.Empty;

        string methodName = method.Name;
        //string returnType = method.ReturnType.Name;
        string parameters = string.Join(", ", method.GetParameters()
            .Select(p => $"{p.ParameterType.Name} {p.Name}"));

        return $"{methodName}({parameters})";
        //return $"{methodName}({parameters}) : {returnType}";
    }
   
    


    private static ConcurrentDictionary<string, (object, MethodInfo)> ConvertorInstance =[];

    /// <summary>
    /// 获取参数信息
    /// </summary>
    /// <param name="parameters"></param>
    /// <returns></returns>
    private static ParameterDetails[] GetExplicitDataOfParameters(ParameterInfo[] parameters)
    {

        var tempParams =  parameters.Select((it, index) =>
        {
            Type paremType;

            #region 存在“枚举=>类型”转换器
            if (it.GetCustomAttribute<EnumTypeConvertorAttribute>() is EnumTypeConvertorAttribute attribute1 && attribute1 is not null)
            {
                // 存在类型选择器
                paremType = attribute1.EnumType;
                return GetExplicitDataOfParameter(it, index, paremType, true); // “枚举=>类型”转换器 获取参数
            }
            #endregion
            #region 存在自定义的转换器
#if false
            else if (it.GetCustomAttribute<BindConvertorAttribute>() is BindConvertorAttribute attribute2 && attribute2 is not null)
            {
                paremType = attribute2.EnumType;

                string key = typeof(IEnumConvertor<,>).FullName + attribute2.EnumType.FullName + attribute2.ConvertorType.FullName;

                if (!ConvertorInstance.ContainsKey(key))
                {
                    Type enumConvertorType = typeof(IEnumConvertor<,>);
                    // 定义具体类型
                    Type specificType = enumConvertorType.MakeGenericType(attribute2.EnumType, it.ParameterType);
                    // 获取实现类的类型
                    Type implementorType = attribute2.ConvertorType;
                    // 创建实现类的实例
                    object instance = Activator.CreateInstance(implementorType);
                    // 调用 Convert 方法
                    MethodInfo convertMethod = implementorType.GetMethod("Convertor");
                    ConvertorInstance[key] = (instance, convertMethod);
                }

                //object func(object enumValue)
                //{
                //    (var obj, var methodInfo) = ConvertorInstance[key];
                //    return methodInfo?.Invoke(obj, [enumValue]);
                //}

                // 确保实例实现了所需接口
                ParameterDetails ed = GetExplicitDataOfParameter(it, index, paremType, true);  // 自定义的转换器 获取参数

                return ed;
            }

#endif
            #endregion
            #region 常规方法的获取参数
            else
            {
                var tmp = GetExplicitDataOfParameter(it, index, it.ParameterType, it.HasDefaultValue); // 常规方法的获取参数
                return tmp;
            } 
            #endregion
        }).ToArray();

       /* foreach(var pd in tempParams)
        {
            var argType = pd.DataType;
            // 运行环境
            if (typeof(IFlowEnvironment).IsAssignableFrom(argType))
            {
                continue;
            }
            // 流程上下文
            if (typeof(IDynamicContext).IsAssignableFrom(argType))
            {
                continue;
            }
            // 节点模型
            if (typeof(NodeModelBase).IsAssignableFrom(argType))
            {
                continue;
            }
            
        }*/
       
        return tempParams;
    }

    private static ParameterDetails GetExplicitDataOfParameter(ParameterInfo parameterInfo,
                                                               int index,
                                                               Type explicitParemType,
                                                               bool isExplicitData)
    {

        bool hasParams = parameterInfo.IsDefined(typeof(ParamArrayAttribute)); // 判断是否为可变参数
        Type dataType;
        if (hasParams && parameterInfo.ParameterType.GetElementType() is Type paramsArgType) // 获取可变参数的子项类型
        {
            // 可选参数为 Array 类型，所以需要获取子项类型
            // 如果 hasParams 为 true ，说明一定存在可选参数，所以 paramsArgType 一定不为 null
            dataType = paramsArgType;
            explicitParemType = paramsArgType;
        }
        else
        {
            dataType = parameterInfo.ParameterType;
        }
        isExplicitData = true;
        string description = string.Empty; // 入参描述
        var nodeParmsAttribute = parameterInfo.GetCustomAttribute<NodeParamAttribute>();
        if(nodeParmsAttribute is not null)
        {
            if (!parameterInfo.HasDefaultValue)
            {
                isExplicitData  = nodeParmsAttribute.IsExplicit; // 设置是否是显式参数
            }
            if (string.IsNullOrEmpty(nodeParmsAttribute.Name)) 
            {
                description = nodeParmsAttribute.Name; // 设置显示的名称
            }
            
        }
        else
        {
            description = parameterInfo.GetCustomAttribute<DescriptionAttribute>()?.Description ?? string.Empty; // 判断是否存在注释特性
        }
        

        var inputType = GetInputType(explicitParemType);
        var items = GetExplicitItems(explicitParemType, inputType);
        //if ("Bool".Equals(inputType)) inputType = "Select"; // 布尔值 转为 可选类型
        return new ParameterDetails
        {
            IsExplicitData = isExplicitData, //attribute is null ? parameterInfo.HasDefaultValue : true,
            Index = index, // 索引
            InputType = inputType, // Select/Bool/Value
            ExplicitType = explicitParemType,// 显示的入参类型
            //Convertor = func, // 转换器
            DataType = dataType, // 实际的入参类型
            Name = parameterInfo.Name,
            DataValue = parameterInfo.HasDefaultValue ? parameterInfo?.DefaultValue?.ToString() : "", // 如果存在默认值，则使用默认值
            Items = items.ToArray(), // 如果是枚举值入参，则获取枚举类型的字面量
            IsParams = hasParams,  // 判断是否为可变参数
            Description = description // 入参描述

        };

    }



    /// <summary>
    /// 判断使用输入器还是选择器
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private static ParameterValueInputType GetInputType(Type type)
    {
        
        return type switch
        {
            Type t when t.IsEnum => ParameterValueInputType.Select,
            Type t when t == typeof(bool) => ParameterValueInputType.Select,
            Type t when t == typeof(string) => ParameterValueInputType.Input,
            Type t when t == typeof(int) => ParameterValueInputType.Input,
            Type t when t == typeof(double) => ParameterValueInputType.Input,
            _ => ParameterValueInputType.Input
        };
    }


    /// <summary>
    /// 获取参数列表选项
    /// </summary>
    /// <param name="type"></param>
    /// <param name="InputType"></param>
    /// <returns></returns>
    private static IEnumerable<string> GetExplicitItems(Type type, ParameterValueInputType InputType)
    {
        IEnumerable<string>  items =  InputType switch
        {
            ParameterValueInputType.Select when type == typeof(bool) => ["True", "False"],
            ParameterValueInputType.Select  => Enum.GetNames(type),
            _ => []
        };
        return items;
    }

    //private static Delegate GenerateMethodDelegate(Type type, MethodInfo methodInfo, ParameterInfo[] parameters, Type returnType)
    //{
    //    var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
    //    var parameterCount = parameters.Length;

    //    if (returnType == typeof(void))
    //    {
    //        if (parameterCount == 0)
    //        {
    //            // 无返回值，无参数
    //            return ExpressionHelper.MethodCaller(type, methodInfo);
    //        }
    //        else
    //        {
    //            // 无返回值，有参数
    //            return ExpressionHelper.MethodCaller(type, methodInfo, parameterTypes);
    //        }
    //    }
    //    // else if (returnType == typeof(Task<FlipflopContext)) // 触发器
    //    else if (FlipflopFunc.IsTaskOfFlipflop(returnType)) // 触发器
    //    {
    //        if (parameterCount == 0)
    //        {
    //            // 有返回值，无参数
    //            return ExpressionHelper.MethodCallerAsync(type, methodInfo);
    //        }
    //        else
    //        {
    //            // 有返回值，有参数
    //            return ExpressionHelper.MethodCallerAsync(type, methodInfo, parameterTypes);
    //        }
    //    }
    //    else
    //    {
    //        if (parameterCount == 0)
    //        {
    //            // 有返回值，无参数
    //            return ExpressionHelper.MethodCallerHaveResult(type, methodInfo);
    //        }
    //        else
    //        {
    //            // 有返回值，有参数
    //            return ExpressionHelper.MethodCallerHaveResult(type, methodInfo, parameterTypes);
    //        }
    //    }
    //}

}


