using System;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;

namespace Nebula.SourceGenerators;


[Generator]
public class ViewConstructorGenerator : IIncrementalGenerator
{
    private static readonly string ViewModelAttribute = "Nebula.Shared.ViewHelper.ViewModelRegisterAttribute";
    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        var provider = context.SyntaxProvider
            .CreateSyntaxProvider(
                (s, _) => s is ClassDeclarationSyntax,
                (ctx, _) => SourceHelper.GetClassDeclarationForSourceGen(ctx,ViewModelAttribute))
            .Where(t => t.reportAttributeFound)
            .Select((t, _) => t.Item1);

        context.RegisterSourceOutput(context.CompilationProvider.Combine(provider.Collect()),
            (ctx, t) => GenerateCode(ctx, t.Left, t.Right));
    }

    private void GenerateCode(SourceProductionContext context, Compilation compilation,
        ImmutableArray<ClassDeclarationSyntax> classDeclarations)
    {
        foreach (var classDeclarationSyntax in classDeclarations)
        {
            var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
            if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
                continue;
            
            var viewModelName = classSymbol.Name;
            var viewModelNamespace = classSymbol.ContainingNamespace.ToDisplayString();
            
            var viewModelRegisterAttr = classSymbol.GetAttributes()
                .FirstOrDefault(attr => attr.AttributeClass?.ToDisplayString() == ViewModelAttribute);

            var viewTypeArg = viewModelRegisterAttr?.ConstructorArguments.FirstOrDefault();
            if (viewTypeArg?.Value is not INamedTypeSymbol viewTypeSymbol)
                continue;

            try
            {
                var viewName = viewTypeSymbol.Name;
                var viewNamespace = viewTypeSymbol.ContainingNamespace.ToDisplayString();
            
                var code = $@"
namespace {viewNamespace}
{{
    public partial class {viewName}
    {{
       public {viewName}({viewModelNamespace}.{viewModelName} viewModel)
        : this()
        {{
            DataContext = viewModel;
        }}
    }}
}}";
            
                // Add the source code to the compilation.
                context.AddSource($"{viewName}_viewConstructAuto.g.cs", SourceText.From(code, Encoding.UTF8));
            }
            catch (Exception e)
            {
                var coder1 = $@"
// <auto-generated/>
// Error!
namespace {viewModelNamespace}
{{
    public partial class {viewModelName}
    {{
        // {e.Message}
    }}
}}";

                // Add the source code to the compilation.
                context.AddSource($"{viewModelName}_viewError.g.cs", SourceText.From(coder1, Encoding.UTF8));
            }
        }
    }


}