using JiShe.CollectBus.Analyzers.Shared;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace JiShe.CollectBus.IncrementalGenerator
{
    /// <summary>
    /// 复杂类型增量源生成器
    /// </summary>
    [Generator(LanguageNames.CSharp)]
    public class ComplexTypeSourceAnalyzers : IIncrementalGenerator
    {
        private const string AttributeFullName = "JiShe.CollectBus.Analyzers.Shared.SourceAnalyzersAttribute";

        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            //Debugger.Launch();

            // 步骤1：筛选带有 [SourceAnalyzers] 的类
            var classDeclarations = context.SyntaxProvider
                .CreateSyntaxProvider(
                    predicate: static (s, _) => IsClassWithAttribute(s),
                    transform: static (ctx, _) => GetClassDeclaration(ctx))
                .Where(static c => c is not null);

            // 步骤2：合并编译信息
            var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());

            context.RegisterSourceOutput(compilationAndClasses, (spc, source) =>
                GenerateCode(source.Left, source.Right!, spc));
        }

        private static bool IsClassWithAttribute(SyntaxNode node) => node is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0;

        private static ClassDeclarationSyntax GetClassDeclaration(GeneratorSyntaxContext context)
        {
            var classDecl = (ClassDeclarationSyntax)context.Node;
            var semanticModel = context.SemanticModel;

            // 获取类符号
            var classSymbol = semanticModel.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
            if (classSymbol == null) return null;

            // 检查是否包含 SourceAnalyzers 特性
            var sourceAnalyzerAttr = classSymbol.GetAttributes().FirstOrDefault(attr => attr.AttributeClass?.ToDisplayString() == AttributeFullName);

            // 必须包含 EntityType 参数
            if (sourceAnalyzerAttr == null ||
                sourceAnalyzerAttr.ConstructorArguments.Length == 0)
            {
                return null;
            }

            return classDecl;

            //var classDecl = (ClassDeclarationSyntax)context.Node;
            //var attributeType = context.SemanticModel.Compilation.GetTypeByMetadataName(AttributeFullName);

            //foreach (var attribute in classDecl.AttributeLists.SelectMany(al => al.Attributes))
            //{
            //    var symbol = context.SemanticModel.GetSymbolInfo(attribute).Symbol;
            //    if (symbol is IMethodSymbol ctor &&
            //        SymbolEqualityComparer.Default.Equals(ctor.ContainingType, attributeType))
            //    {
            //        return classDecl;
            //    }
            //}
            //return null;
        }

        /// <summary>
        /// 递归获取所有层级的属性
        /// </summary>
        /// <param name="classSymbol"></param>
        /// <returns></returns>
        private static IEnumerable<IPropertySymbol> GetAllPropertiesInHierarchy(INamedTypeSymbol classSymbol)
        {
            var currentSymbol = classSymbol;
            while (currentSymbol != null)
            {
                foreach (var prop in currentSymbol.GetMembers().OfType<IPropertySymbol>())
                {
                    yield return prop;
                }
                currentSymbol = currentSymbol.BaseType; // 向上遍历基类
            }
        }

        /// <summary>
        /// 生成代码
        /// </summary>
        /// <param name="compilation"></param>
        /// <param name="classes"></param>
        /// <param name="context"></param>
        private static void GenerateCode(
            Compilation compilation,
            IEnumerable<ClassDeclarationSyntax> classes,
            SourceProductionContext context)
        {
            var processedTypes = new HashSet<ITypeSymbol>(SymbolEqualityComparer.Default);

            if (!classes.Any())
            {
                context.ReportDiagnostic(Diagnostic.Create(
                    new DiagnosticDescriptor("GEN002", "没有目标类",
                    "没有找到SourceAnalyzers标记的类", "Debug", DiagnosticSeverity.Warning, true),
                    Location.None));
            }

            foreach (var classDecl in classes.Distinct())
            {
                var model = compilation.GetSemanticModel(classDecl.SyntaxTree);
                var classSymbol = model.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;

                if (classSymbol == null || !processedTypes.Add(classSymbol))
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                        new DiagnosticDescriptor("GEN003", "无效符号",
                        $"类名称为{classDecl.Identifier.Text} 符号为空", "Error", DiagnosticSeverity.Error, true),
                        Location.None));
                    continue;
                }

                var code3 = BuildAccessorsForSourceEntity(classSymbol, compilation, processedTypes);
                context.AddSource($"{classSymbol.Name}Accessor.g.cs", code3);
            }

            // 生成工厂注册代码
            context.AddSource("SourceEntityAccessorFactory.g.cs", BuildFactoryCode());
        }

        /// <summary>
        /// 获取泛型参数
        /// </summary>
        /// <param name="symbol"></param>
        /// <returns></returns>
        public static string GetGenericParams(INamedTypeSymbol symbol)
        {
            if (!symbol.IsGenericType) return "";
            var parameters = symbol.TypeParameters.Select(t => t.Name);
            return $"<{string.Join(", ", parameters)}>";
        }


        /// <summary>
        /// 生成标准属性的访问器
        /// </summary>
        /// <param name="prop"></param>
        /// <param name="propType"></param>
        /// <param name="code"></param>
        private static void GenerateStandardAccessors(IPropertySymbol prop, INamedTypeSymbol propType, StringBuilder code)
        {
            var parentType = prop.ContainingType.ToDisplayString();
            code.AppendLine($"    public static {propType.ToDisplayString()} Get{prop.Name}({parentType} obj) => obj.{prop.Name};");

            if (prop.SetMethod != null)
            {
                code.AppendLine($"    public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;");
            }
        }


        /// <summary>
        /// 构建实体访问器代码（支持泛型）
        /// </summary>
        private static string BuildAccessorsForSourceEntity(
            INamedTypeSymbol classSymbol,
            Compilation compilation,
            HashSet<ITypeSymbol> processedTypes)
        {
            // 获取 SourceAnalyzers 特性的 EntityType 参数
            var sourceAnalyzerAttr = classSymbol.GetAttributes()
                .FirstOrDefault(attr =>
                    attr.AttributeClass?.ToDisplayString() == AttributeFullName);

            // 解析 EntityType 枚举值
            string entityTypeValue = "EntityTypeEnum.Other"; // 默认值
            if (sourceAnalyzerAttr != null &&
                sourceAnalyzerAttr.ConstructorArguments.Length > 0)
            {
                var arg = sourceAnalyzerAttr.ConstructorArguments[0];
                if (arg.Kind == TypedConstantKind.Enum &&
                    arg.Type is INamedTypeSymbol enumType)
                {
                    int enumValue = (int)arg.Value!;
                    entityTypeValue = GetEnumMemberName(enumType, enumValue);
                }
            }

            var code = new StringBuilder();
            code.AppendLine("// <auto-generated/>");
            code.AppendLine("#nullable enable");
            code.AppendLine("using System;");
            code.AppendLine("using System.Reflection;");
            code.AppendLine("using System.Collections.Generic;");
            code.AppendLine("using JiShe.CollectBus.Analyzers.Shared;");
            code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};");
            code.AppendLine();

            // 处理泛型类型名称
            var accessibility = classSymbol.DeclaredAccessibility switch
            {
                Accessibility.Public => "public",
                _ => "internal"
            };

            var genericParams = classSymbol.IsGenericType
                ? $"<{string.Join(", ", classSymbol.TypeParameters.Select(t => t.Name))}>"
                : "";

            code.AppendLine(
                $"{accessibility} sealed class {classSymbol.Name}Accessor{genericParams} " + // 保留泛型参数
                $": ISourceEntityAccessor<{classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>");

            code.AppendLine("{");

            var propList = GetAllPropertiesInHierarchy(classSymbol);

            //类名称
            code.AppendLine($"   public string EntityName {{get;}} = \"{classSymbol.Name}\";");
            // 添加 EntityType 属性
            code.AppendLine($"    public EntityTypeEnum? EntityType {{ get; }} = {entityTypeValue};");

            foreach (var prop in propList)
            {
                // 安全类型转换
                if (prop.Type is not ITypeSymbol propType) continue;

                if (propType is INamedTypeSymbol namedType)
                {
                    GenerateStandardAccessors(prop, namedType, code);
                }

                if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
                {
                    GenerateTupleAccessors(prop, tupleType, code);
                }
            }

            //生成当前类属性名称集合
            GeneratePropertyListForSourceEntity(propList, code, compilation, classSymbol);

            //生成当前类属性信息集合
            GenerateEntityMemberInfoList(propList, code, compilation, classSymbol);


            //生成当前类属性访问
            GetGeneratePropertyValueForSourceEntity(propList, code, compilation, classSymbol);

            //生成当前类属性设置
            SetGeneratePropertyValueForSourceEntity(propList, code, compilation, classSymbol);

            code.AppendLine("}");
            return code.ToString();
        }

        /// <summary>
        /// 生成ValueTuple元组属性访问器
        /// </summary>
        /// <param name="prop"></param>
        /// <param name="tupleType"></param>
        /// <param name="code"></param>
        private static void GenerateTupleAccessors(
            IPropertySymbol prop,
            INamedTypeSymbol tupleType,
            StringBuilder code)
        {
            var parentType = prop.ContainingType.ToDisplayString();
            var tupleElements = tupleType.TupleElements;

            for (int i = 0; i < tupleElements.Length; i++)
            {
                var element = tupleElements[i];
                var elementType = element.Type.ToDisplayString();
                var elementName = element.Name;

                // Getter
                code.AppendLine($"public static {elementType} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};");

                // Setter
                if (prop.SetMethod != null)
                {
                    code.AppendLine($"public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType} value) => obj.{prop.Name} = ({string.Join(", ", GetTupleElements(prop.Name, tupleElements, i))});");
                }
            }
        }

        private static IEnumerable<string> GetTupleElements(
            string propName,
            ImmutableArray<IFieldSymbol> elements,
            int targetIndex)
        {
            for (int i = 0; i < elements.Length; i++)
            {
                yield return i == targetIndex
                    ? "value"
                    : $"obj.{propName}.{elements[i].Name}";
            }
        }

        /// <summary>
        /// 处理System.Tuple类型的访问器生成
        /// </summary>
        private static void GenerateSystemTupleAccessors(
            IPropertySymbol prop,
            INamedTypeSymbol tupleType,
            StringBuilder code,
            INamedTypeSymbol classSymbol)
        {
            var parentType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
            var elementTypes = tupleType.TypeArguments;
            var tupleTypeName = tupleType.ToDisplayString();

            for (int i = 0; i < elementTypes.Length; i++)
            {
                var elementType = elementTypes[i].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                var elementName = $"Item{i + 1}";

                // Getter
                code.AppendLine(
                    $"    public static {elementType} Get{prop.Name}_{elementName}" +
                    $"({parentType} obj) => obj.{prop.Name}.{elementName};");

                // Setter
                if (prop.SetMethod != null)
                {
                    var assignments = elementTypes.Select((_, idx) =>
                        idx == i ? "value" : $"obj.{prop.Name}.Item{idx + 1}"
                    ).ToList();

                    code.AppendLine(
                        $"    public static void Set{prop.Name}_{elementName}" +
                        $"({parentType} obj, {elementType} value) => " +
                        $"obj.{prop.Name} = new {tupleTypeName}({string.Join(", ", assignments)});");
                }
            }
        }

        /// <summary>
        /// 增强的工厂类实现
        /// </summary>
        private static string BuildFactoryCode()
        {
            return """
        using System;
        using System.Collections.Concurrent;
        using System.Reflection;
        
        namespace JiShe.CollectBus.Analyzers.Shared;
        
        public static class SourceEntityAccessorFactory
        {
            private static readonly ConcurrentDictionary<Type, object> _accessors = new();

            public static ISourceEntityAccessor<T> GetAccessor<T>()
            {
                return (ISourceEntityAccessor<T>)_accessors.GetOrAdd(typeof(T), t =>
                {
                    // 获取泛型类型定义信息（如果是泛型类型）
                    var isGeneric = t.IsGenericType;
                    var genericTypeDef = isGeneric ? t.GetGenericTypeDefinition() : null;
                    var arity = isGeneric ? genericTypeDef!.GetGenericArguments().Length : 0;

                    // 构建访问器类名
                    var typeName = isGeneric 
                        ? $"{t.Namespace}.{genericTypeDef!.Name.Split('`')[0]}Accessor`{arity}" 
                        : $"{t.Namespace}.{t.Name}Accessor";

                    // 尝试从当前程序集加载
                    var accessorType = Assembly.GetAssembly(t)!.GetType(typeName)
                        ?? throw new InvalidOperationException($"Accessor type {typeName} not found");

                    // 处理泛型参数
                    if (isGeneric && accessorType.IsGenericTypeDefinition)
                    {
                        accessorType = accessorType.MakeGenericType(t.GetGenericArguments());
                    }

                    return Activator.CreateInstance(accessorType)!;
                });
            }
        }
        """;
        }

        /// <summary>
        /// 属性访问生成逻辑
        /// </summary>
        /// <param name="propList">属性集合</param>
        /// <param name="code"></param>
        /// <param name="compilation"></param>
        /// <param name="classSymbol"></param>
        private static void GetGeneratePropertyValueForSourceEntity(
            IEnumerable<IPropertySymbol> propList,
            StringBuilder code,
            Compilation compilation,
            INamedTypeSymbol classSymbol)
        {
            code.AppendLine($"    public object GetPropertyValue({classSymbol} targetEntity, string propertyName)");
            code.AppendLine("    {");
            code.AppendLine("        return propertyName switch");
            code.AppendLine("        {");

            foreach (var prop in propList)
            {
                code.AppendLine(
                        $"            \"{prop.Name}\" => " +
                        $"Get{prop.Name}(targetEntity),");

                if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
                {
                    foreach (var element in tupleType.TupleElements)
                    {
                        code.AppendLine(
                            $"            \"{prop.Name}.{element.Name}\" => " +
                            $"Get{prop.Name}_{element.Name}(targetEntity),");
                    }
                }

            }

            code.AppendLine("            _ => throw new ArgumentException($\"Unknown property: {propertyName}\")");
            code.AppendLine("        };");
            code.AppendLine("    }");
        }

        /// <summary>
        /// 属性设置生成逻辑
        /// </summary>
        /// <param name="propList">属性集合</param>
        /// <param name="code"></param>
        /// <param name="compilation"></param>
        /// <param name="classSymbol"></param>
        private static void SetGeneratePropertyValueForSourceEntity(
            IEnumerable<IPropertySymbol> propList,
            StringBuilder code,
            Compilation compilation,
            INamedTypeSymbol classSymbol)
        {
            code.AppendLine($"    public void SetPropertyValue({classSymbol} targetEntity, string propertyName, object value)");
            code.AppendLine("    {");
            code.AppendLine("        switch (propertyName)");
            code.AppendLine("        {");

            foreach (var prop in propList)
            {
                var propType = prop.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                code.AppendLine($"            case \"{prop.Name}\":");
                code.AppendLine($"                Set{prop.Name}(");
                code.AppendLine($"                    targetEntity, ({propType})value);");
                code.AppendLine("                break;");

                if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
                {
                    foreach (var element in tupleType.TupleElements)
                    {
                        var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                        code.AppendLine($"            case \"{prop.Name}.{element.Name}\":");
                        code.AppendLine($"                Set{prop.Name}_{element.Name}(");
                        code.AppendLine($"                    targetEntity, ({elementType})value);");
                        code.AppendLine("                break;");
                    }
                }
            }

            code.AppendLine("            default:");
            code.AppendLine("                throw new ArgumentException($\"Unknown property: {propertyName}\");");
            code.AppendLine("        }");
            code.AppendLine("    }");
        }

        /// <summary>
        /// 属性名称集合
        /// </summary>
        /// <param name="propList">属性集合</param>
        /// <param name="code"></param>
        /// <param name="compilation"></param>
        /// <param name="classSymbol"></param>
        private static void GeneratePropertyListForSourceEntity(
            IEnumerable<IPropertySymbol> propList,
            StringBuilder code,
            Compilation compilation,
            INamedTypeSymbol classSymbol)
        {
            code.AppendLine("    public List<string> PropertyNameList {get;} = new List<string>()");
            code.AppendLine("    {");
            List<string> tempPropList = new List<string>();
            foreach (var prop in propList)
            {
                if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
                {
                    foreach (var element in tupleType.TupleElements)
                    {
                        tempPropList.Add($"\"{prop.Name}.{element.Name}\"");
                    }
                }
                else
                {
                    tempPropList.Add($"\"{prop.Name}\"");
                }
            }

            code.Append(string.Join(",", tempPropList));

            code.AppendLine("    };");
        }


        /// <summary>
        /// 生成当前类属性信息集合
        /// </summary>
        private static void GenerateEntityMemberInfoList(
            IEnumerable<IPropertySymbol> propList,
            StringBuilder code,
            Compilation compilation,
            INamedTypeSymbol classSymbol)
        {
            code.AppendLine("    public List<EntityMemberInfo> MemberList { get; } = new()");
            code.AppendLine("    {");

            var initializerLines = new List<string>();

            foreach (var prop in propList)
            {
                var entityType = prop.ContainingType.ToDisplayString();//entity 实体类型名称
                var propType = prop.Type;//实体属性的类型
                var propTypeName = propType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
               // var declaredTypeName = propType.Name; // 直接获取类型名称（如 "Int32"）
                                                      // 处理可空类型，获取底层具体类型名称
                var declaredTypeName = propType switch
                {
                    INamedTypeSymbol { OriginalDefinition.SpecialType: SpecialType.System_Nullable_T } nullableType =>
                        nullableType.TypeArguments[0].Name, // 提取如 "Int32"
                    _ => propType.Name
                };

                // 处理主属性
                var propAttributes = prop.GetAttributes()
                    .Where(a => !IsCompilerGeneratedAttribute(a))
                    .ToList();

                var attributeInitializers = propAttributes
                    .Select(GenerateAttributeInitializer)
                    .Where(s => !string.IsNullOrEmpty(s));

                var mainMember = new StringBuilder();
                mainMember.Append(
                    $"new EntityMemberInfo(" +
                    $"\"{prop.Name}\", " +
                    $"typeof({propTypeName}), " +
                    $"\"{declaredTypeName}\", " +
                    $"(e) => Get{prop.Name}(({entityType})e), " +
                    $"(e, v) => Set{prop.Name}(({entityType})e, ({propTypeName})v))");

                if (attributeInitializers.Any())
                {
                    mainMember.AppendLine();
                    mainMember.Append("    { CustomAttributes = new List<Attribute>");
                    mainMember.Append($" {{ {string.Join(", ", attributeInitializers)} }} }}");
                }

                initializerLines.Add(mainMember.ToString());

                // 处理元组元素,（暂不需要处理元组元素的特性）
                if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
                {
                    foreach (var element in tupleType.TupleElements)
                    {
                        var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);//元组元素的类型
                        var elementName = element.Name;//元组元素名称
                        var elementDeclaredName = element.Type.Name;//元组元素类型名称

                        initializerLines.Add(
                           $"new EntityMemberInfo(" +
                           $"\"{prop.Name}.{elementName}\", " +
                           $"typeof({elementType}), " +
                           $"typeof({elementType}).Name, " +//$"\"{elementDeclaredName}\", " +
                           $"(e) => Get{prop.Name}_{elementName}(({entityType})e), " +
                           $"(e, v) => Set{prop.Name}_{elementName}(({entityType})e, ({elementType})v))");
                    }
                }
            }

            code.AppendLine(string.Join(",\n", initializerLines));
            code.AppendLine("    };");
        }


        private static string GenerateAttributeInitializer(AttributeData attribute)
        {
            if (attribute.AttributeClass == null)
                return string.Empty;

            var attributeClass = attribute.AttributeClass.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
            var args = attribute.ConstructorArguments;
            var namedArgs = attribute.NamedArguments;

            var parameters = new List<string>();
            foreach (var arg in args)
            {
                parameters.Add(ConvertTypedConstantToCode(arg));
            }

            var constructorArgs = string.Join(", ", parameters);

            var initializer = new StringBuilder();
            initializer.Append($"new {attributeClass}({constructorArgs})");

            if (namedArgs.Any())
            {
                initializer.Append(" { ");
                var namedArgsList = namedArgs.Select(n => $"{n.Key} = {ConvertTypedConstantToCode(n.Value)}");
                initializer.Append(string.Join(", ", namedArgsList));
                initializer.Append(" }");
            }

            return initializer.ToString();
        }

        private static string ConvertTypedConstantToCode(TypedConstant constant)
        {
            if (constant.IsNull)
                return "null";

            switch (constant.Kind)
            {
                case TypedConstantKind.Array:
                    var elements = constant.Values.Select(ConvertTypedConstantToCode);
                    return $"new[] {{ {string.Join(", ", elements)} }}";
                case TypedConstantKind.Type:
                    var typeSymbol = (ITypeSymbol)constant.Value!;
                    return $"typeof({typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)})";
                case TypedConstantKind.Enum:
                    return ConvertEnumTypedConstant(constant);
                default:
                    return ConvertPrimitiveConstant(constant);
            }
        }

        private static string ConvertEnumTypedConstant(TypedConstant constant)
        {
            var enumType = constant.Type!;
            var enumValue = constant.Value!;
            var enumTypeName = enumType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

            foreach (var member in enumType.GetMembers().OfType<IFieldSymbol>())
            {
                if (member.ConstantValue != null && member.ConstantValue.Equals(enumValue))
                    return $"{enumTypeName}.{member.Name}";
            }

            return $"({enumTypeName})({enumValue})";
        }

        private static string ConvertPrimitiveConstant(TypedConstant constant)
        {
            var value = constant.Value!;
            return value switch
            {
                string s => $"\"{s}\"",
                char c => $"'{c}'",
                bool b => b ? "true" : "false",
                _ => value.ToString()
            };
        }

        private static bool IsCompilerGeneratedAttribute(AttributeData attribute)
        {
            return attribute.AttributeClass?.ToDisplayString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute";
        }

        /// <summary>
        /// 获取枚举的参数
        /// </summary>
        /// <param name="enumType"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private static string GetEnumMemberName(INamedTypeSymbol enumType, int value)
        {
            foreach (var member in enumType.GetMembers().OfType<IFieldSymbol>())
            {
                if (member.ConstantValue is int intValue && intValue == value)
                {
                    return $"{enumType.ToDisplayString()}.{member.Name}";
                }
            }
            return $"{enumType.ToDisplayString()}.Other";
        }
    }
}