using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
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();

            context.RegisterPostInitializationOutput(ctx =>
            {
                ctx.AddSource("GeneratorInit.g.cs", "// Initialization Marker");
            });

            // 步骤1：筛选带有 [GenerateAccessors] 的类
            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 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; // 向上遍历基类
            }
        }

        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", "No Targets",
                    "No classes with [GenerateAccessors] found", "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", "Invalid Symbol",
                        $"Class symbol is null for {classDecl.Identifier.Text}", "Error", DiagnosticSeverity.Error, true),
                        Location.None));
                    continue;
                }

                context.ReportDiagnostic(Diagnostic.Create(
                new DiagnosticDescriptor(
                    "PA001",
                    "Generated Accessors",
                    $"Generating accessors for {classSymbol.Name}",
                    "Performance",
                    DiagnosticSeverity.Info,
                    true),
                Location.None));

                // 新增：输出继承链信息
                context.ReportDiagnostic(Diagnostic.Create(
                    new DiagnosticDescriptor("HIERARCHY", "Class Hierarchy",
                    $"Processing class: {classSymbol.Name}, BaseType: {classSymbol.BaseType?.Name}",
                    "Debug", DiagnosticSeverity.Info, true),
                    Location.None));

                context.ReportDiagnostic(Diagnostic.Create(
                new DiagnosticDescriptor("PA002", "Class Found",
                $"Processing class: {classSymbol.Name}", "Debug", DiagnosticSeverity.Warning, true),
                Location.None));

                var code = BuildAccessorsForType(classSymbol, compilation, processedTypes);

                System.Diagnostics.Debug.WriteLine($"Generated code for {classSymbol.Name}:\n{code}"); // 调试输出

                context.AddSource($"{classSymbol.Name}Extension.g.cs", code);
            }
        }

        private static string BuildAccessorsForType(
            INamedTypeSymbol classSymbol,
            Compilation compilation,
            HashSet<ITypeSymbol> processedTypes)
        {
            var code = new StringBuilder();
            code.AppendLine("#pragma warning disable CS0419 // 禁用警告");
            code.AppendLine("// Generated code for " + classSymbol.Name);
            code.AppendLine("// <auto-generated/>");
            code.AppendLine("#nullable enable");
            code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};");
            code.AppendLine();

            code.AppendLine($"public static class {classSymbol.Name}Extension{GetGenericParams(classSymbol)}");
            code.AppendLine("{");

            //foreach (var prop in classSymbol.GetMembers().OfType<IPropertySymbol>())
            //{
            //    if (prop.IsIndexer) continue;

            //    GeneratePropertyAccessors(prop, code, compilation, processedTypes);
            //}

            foreach (var prop in GetAllPropertiesInHierarchy(classSymbol))
            {
                if (prop.IsIndexer) continue;
                GeneratePropertyAccessors(prop, code, compilation, processedTypes);
            }

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

        //private static string GetGenericParams(INamedTypeSymbol symbol)
        //    => symbol.IsGenericType ? $"<{string.Join(", ", symbol.TypeParameters.Select(t => t.Name))}>" : "";
        public static string GetGenericParams(INamedTypeSymbol symbol)
        {
            if (!symbol.IsGenericType) return "";
            var parameters = symbol.TypeParameters.Select(t => t.Name);
            return $"<{string.Join(", ", parameters)}>";
        }

        private static void GeneratePropertyAccessors(
            IPropertySymbol prop,
            StringBuilder code,
            Compilation compilation,
            HashSet<ITypeSymbol> processedTypes)
        {
            // 关键修复点1：安全类型转换
            if (prop.Type is not ITypeSymbol propType) return;

            code.AppendLine($"    // Processing property: {prop.Name}");

            // 处理元组类型
            if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
            {
                GenerateTupleAccessors(prop, tupleType, code);
            }
            else if (propType is INamedTypeSymbol namedType)
            {
                GenerateStandardAccessors(prop, namedType, code);
                ProcessNestedType(namedType, compilation, processedTypes);
            }
        }

        private static void GenerateTupleAccessors(IPropertySymbol prop, INamedTypeSymbol tupleType, StringBuilder code)
        {
            var elements = tupleType.TupleElements;
            var parentType = prop.ContainingType.ToDisplayString();

            for (int i = 0; i < elements.Length; i++)
            {
                var element = elements[i];
                if (element.Type is not ITypeSymbol elementType) continue;

                var elementName = element.CorrespondingTupleField?.Name ?? $"Item{i + 1}";
                code.AppendLine($"    public static {elementType.ToDisplayString()} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};");

                if (prop.SetMethod != null)
                {
                    var assignments = elements.Select((e, idx) =>
                        idx == i ? "value" : $"obj.{prop.Name}.{e.Name}");
                    code.AppendLine($"    public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType.ToDisplayString()} value) => obj.{prop.Name} = ({string.Join(", ", assignments)});");
                }
            }
        }

        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;");
            }
        }

        private static void ProcessNestedType(ITypeSymbol typeSymbol, Compilation compilation, HashSet<ITypeSymbol> processedTypes)
        {
            if (typeSymbol is not INamedTypeSymbol namedType) return;
            if (!ShouldProcessNestedType(namedType)) return;
            if (!processedTypes.Add(namedType)) return;

            var code = BuildAccessorsForType(namedType, compilation, processedTypes);
        }

        private static bool ShouldProcessNestedType(INamedTypeSymbol symbol)
        {
            return symbol.DeclaredAccessibility == Accessibility.Public &&
                   !symbol.IsTupleType &&
                   !symbol.IsAnonymousType &&
                   !symbol.IsImplicitlyDeclared &&
                   !symbol.Name.StartsWith("<");
        }
    }
}